feat: 删掉所有view, templates, forms

This commit is contained in:
ibuler
2020-06-03 11:43:43 +08:00
parent 7c479c2479
commit 8efc0331de
178 changed files with 4 additions and 18821 deletions

View File

@@ -1,5 +0,0 @@
# coding: utf-8
#
from .terminal import *
from .storage import *

View File

@@ -1,165 +0,0 @@
# coding: utf-8
#
from django import forms
from django.utils.translation import ugettext_lazy as _
from terminal.models import ReplayStorage, CommandStorage
__all__ = [
'ReplayStorageAzureForm', 'ReplayStorageOSSForm', 'ReplayStorageS3Form',
'ReplayStorageCephForm', 'ReplayStorageSwiftForm',
'CommandStorageTypeESForm',
]
class BaseStorageForm(forms.Form):
def __init__(self, *args, **kwargs):
super(BaseStorageForm, self).__init__(*args, **kwargs)
self.fields['type'].widget.attrs['disabled'] = True
self.fields.move_to_end('comment')
class BaseReplayStorageForm(BaseStorageForm, forms.ModelForm):
class Meta:
model = ReplayStorage
fields = ['name', 'type', 'comment']
class BaseCommandStorageForm(BaseStorageForm, forms.ModelForm):
class Meta:
model = CommandStorage
fields = ['name', 'type', 'comment']
class ReplayStorageAzureForm(BaseReplayStorageForm):
azure_container_name = forms.CharField(
max_length=128, label=_('Container name'), required=False
)
azure_account_name = forms.CharField(
max_length=128, label=_('Account name'), required=False
)
azure_account_key = forms.CharField(
max_length=128, label=_('Account key'), required=False,
widget=forms.PasswordInput
)
azure_endpoint_suffix = forms.ChoiceField(
choices=(
('core.chinacloudapi.cn', 'core.chinacloudapi.cn'),
('core.windows.net', 'core.windows.net')
),
label=_('Endpoint suffix'), required=False,
)
class ReplayStorageOSSForm(BaseReplayStorageForm):
oss_bucket = forms.CharField(
max_length=128, label=_('Bucket'), required=False
)
oss_access_key = forms.CharField(
max_length=128, label=_('Access key'), required=False,
widget=forms.PasswordInput
)
oss_secret_key = forms.CharField(
max_length=128, label=_('Secret key'), required=False,
widget=forms.PasswordInput
)
oss_endpoint = forms.CharField(
max_length=128, label=_('Endpoint'), required=False,
help_text=_(
"""
OSS: http://{REGION_NAME}.aliyuncs.com <br>
Example: http://oss-cn-hangzhou.aliyuncs.com
"""
)
)
class ReplayStorageS3Form(BaseReplayStorageForm):
s3_bucket = forms.CharField(
max_length=128, label=_('Bucket'), required=False
)
s3_access_key = forms.CharField(
max_length=128, label=_('Access key'), required=False,
widget=forms.PasswordInput
)
s3_secret_key = forms.CharField(
max_length=128, label=_('Secret key'), required=False,
widget=forms.PasswordInput
)
s3_endpoint = forms.CharField(
max_length=128, label=_('Endpoint'), required=False,
help_text=_(
"""
S3: http://s3.{REGION_NAME}.amazonaws.com <br>
S3(China): http://s3.{REGION_NAME}.amazonaws.com.cn <br>
Example: http://s3.cn-north-1.amazonaws.com.cn
"""
)
)
class ReplayStorageCephForm(BaseReplayStorageForm):
ceph_bucket = forms.CharField(
max_length=128, label=_('Bucket'), required=False
)
ceph_access_key = forms.CharField(
max_length=128, label=_('Access key'), required=False,
widget=forms.PasswordInput
)
ceph_secret_key = forms.CharField(
max_length=128, label=_('Secret key'), required=False,
widget=forms.PasswordInput
)
ceph_endpoint = forms.CharField(
max_length=128, label=_('Endpoint'), required=False,
)
class ReplayStorageSwiftForm(BaseReplayStorageForm):
swift_bucket = forms.CharField(
max_length=128, label=_('Bucket'), required=False
)
swift_access_key = forms.CharField(
max_length=128, label=_('Access key'), required=False,
widget=forms.PasswordInput
)
swift_secret_key = forms.CharField(
max_length=128, label=_('Secret key'), required=False,
widget=forms.PasswordInput
)
swift_region = forms.CharField(
max_length=128, label=_('Region'), required=False,
)
swift_endpoint = forms.CharField(
max_length=128, label=_('Endpoint'), required=False,
)
swift_protocol = forms.ChoiceField(
choices=(
('HTTP', 'http'),
('HTTPS', 'https')
), initial='http', label=_('Protocol'), required=True,
)
class CommandStorageTypeESForm(BaseCommandStorageForm):
es_hosts = forms.CharField(
max_length=128, label=_('Hosts'), required=True,
help_text=_(
"""
Tips: If there are multiple hosts, separate them with a comma (,)
<br>
eg: http://www.jumpserver.a.com,http://www.jumpserver.b.com
"""
)
)
es_index = forms.CharField(
max_length=128, label=_('Index'), required=True
)
es_doc_type = forms.CharField(
max_length=128, label=_('Doc type'), required=True
)

View File

@@ -1,39 +0,0 @@
# coding: utf-8
#
__all__ = ['TerminalForm']
from django import forms
from django.utils.translation import ugettext_lazy as _
from ..models import Terminal, ReplayStorage, CommandStorage
def get_all_command_storage():
for c in CommandStorage.objects.all():
yield (c.name, c.name)
def get_all_replay_storage():
for r in ReplayStorage.objects.all():
yield (r.name, r.name)
class TerminalForm(forms.ModelForm):
command_storage = forms.ChoiceField(
choices=get_all_command_storage,
label=_("Command storage"),
help_text=_("Command can store in server db or ES, default to server, more see docs"),
)
replay_storage = forms.ChoiceField(
choices=get_all_replay_storage,
label=_("Replay storage"),
help_text=_("Replay file can store in server disk, AWS S3, Aliyun OSS, default to server, more see docs"),
)
class Meta:
model = Terminal
fields = [
'name', 'remote_addr', 'comment',
'command_storage', 'replay_storage',
]

View File

@@ -1,59 +0,0 @@
{% extends '_base_create_update.html' %}
{% load static %}
{% load bootstrap3 %}
{% load i18n %}
{% block form %}
<form id="StorageForm" method="post" class="form-horizontal">
{% bootstrap_form form layout="horizontal"%}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
{% endblock %}
{% block custom_foot_js %}
<script type="text/javascript">
var storageCreateUrl, storageUpdateUrl, storageListUrl = null;
var type_id = '#' + '{{ form.type.id_for_label }}';
var api_action = "{{ api_action }}";
function getFormDataType(){
return $(type_id+ " option:selected").val();
}
function getFormData(form){
var data = form.serializeObject();
data['type'] = getFormDataType();
data['meta'] = constructFormDataMeta(data);
return data
}
$(document).ready(function () {
})
.on("submit", "form", function (evt) {
evt.preventDefault();
var the_url = storageCreateUrl;
var method = "POST";
{% if api_action == "update" %}
the_url = storageUpdateUrl.replace('{{ DEFAULT_PK }}', '{{ object.id }}');
method = "PUT";
{% endif %}
var redirect_to = storageListUrl;
var form = $("form");
var data = getFormData(form);
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
})
</script>
{% endblock %}

View File

@@ -1,129 +0,0 @@
{% extends 'base.html' %}
{% load i18n static %}
{% block content %}
<div class="wrapper wrapper-content animated fadeIn">
<div class="col-lg-12">
<div class="tabs-container">
<ul class="nav nav-tabs">
<li {% if is_replay %}class="active" {% endif %}><a href="{% url 'terminal:replay-storage-list' %}"> {% trans 'Replay storage' %}</a></li>
<li {% if is_command %}class="active" {% endif %}><a href="{% url 'terminal:command-storage-list' %}" >{% trans 'Command storage' %}</a></li>
</ul>
<div class="tab-content">
<div id="my-tickets" class="tab-pane active">
<div class="panel-body">
<div class="btn-group uc pull-left m-r-5">
<button data-toggle="dropdown" class="btn btn-primary btn-sm dropdown-toggle">
{% block create_storage_info %}{% endblock %}
<span class="caret"></span></button>
<ul class="dropdown-menu">
{% for key, value in type_choices %}
<li><a class="" href="{% block create_storage_url %}{% endblock %}?type={{ key }}">{{ value }}</a></li>
{% endfor %}
</ul>
</div>
<table class="table table-striped table-bordered table-hover" id="storage_list_table" >
<thead>
<tr>
<th class="text-center">
<input id="" type="checkbox" class="ipt_check_all">
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Type' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center" style="width: 150px">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script>
var storage_table , storageTableAjaxUrl , storageUpdateUrl , storageDeleteUrl , storageTestConnectiveUrl = null ;
function initTable() {
var options = {
ele: $('#storage_list_table'),
columnDefs: [
{targets: 4, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var del_btn, update_btn;
if (['server', 'null'].indexOf(rowData.type) === -1){
del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
update_btn = '<a class="btn btn-xs m-l-xs btn-info btn-update" data-uid="{{ DEFAULT_PK }}">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
}
else{
del_btn = '<a class="btn btn-xs btn-danger disabled m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
update_btn = '<a class="btn btn-xs m-l-xs disabled btn-info btn-update" data-uid="{{ DEFAULT_PK }}">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
}
var test_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-test-connective" data-uid="{{ DEFAULT_PK }}">{% trans 'Test' %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn + test_btn);
}
}
],
ajax_url: storageTableAjaxUrl,
columns: [
{data: "id"}, {data: "name" }, {data: "type"}, {data: "comment"},
{data: "id", orderable: false,}
],
op_html: $('#actions').html()
};
storage_table = jumpserver.initServerSideDataTable(options);
return storage_table
}
$(document).ready(function(){
initTable()
})
.on('click', '.btn-update', function (){
var $this = $(this);
var uid = $this.data('uid');
window.location.href = storageUpdateUrl.replace('{{ DEFAULT_PK }}', uid);
})
.on('click', '.btn-del', function () {
var $this = $(this);
var uid = $this.data('uid');
var name = $this.data('name');
var the_url = storageDeleteUrl.replace('{{ DEFAULT_PK }}', uid);
objectDelete($this, name, the_url);
})
.on('click', '.btn-test-connective', function () {
var $this = $(this);
var uid = $this.data('uid');
var the_url = storageTestConnectiveUrl.replace('{{ DEFAULT_PK }}', uid);
var error = function (data) {
toastr.error(data)
};
var success = function(data) {
var isValid = data.is_valid;
if (isValid){
toastr.success(data.msg)
}
else{
toastr.error(data.msg)
}
};
requestApi({
url: the_url,
error: error,
method: 'GET',
success: success,
flash_message: false
});
})
</script>
{% endblock %}

View File

@@ -1,237 +0,0 @@
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% load common_tags %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
.toggle {
cursor: pointer;
}
.detail-key {
width: 70px;
}
</style>
{% endblock %}
{% block table_pagination %}
{% endblock %}
{% block table_search %}
{% endblock %}
{% block table_container %}
<table class="table table-striped table-bordered table-hover" id="command_table" data-page="false" >
<thead>
<tr>
<th></th>
<th>{% trans 'Command' %}</th>
<th>{% trans 'Risk level' %}</th>
<th>{% trans 'User' %}</th>
<th>{% trans 'Asset' %}</th>
<th>{% trans 'System user'%}</th>
<th>{% trans 'Session' %}</th>
<th>{% trans 'Datetime' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="actions" class="hide">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="export">{% trans 'Export command' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
<div class="hide" id="daterange">
<div class="form-group p-l-5" id="date" style="padding-left: 5px">
<div class="input-daterange input-group p-l-5" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" id="date_from" name="date_from" value="{{ date_from|date:'Y-m-d' }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" id="date_to" name="date_to" value="{{ date_to|date:'Y-m-d' }}">
</div>
</div>
</div>
{% include '_filter_dropdown.html' %}
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}" charset="UTF-8"></script>
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.zh-CN.min.js' %}" ></script>
<script>
var table;
$(document).ready(function () {
table = initTable().on("init", function () {
var dateFromRef = $("#date_from");
var dateToRef = $("#date_to");
var options = {
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
calendarWeeks: true,
autoclose: true,
language: getUserLang(),
};
dateFromRef.datepicker(options).on("changeDate", function () {
var value = $(this).val() + ' 0:0:0';
var date = safeDate(value);
var url = table.ajax.url();
url = setUrlParam(url, "date_from", date.getTime()/1000);
table.ajax.url(url);
table.ajax.reload();
});
dateToRef.datepicker(options).on("changeDate", function () {
var value = $(this).val() + ' 23:59:59';
var date = safeDate(value);
var url = table.ajax.url();
url = setUrlParam(url, "date_to", date.getTime()/1000);
table.ajax.url(url);
table.ajax.reload();
});
});
var filterMenu = [
{title: "{% trans 'User' %}", value: "user"},
{title: "{% trans 'Asset' %}", value: "asset"},
{title: "{% trans 'System user' %}", value: "system_user"},
{title: "{% trans 'Command' %}", value: "input"},
{title: "{% trans 'Risk level' %}", value: "risk_level", submenu: [
{title: "{% trans 'Ordinary' %}", value: "0"},
{title: "{% trans 'Dangerous' %}", value: "5"},
]},
];
initTableFilterDropdown('#command_table_filter input', filterMenu, 15, 50)
})
.on('click', '#btn_bulk_update', function(){
// var action = $('#slct_bulk_update').val();
var params = getUrlParams(table.ajax.url());
var searchParams = '';
var searchValue = $('input[type=search]').val();
var searchMap = parseTableFilter(searchValue);
if (Object.keys(searchMap).length === 0) {
searchParams = searchValue;
} else {
$.each(searchMap, function (k, v) {
searchParams += k + '=' + v + '&'
})
}
params += '&' + searchParams;
var exportPath = "{% url 'api-terminal:command-export' %}";
var url = exportPath + "?" + params;
window.open(url);
})
.on('click', 'body', function (e) {
$('.dropdown-menu.search-help').hide()
})
.on('click', '.toggle', function (e) {
e.preventDefault();
var detailRows = [];
var tr = $(this).closest('tr');
var row = table.row(tr);
var idx = $.inArray(tr.attr('id'), detailRows);
if (row.child.isShown()) {
tr.removeClass('details');
$(this).children('i:first-child').removeClass('fa-angle-down').addClass('fa-angle-right');
row.child.hide();
// Remove from the 'open' array
detailRows.splice(idx, 1);
} else {
tr.addClass('details');
$(this).children('i:first-child').removeClass('fa-angle-right').addClass('fa-angle-down');
row.child(format(row.data())).show();
// Add to the 'open' array
if (idx === -1) {
detailRows.push(tr.attr('id'));
}
}
});
function format(d) {
var output = $("<pre style='border: none; background: none; white-space: pre-wrap'></pre>");
output.append('$ ', d.input);
output.append('\r\n\r\n');
output.append(d.output);
return output
}
var commandListUrl = '{% url "api-terminal:command-list" %}';
var dateFrom = "{{ date_from.timestamp }}";
var dateTo = "{{ date_to.timestamp }}";
function initTable() {
commandListUrl = setUrlParam(commandListUrl, "date_from", dateFrom);
commandListUrl = setUrlParam(commandListUrl, "date_to", dateTo);
var options = {
ele: $('#command_table'),
columnDefs: [
{targets: 0, createdCell: function (td, cellData, rowData) {
$(td).addClass("toggle");
$(td).html("<i class='fa fa-angle-right'></i>");
}},
{targets: 1, createdCell: function (td, cellData) {
var data = htmlEscape(cellData);
var interHtml = $("<span></span>");
if (data.length > 40) {
interHtml.attr('title', data);
data = data.slice(0, 40);
data += ' ...';
}
interHtml.html(data);
$(td).html(interHtml);
}},
{targets: 2, createdCell: function (td, cellData){
let risk;
if(cellData === 5){
risk = "{% trans 'Dangerous' %}";
}
else{
risk = "{% trans 'Ordinary' %}";
}
$(td).html(risk)
}},
{targets: 6, createdCell: function (td, cellData) {
var data = '<a href="{% url "terminal:session-detail" pk=DEFAULT_PK %}">{% trans "Goto" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(data);
}},
{targets: 7, createdCell: function (td, cellData) {
var data = toSafeLocalDateStr(cellData*1000);
$(td).html(data);
}},
],
toggle: true,
ajax_url: commandListUrl,
columns: [
{data: "id"}, {data: "input", orderable: false, width: "40%"},
{data: "risk_level", orderable: false}, {data: "user", orderable: false},
{data: "asset", orderable: false}, {data: "system_user", orderable: false},
{data: "session", orderable: false}, {data: "timestamp", width: "160px", orderable: false},
],
select: {},
op_html: $('#actions').html(),
fb_html: $("#daterange").html(),
};
table = jumpserver.initServerSideDataTable(options);
return table
}
</script>
{% endblock %}

View File

@@ -1,103 +0,0 @@
{% load common_tags %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Command Report</title>
<style>
*{
margin: 0;
padding: 0;
}
.background {
background-color: #535659;
padding-top: 50px;
padding-bottom: 50px;
}
.paper {
margin-left: 23%;
margin-right: 24%;
border: solid;
padding: 50px;
background-color: #fff;
}
h2 {
font-style: italic;
text-align: center;
}
.info {
width: 200px;
margin-left: 450px;
font-style: italic;
text-align: left;
padding-top: 20px;
padding-bottom: 20px;
}
.command {
margin-left: 10px;
}
.command-desc {
font-size: 12px;
}
.command-desc span {
float: right;
}
.command-input {
{#font-style: italic;#}
font-size: 15px;
margin-top: 10px;
margin-bottom: 10px;
}
.command-input span {
font-size: 13px;
}
.hr-line-dashed {
border-top: 1px dashed #000;
color: #000;
background-color: #fff;
height: 1px;
margin: 20px 0;
}
pre {
font-size: 12px;
}
</style>
</head>
<body>
<div class="background">
<div class="paper">
<h2>Command Report</h2>
<div class="info">
<p>total: {{ total_count }}</p>
<p>date: {{ now | ts_to_date }}</p>
</div>
<div class="hr-line-dashed"></div>
<div>
{% for command in queryset %}
<div class="command">
<p class="command-desc">
[{{ command.user}} {{ command.system_user }}@{{ command.asset }} {{ command.timestamp | ts_to_date }}]
<span>{{ forloop.counter }}</span>
</p>
<p class="command-input"><span>$ </span>{{ command.input }}</p>
<pre>{{ command.output }}</pre>
</div>
<div class="hr-line-dashed"></div>
{% endfor %}
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,30 +0,0 @@
{% extends 'terminal/base_storage_create_update.html' %}
{% load i18n static %}
{% block custom_foot_js %}
{{ block.super }}
<script type="text/javascript">
storageCreateUrl = "{% url 'api-terminal:command-storage-list' %}";
storageUpdateUrl = "{% url 'api-terminal:command-storage-detail' pk=DEFAULT_PK %}";
storageListUrl = "{% url "terminal:command-storage-list" %}";
function constructFormDataMeta(data){
var meta = {};
var type = data.type;
for (var k in data){
if (k.startsWith(type)){
var v = data[k];
if (k === 'es_hosts'){
v = v.split(',');
}
meta[k] = v;
delete data[k]
}
}
return meta
}
</script>
{% endblock %}

View File

@@ -1,15 +0,0 @@
{% extends 'terminal/base_storage_list.html' %}
{% load i18n static %}
{% block create_storage_url %}{% url "terminal:command-storage-create" %}{% endblock%}
{% block create_storage_info %}{% trans 'Create command storage' %}{% endblock %}
{% block custom_foot_js %}
{{ block.super }}
<script>
storageTableAjaxUrl = '{% url "api-terminal:command-storage-list" %}';
storageUpdateUrl = '{% url "terminal:command-storage-update" pk=DEFAULT_PK %}';
storageDeleteUrl = '{% url "api-terminal:command-storage-detail" pk=DEFAULT_PK %}';
storageTestConnectiveUrl = '{% url "api-terminal:command-storage-test-connective" pk=DEFAULT_PK %}';
</script>
{% endblock %}

View File

@@ -1,25 +0,0 @@
{% extends 'terminal/base_storage_create_update.html' %}
{% load i18n static %}
{% block custom_foot_js %}
{{ block.super }}
<script type="text/javascript">
storageCreateUrl = "{% url 'api-terminal:replay-storage-list' %}";
storageUpdateUrl = "{% url 'api-terminal:replay-storage-detail' pk=DEFAULT_PK %}";
storageListUrl = "{% url "terminal:replay-storage-list" %}";
function constructFormDataMeta(data){
var meta = {};
var type = data.type;
for (var k in data){
if (k.startsWith(type)){
meta[k] = data[k];
delete data[k]
}
}
return meta
}
</script>
{% endblock %}

View File

@@ -1,14 +0,0 @@
{% extends 'terminal/base_storage_list.html' %}
{% load i18n static %}
{% block create_storage_url %}{% url "terminal:replay-storage-create" %}{% endblock%}
{% block create_storage_info %}{% trans 'Create replay storage' %}{% endblock %}
{% block custom_foot_js %}
{{ block.super }}
<script>
storageTableAjaxUrl = '{% url "api-terminal:replay-storage-list" %}';
storageUpdateUrl = '{% url "terminal:replay-storage-update" pk=DEFAULT_PK %}';
storageDeleteUrl = '{% url "api-terminal:replay-storage-detail" pk=DEFAULT_PK %}';
storageTestConnectiveUrl = '{% url "api-terminal:replay-storage-test-connective" pk=DEFAULT_PK %}';
</script>
{% endblock %}

View File

@@ -1,96 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load common_tags %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/ladda/ladda-themeless.min.css' %}" rel="stylesheet">
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li>
<a class="text-center" href="{% url 'terminal:session-detail' pk=object.id %}"> {% trans 'Session detail' %} </a>
</li>
<li class="active">
<a class="text-center" href="{% url 'terminal:session-commands' pk=object.id %}"> {% trans 'Commands' %} </a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-10" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Command list' %} <b></b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table id="command-log" class="footable table table-stripped toggle-arrow-tiny" data-page-size="10">
<thead>
<tr>
<th data-toggle="true">ID</th>
<th>{% trans 'Command' %}</th>
<th data-hide="all"></th>
<th style="">{% trans 'Datetime' %}</th>
</tr>
</thead>
<tbody>
{% for command in object_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ command.input | truncatechars:40 }}</td>
<td><pre style="border: none;background: none; white-space: pre-wrap;">
$ {{ command.input }}
{{ command.output }}
</pre></td>
<td>{{ command.timestamp|ts_to_date}}</td>
</tr>
{% empty %}
<tr>
<td colspan="3">{% trans "There is no command about this session" %}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="5">
<ul class="pagination pull-right"></ul>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
<script>
$(document).ready(function () {
$('.footable').footable();
})
</script>
{% endblock %}

View File

@@ -1,211 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load common_tags %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/ladda/ladda-themeless.min.css' %}" rel="stylesheet">
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a class="text-center" href="{% url 'terminal:session-detail' pk=object.id %}"> {% trans 'Session detail' %} </a>
</li>
<li>
<a class="text-center" href="{% url 'terminal:session-commands' pk=object.id %}"> {% trans 'Commands' %} </a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-8" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left"> <b>{{ object.id }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="20%">{% trans 'User' %}:</td>
<td><b>{{ object.user }}</b></td>
</tr>
<tr>
<td>{% trans 'Asset' %}:</td>
<td><b>{{ object.asset }}</b></td>
</tr>
<tr>
<td>{% trans 'System user' %}:</td>
<td><b>{{ object.system_user }}</b></td>
</tr>
<tr>
<td>{% trans 'Protocol' %}:</td>
<td><b>{{ object.protocol }}</b></td>
</tr>
<tr>
<td>{% trans 'Login from' %}:</td>
<td><b>{{ object.login_from_display }}</b></td>
</tr>
<tr>
<td>{% trans 'Remote addr' %}:</td>
<td><b>{{ object.remote_addr }}</b></td>
</tr>
<tr>
<td>{% trans 'Date start' %}:</td>
<td><b>{{ object.date_start }}</b></td>
</tr>
<tr>
<td>{% trans 'Date end' %}:</td>
<td><b>{{ object.date_end }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick modify' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
{% if object.is_finished %}
<tr class="no-borders-tr">
<td>{% trans 'Replay session' %}:</td>
<td>
<span class="pull-right">
<button type="button" onclick="window.open('/luna/replay/{{ object.id }}','luna', 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Go' %}</button>
</span>
</td>
</tr>
<tr>
<td>{% trans 'Download replay' %}:</td>
<td>
<span class="pull-right">
<button class="ladda-button btn btn-primary btn-xs btn-download" style="width: 54px" data-style="zoom-in" >{% trans 'Download' %}</button>
</span>
</td>
</tr>
{% else %}
<!--<tr>-->
<!--<td class="no-borders" >{% trans 'Monitor session' %}:</td>-->
<!--<td class="no-borders" >-->
<!--<span class="pull-right">-->
<!--<button type="button" class="btn btn-primary btn-xs " style="width: 54px">{% trans 'Go' %}</button>-->
<!--</span>-->
<!--</td>-->
<!--</tr>-->
<tr class="no-borders-tr">
<td>{% trans 'Terminate session' %}:</td>
<td>
<span class="pull-right">
<button type="button" class="btn btn-primary btn-xs btn-term" value="{{ object.id }}" terminal="{{ object.terminal.id }}" style="width: 54px;">{% trans 'Confirm' %}</button>
</span>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static "js/plugins/ladda/spin.min.js" %}"></script>
<script src="{% static "js/plugins/ladda/ladda.min.js" %}"></script>
<script src="{% static "js/plugins/ladda/ladda.jquery.min.js" %}"></script>
<script>
var downloadPageUrl = "{% url "terminal:session-replay-download" pk=object.id %}";
var sessionReplayDetailUrl = '{% url "api-terminal:session-replay" pk=object.id %}';
var interval = null;
var l;
function terminateSession(data) {
function success() {
window.setTimeout(function () {
window.location.reload()
}, 300)
}
var the_url = "{% url 'api-terminal:tasks-list' %}";
requestApi({
url: the_url,
method: 'POST',
body: JSON.stringify(data),
success: success,
success_message: "{% trans 'Terminate success'%}"
});
}
function getReplayDetail() {
function success(data) {
if (data.src) {
clearInterval(interval);
l.ladda('stop');
window.open(downloadPageUrl);
return;
}
if (data.status === "error") {
clearInterval(interval);
l.ladda('stop');
toastr.error(data.error)
}
}
requestApi({
url: sessionReplayDetailUrl,
method: 'GET',
success: success,
flash_message: false
})
}
$(document).ready(function () {
l = $('.btn-download').ladda();
l.click(function () {
l.ladda('start');
interval = setInterval(getReplayDetail, 2000)
});
var downloadDirect = getUrlParam('download');
if (downloadDirect) {
$('.btn-download').trigger('click');
}
}).on('click', '.btn-term', function () {
var $this = $(this);
var session_id = $this.attr('value');
var terminal_id = $this.attr('terminal');
alert(session_id);
var data = {
name: "kill_session",
args: session_id,
terminal: terminal_id
};
terminateSession(data)
})
</script>
{% endblock %}

View File

@@ -1,322 +0,0 @@
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% load terminal_tags %}
{% load common_tags %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
{% endblock %}
{% block content_left_head %}
{% endblock %}
{% block table_pagination %}
{% endblock %}
{% block table_search %}
{% endblock %}
{% block table_container %}
<table class="table table-striped table-bordered table-hover" id="session_table" data-page="false" >
<thead>
<tr>
<th class="text-center"></th>
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">{% trans 'Remote addr' %}</th>
<th class="text-center">{% trans 'Protocol' %}</th>
<th class="text-center">{% trans 'Login from' %}</th>
<th class="text-center">{% trans 'Command' %}</th>
<th class="text-center">{% trans 'Date start' %}</th>
<th class="text-center">{% trans 'Duration' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="actions" class="hide">
{% if type == "online" and request.user.can_admin_current_org %}
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="terminate">{% trans 'Terminate selected' %}</option>
<option value="finished">{% trans 'Confirm finished' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
{% endif %}
</div>
<div class="hide" id="daterange">
<div class="form-group p-l-5" id="date" style="padding-left: 5px">
<div class="input-daterange input-group p-l-5" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" id="date_from" name="date_from" value="{{ date_from|date:'Y-m-d' }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" id="date_to" name="date_to" value="{{ date_to|date:'Y-m-d' }}">
</div>
</div>
</div>
<ul class="dropdown-menu search-help">
<li><a class="search-item" data-value="user">{% trans 'User' %}</a></li>
<li><a class="search-item" data-value="asset">{% trans 'Asset' %}</a></li>
<li><a class="search-item" data-value="system_user">{% trans 'System user' %}</a></li>
<li><a class="search-item" data-value="remote_addr">{% trans 'Remote addr' %}</a></li>
<li><a class="search-item" data-value="protocol">{% trans 'Protocol' %}</a></li>
{# <li><a class="search-item" data-value="protocol">{% trans 'Protocol' %}</a></li>#}
</ul>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.zh-CN.min.js' %}" ></script>
<script>
function terminateSession(data) {
function success() {
window.setTimeout(function () {
window.location.reload()
}, 1000)
}
var success_message = '{% trans "Terminate task send, waiting ..." %}';
var the_url = "{% url 'api-terminal:kill-session' %}";
requestApi({
url: the_url,
method: 'POST',
body: JSON.stringify(data),
success: success,
success_message: success_message
});
}
var sessionListUrl = "{% url 'api-terminal:session-list' %}?is_finished={% if type == "online" %}0{% else %}1{% endif %}";
var dateFrom = "{{ date_from.timestamp }}";
var dateTo = "{{ date_to.timestamp }}";
function initTable() {
dateFrom = toSafeDateISOStr(dateFrom * 1000);
dateTo = toSafeDateISOStr(dateTo * 1000);
sessionListUrl = setUrlParam(sessionListUrl, "date_from", dateFrom);
sessionListUrl = setUrlParam(sessionListUrl, "date_to", dateTo);
var options = {
ele: $('#session_table'),
ordering: false,
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData, i) {
var index = i + 1;
var data = '<a href="{% url 'terminal:session-detail' pk=DEFAULT_PK %}">'
+ index + "</a>";
data = data.replace("{{ DEFAULT_PK }}", cellData);
$(td).html(data);
}},
{targets: 9, createdCell: function (td, cellData) {
var data = toSafeLocalDateStr(cellData);
$(td).html(data);
}},
{targets: 10, createdCell: function (td, cellData, rowData) {
var data = "";
if (cellData && rowData.date_start) {
data = timeOffset(rowData.date_start, cellData)
}
$(td).html(data);
}},
{targets: 11, createdCell: function (td, cellData, rowData) {
var btnGroup = "";
var replayBtn = '<a disabled data-session="sessionID" class="btn btn-xs btn-warning btn-replay" >{% trans "Replay" %}</a>';
replayBtn = replayBtn.replace("sessionID", rowData.id);
var downloadBtn = ' <a disabled data-session="sessionID" class="btn btn-xs btn-info btn-download" >{% trans "Download" %}</a>';
downloadBtn = downloadBtn.replace("sessionID", rowData.id);
if (rowData.can_replay) {
replayBtn = replayBtn.replace("disabled", "");
downloadBtn = downloadBtn.replace("disabled", "");
}
var termBtn = '<a class="btn btn-xs btn-danger btn-term" disabled value="sessionID" terminal="terminalID" >{% trans "Terminate" %}</a>';
if ("{{ request.user.can_admin_current_org }}" === "True") {
termBtn = termBtn.replace("disabled", "")
.replace("sessionID", cellData)
.replace("terminalID", rowData.terminal)
}
var joinBtn = ' <a disabled data-session="sessionID" class="btn btn-xs btn-info btn-join" >{% trans "Monitoring" %}</a>';
joinBtn = joinBtn.replace("sessionID", rowData.id);
if (rowData.can_join){
joinBtn = joinBtn.replace("disabled", "")
}
if (rowData.is_finished) {
btnGroup += replayBtn + downloadBtn
} else {
btnGroup += termBtn + joinBtn;
}
$(td).html(btnGroup);
}},
],
ajax_url: sessionListUrl,
columns: [
{data: "id"}, {data: "id", orderable:false}, {data: "user"},
{data: "asset"}, {data: "system_user"},
{data: "remote_addr"}, {data: "protocol"}, {data: "login_from_display", orderable:false},
{data: "command_amount", orderable:false}, {data: "date_start"},
{data: "date_end", orderable:false}, {data: "id",orderable:false},
],
op_html: $('#actions').html(),
fb_html: $("#daterange").html(),
};
table = jumpserver.initServerSideDataTable(options);
return table
}
function finishedSession(data) {
var the_url = "{% url 'api-terminal:session-list' %}";
var success_message = '{% trans "Finish session success" %}';
var success = function() {
location.reload();
};
requestApi({
url: the_url,
method: 'PATCH',
body: JSON.stringify(data),
success: success,
success_message: success_message
});
}
var table;
$(document).ready(function() {
table = initTable("#session_table").on('init', function () {
var dateFromRef = $("#date_from");
var dateToRef = $("#date_to");
var options = {
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
calendarWeeks: true,
autoclose: true,
language: getUserLang(),
};
dateFromRef.datepicker(options).on("changeDate", function () {
if (!$(this).val()) {
return
}
var value = $(this).val() + ' 0:0:0';
var date = toSafeDateISOStr(value);
var url = table.ajax.url();
url = setUrlParam(url, "date_from", date);
table.ajax.url(url);
table.ajax.reload();
});
dateToRef.datepicker(options).on("changeDate", function () {
if (!$(this).val()) {
return
}
var value = $(this).val() + ' 23:59:59';
var date = toSafeDateISOStr(value);
var url = table.ajax.url();
url = setUrlParam(url, "date_to", date);
table.ajax.url(url);
table.ajax.reload();
});
});
}).on('click', '.btn-term', function () {
var $this = $(this);
var session_id = $this.attr('value');
var data = [
session_id
];
terminateSession(data)
}).on('click', '.btn-replay', function () {
var sessionID = $(this).data("session");
var replayUrl = "/luna/replay/" + sessionID;
window.open(replayUrl, "_blank", "height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no");
})
.on('click', '.btn-download', function () {
var sessionID = $(this).data("session");
var downloadUrl = "{% url 'terminal:session-replay-download' pk=DEFAULT_PK %}"
.replace("{{ DEFAULT_PK }}", sessionID);
var hasConfirm = getCookie('replayConfirm');
if (!hasConfirm) {
var help_text = "{% trans "Visit doc for replay play offline: " %}";
help_text += "https://github.com/jumpserver/videoplayer";
var r = confirm(help_text);
setCookie("replayConfirm", "1")
}
window.open(downloadUrl)
})
.on('click', '.btn-join', function () {
var sessionID = $(this).data("session");
var joinUrl = "/luna/join/?shareroom=" + sessionID;
window.open(joinUrl)
})
.on("click", '#session_table_filter input', function (e) {
e.preventDefault();
e.stopPropagation();
var offset1 = $('#session_table_filter input').offset();
var x = offset1.left;
var y = offset1.top;
var offset = $(".search-help").parent().offset();
x -= offset.left;
y -= offset.top;
x += 18;
y += 80;
$('.search-help').css({"top":y+"px", "left":x+"px", "position": "absolute"});
$('.dropdown-menu.search-help').show();
})
.on('click', '.search-item', function (e) {
e.preventDefault();
e.stopPropagation();
var keyword = $("#session_table_filter input");
var value = $(this).data('value');
var old_value = keyword.val();
var new_value = old_value + ' ' + value + ':';
keyword.val(new_value.trim());
$('.dropdown-menu.search-help').hide();
keyword.focus()
})
.on('click', 'body', function (e) {
$('.dropdown-menu.search-help').hide()
})
.on('click', '#btn_bulk_update', function () {
var action = $('#slct_bulk_update').val();
var idList = table.selected;
if (idList.length === 0) {
return false;
}
function doTerminate() {
terminateSession(idList)
}
function doFinishSession() {
var data = [];
$.each(idList, function (i, v) {
data.push({
"id": v,
"is_finished": true
})
});
finishedSession(data)
}
switch(action) {
case 'terminate':
doTerminate();
break;
case "finished":
doFinishSession();
break;
default:
break;
}
});
</script>
{% endblock %}

View File

@@ -1,77 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Terminal detail' %} </a>
</li>
<li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'terminal:terminal-update' pk=terminal.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ terminal.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="20%">{% trans 'Name' %}:</td>
<td><b>{{ terminal.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Remote addr' %}:</td>
<td><b>{{ terminal.remote_addr }}</b></td>
</tr>
<tr>
<td>{% trans 'SSH port' %}:</td>
<td><b>{{ terminal.ssh_port }}</b></td>
</tr>
<tr>
<td>{% trans 'Http port' %}:</td>
<td><b>{{ terminal.http_port }}</b></td>
</tr>
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ terminal.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ asset.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,144 +0,0 @@
{% extends '_base_list.html' %}
{% load i18n static %}
{% block custom_head_css_js %}
{{ block.super }}
<style>
div.dataTables_wrapper div.dataTables_filter,
.dataTables_length {
float: right !important;
}
div.dataTables_wrapper div.dataTables_filter {
margin-left: 15px;
}
#modal .modal-body { max-height: 200px; }
</style>
{% endblock %}
{% block table_search %}{% endblock %}
{% block table_container %}
<div class="uc pull-left m-r-5"><a href="{% url "terminal:replay-storage-list" %}" class="btn btn-sm btn-primary"> {% trans "Storage configuration" %} </a></div>
<table class="table table-striped table-bordered table-hover " id="terminal_list_table" >
<thead>
<tr>
<th class="text-center">
<div class="checkbox checkbox-default">
<input type="checkbox" class="ipt_check_all">
</div>
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Addr' %}</th>
{# <th class="text-center">{% trans 'SSH port' %}</th>#}
{# <th class="text-center">{% trans 'Http port' %}</th>#}
<th class="text-center">{% trans 'Session' %}</th>
<th class="text-center">{% trans 'Active' %}</th>
<th class="text-center">{% trans 'Alive' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% include 'terminal/terminal_modal_accept.html' %}
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<script>
function initTable() {
var options = {
ele: $('#terminal_list_table'),
buttons: [],
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "terminal:terminal-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 4, createdCell: function (td, cellData) {
if (!cellData) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else {
$(td).html('<i class="fa fa-check text-navy"></i>')
}
}},
{targets: 5, createdCell: function (td, cellData) {
if (!cellData) {
$(td).html('<i class="fa fa-circle text-danger"></i>')
} else {
$(td).html('<i class="fa fa-circle text-navy"></i>')
}
}},
{targets: 6, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = '<a href="{% url "terminal:terminal-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData);
var delete_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
var accept_btn = '<a class="btn btn-xs btn-primary btn-accept" data-id="{{ DEFAULT_PK }}">{% trans "Accept" %}</a> '
.replace('{{ DEFAULT_PK }}', cellData);
var reject_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-id="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Reject" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
if (rowData.is_accepted) {
$(td).html(update_btn + delete_btn);
} else {
{% if user.is_superuser %}
$(td).html(accept_btn + reject_btn);
{% endif %}
}
}}
],
ajax_url: '{% url "api-terminal:terminal-list" %}',
columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" },
{data: "session_online", orderable: false}, {data: "is_active", orderable: false}, {data: 'is_alive'}, {data: "id", orderable: false}],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
$(document).ready(function(){
initTable();
}).on('click', '#btn-confirm',function () {
var $form = $('#form_terminal_accept');
function success(data, textStatus, jqXHR) {
if (data.success === true) {
window.location.reload()
} else {
$('#modal-error').html(data.msg).css('display', 'block');
}
}
$form.ajaxSubmit({success: success});
}).on('click', '.btn-del', function(){
var $this = $(this);
var id = $this.data('id');
var name = $(this).data('name');
var the_url = '{% url "api-terminal:terminal-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', id);
objectDelete($this, name, the_url)
}).on('click', '.btn-accept', function () {
var $this = $(this);
var terminal_id = $this.data('id');
var the_url = "{% url 'api-terminal:terminal-detail' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', terminal_id);
var post_url = "{% url 'terminal:terminal-accept' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', terminal_id);
$.ajax({
url: the_url,
method: 'GET',
success: function (data) {
$('#id_name').val(data.name);
$('#id_remote_addr').val(data.remote_addr);
$('#id_url').val(data.url);
$('#id_comment').val(data.comment);
$('#form_terminal_accept').attr('action', post_url)
}
});
$('#modal_terminal_accept').modal({
show: true
});
}).on('click', '.btn-connect', function () {
var $this = $(this);
var id = $this.data('id');
})
</script>
{% endblock %}

View File

@@ -1,21 +0,0 @@
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}modal_terminal_accept{% endblock %}
{% block modal_class %}modal-lg{% endblock %}
{% block modal_title%}{% trans "Accept terminal registration" %}{% endblock %}
{% block modal_body %}
{% load bootstrap3 %}
<form action="" method="post" class="form-horizontal" id="form_terminal_accept" enctype="multipart/form-data">
{% csrf_token %}
<p class="alert alert-danger" id="modal-error" style="display: none"></p>
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.remote_addr layout="horizontal" %}
{# {% bootstrap_field form.ssh_port layout="horizontal" %}#}
{# {% bootstrap_field form.http_port layout="horizontal" %}#}
{% bootstrap_field form.command_storage layout="horizontal" %}
{% bootstrap_field form.replay_storage layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
</form>
{% endblock %}
{% block modal_confirm_id %}btn-confirm{% endblock %}

View File

@@ -1,5 +0,0 @@
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>

View File

@@ -1,70 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap3 %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>{{ action }}</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Info' %}</h3>
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.remote_addr layout="horizontal" %}
{% bootstrap_field form.command_storage layout="horizontal" %}
{% bootstrap_field form.replay_storage layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3>
{% bootstrap_field form.comment layout="horizontal" %}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function () {
$('.select2').select2();
}).on('submit', 'form', function (e) {
e.preventDefault();
var form = $('form');
formSubmit({
'url': '{% url 'api-terminal-v2:terminal-detail' pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', '{{ object.id }}'),
'form': form,
'method': 'PUT',
'redirect_to': '{% url "terminal:terminal-list" %}'
});
})
</script>
{% endblock %}

View File

@@ -1,2 +0,0 @@
# -*- coding: utf-8 -*-
#

View File

@@ -1,14 +0,0 @@
# ~*~ coding: utf-8 ~*~
from django import template
from ..backends import get_multi_command_storage
register = template.Library()
@register.filter
def get_session_command_amount(session_id):
command_store = get_multi_command_storage()
return command_store.count(session=session_id)

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from django.urls import path
from .. import views
app_name = 'terminal'
urlpatterns = [
# Terminal view
path('terminal/', views.TerminalListView.as_view(), name='terminal-list'),
path('terminal/<uuid:pk>/', views.TerminalDetailView.as_view(), name='terminal-detail'),
path('terminal/<uuid:pk>/connect/', views.TerminalConnectView.as_view(), name='terminal-connect'),
path('terminal/<uuid:pk>/update/', views.TerminalUpdateView.as_view(), name='terminal-update'),
path('<uuid:pk>/accept/', views.TerminalAcceptView.as_view(), name='terminal-accept'),
path('web-terminal/', views.WebTerminalView.as_view(), name='web-terminal'),
path('web-sftp/', views.WebSFTPView.as_view(), name='web-sftp'),
# Session view
path('session-online/', views.SessionOnlineListView.as_view(), name='session-online-list'),
path('session-offline/', views.SessionOfflineListView.as_view(), name='session-offline-list'),
path('session/<uuid:pk>/', views.SessionDetailView.as_view(), name='session-detail'),
path('session/<uuid:pk>/commands/', views.SessionCommandsView.as_view(), name='session-commands'),
path('session/<uuid:pk>/replay/download/', views.SessionReplayDownloadView.as_view(), name='session-replay-download'),
# Command view
path('command/', views.CommandListView.as_view(), name='command-list'),
# replay-storage
path('terminal/replay-storage/', views.ReplayStorageListView.as_view(), name='replay-storage-list'),
path('terminal/replay-storage/create/', views.ReplayStorageCreateView.as_view(), name='replay-storage-create'),
path('terminal/replay-storage/<uuid:pk>/update/', views.ReplayStorageUpdateView.as_view(), name='replay-storage-update'),
# command-storage
path('terminal/command-storage/', views.CommandStorageListView.as_view(), name='command-storage-list'),
path('terminal/command-storage/create/', views.CommandStorageCreateView.as_view(), name='command-storage-create'),
path('terminal/command-storage/<uuid:pk>/update/', views.CommandStorageUpdateView.as_view(), name='command-storage-update'),
]

View File

@@ -1,9 +0,0 @@
# -*- coding: utf-8 -*-
#
from .terminal import *
from .session import *
from .command import *
from .storage import *
# from .replay_storage import *
# from .command_storage import *

View File

@@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
#
from django.views.generic import TemplateView
from django.utils.translation import ugettext as _
from django.utils import timezone
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
__all__ = ['CommandListView']
class CommandListView(PermissionsMixin, TemplateView):
template_name = "terminal/command_list.html"
permission_classes = [IsOrgAdmin | IsOrgAuditor]
default_days_ago = 5
def get_context_data(self, **kwargs):
now = timezone.now()
context = {
'app': _('Sessions'),
'action': _('Command list'),
'date_from': now - timezone.timedelta(days=self.default_days_ago),
'date_to': now,
}
kwargs.update(context)
return super().get_context_data(**kwargs)

View File

@@ -1,142 +0,0 @@
# -*- coding: utf-8 -*-
#
import os
import tarfile
from django.views.generic import ListView, TemplateView, DetailView
from django.views.generic.edit import SingleObjectMixin
from django.utils.translation import ugettext as _
from django.utils import timezone
from django.utils.encoding import escape_uri_path
from django.http import FileResponse, HttpResponse
from django.core.files.storage import default_storage
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
from common.utils import model_to_json
from ..models import Session
from ..backends import get_multi_command_storage
from .. import utils
__all__ = [
'SessionOnlineListView', 'SessionOfflineListView',
'SessionDetailView', 'SessionReplayDownloadView',
'SessionCommandsView',
]
class SessionListView(PermissionsMixin, TemplateView):
model = Session
template_name = 'terminal/session_list.html'
date_from = date_to = None
permission_classes = [IsOrgAdmin | IsOrgAuditor]
default_days_ago = 5
def get_context_data(self, **kwargs):
now = timezone.now()
context = {
'date_from': now - timezone.timedelta(days=self.default_days_ago),
'date_to': now,
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class SessionOnlineListView(SessionListView):
def get_context_data(self, **kwargs):
context = {
'app': _('Sessions'),
'action': _('Session online list'),
'type': 'online',
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class SessionOfflineListView(SessionListView):
def get_context_data(self, **kwargs):
context = {
'app': _('Sessions'),
'action': _('Session offline'),
'type': 'offline',
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class SessionDetailView(PermissionsMixin, DetailView):
template_name = 'terminal/session_detail.html'
model = Session
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def get_context_data(self, **kwargs):
context = {
'app': _('Sessions'),
'action': _('Session detail'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class SessionCommandsView(SingleObjectMixin, PermissionsMixin, ListView):
template_name = 'terminal/session_commands.html'
model = Session
object = None
permission_classes = [IsOrgAdmin | IsOrgAuditor]
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=self.model.objects.all())
return super().get(request, *args, **kwargs)
def get_queryset(self):
command_store = get_multi_command_storage()
return command_store.filter(session=self.object.id)
def get_context_data(self, **kwargs):
context = {
'app': _('Sessions'),
'action': _('Session detail'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class SessionReplayDownloadView(PermissionsMixin, DetailView):
permission_classes = [IsOrgAdmin | IsOrgAuditor]
model = Session
@staticmethod
def prepare_offline_file(session, local_path):
replay_path = default_storage.path(local_path)
current_dir = os.getcwd()
dir_path = os.path.dirname(replay_path)
replay_filename = os.path.basename(replay_path)
meta_filename = '{}.json'.format(session.id)
offline_filename = '{}.tar'.format(session.id)
os.chdir(dir_path)
with open(meta_filename, 'wt') as f:
f.write(model_to_json(session))
with tarfile.open(offline_filename, 'w') as f:
f.add(replay_filename)
f.add(meta_filename)
file = open(offline_filename, 'rb')
os.chdir(current_dir)
return file
def get(self, request, *args, **kwargs):
session = self.get_object()
local_path, url = utils.get_session_replay_url(session)
if local_path is None:
error = url
return HttpResponse(error)
file = self.prepare_offline_file(session, local_path)
response = FileResponse(file)
response['Content-Type'] = 'application/octet-stream'
# 这里要注意哦网上查到的方法都是response['Content-Disposition']='attachment;filename="filename.py"',
# 但是如果文件名是英文名没问题如果文件名包含中文下载下来的文件名会被改为url中的path。
filename = escape_uri_path('{}.tar'.format(session.id))
disposition = "attachment; filename*=UTF-8''{}".format(filename)
response["Content-Disposition"] = disposition
return response

View File

@@ -1,181 +0,0 @@
# coding: utf-8
#
from django.http import Http404
from django.views.generic import TemplateView
from django.views.generic.edit import CreateView, UpdateView
from django.utils.translation import ugettext as _
from common.permissions import PermissionsMixin, IsSuperUser
from terminal.models import ReplayStorage, CommandStorage
from .. import forms, const
__all__ = [
'ReplayStorageListView', 'ReplayStorageCreateView',
'ReplayStorageUpdateView', 'CommandStorageListView',
'CommandStorageCreateView', 'CommandStorageUpdateView'
]
class ReplayStorageListView(PermissionsMixin, TemplateView):
template_name = 'terminal/replay_storage_list.html'
permission_classes = [IsSuperUser]
def get_context_data(self, **kwargs):
context = {
'app': _('Terminal'),
'action': _('Replay storage list'),
'is_replay': True,
'type_choices': const.REPLAY_STORAGE_TYPE_CHOICES_EXTENDS,
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class CommandStorageListView(PermissionsMixin, TemplateView):
template_name = 'terminal/command_storage_list.html'
permission_classes = [IsSuperUser]
def get_context_data(self, **kwargs):
context = {
'app': _('Terminal'),
'action': _('Command storage list'),
'type_choices': const.COMMAND_STORAGE_TYPE_CHOICES_EXTENDS,
'is_command': True,
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class BaseStorageCreateUpdateViewMixin:
permission_classes = [IsSuperUser]
default_type = None
form_class = None
form_class_choices = {}
def get_initial(self):
return {'type': self.get_type()}
def get_type(self):
return self.default_type
def get_form_class(self):
tp = self.get_type()
form_class = self.form_class_choices.get(tp)
if not form_class:
raise Http404()
return form_class
class ReplayStorageCreateUpdateViewMixin(BaseStorageCreateUpdateViewMixin):
model = ReplayStorage
default_type = const.REPLAY_STORAGE_TYPE_S3
form_class = forms.ReplayStorageS3Form
form_class_choices = {
const.REPLAY_STORAGE_TYPE_S3: forms.ReplayStorageS3Form,
const.REPLAY_STORAGE_TYPE_CEPH: forms.ReplayStorageCephForm,
const.REPLAY_STORAGE_TYPE_SWIFT: forms.ReplayStorageSwiftForm,
const.REPLAY_STORAGE_TYPE_OSS: forms.ReplayStorageOSSForm,
const.REPLAY_STORAGE_TYPE_AZURE: forms.ReplayStorageAzureForm
}
class ReplayStorageCreateView(ReplayStorageCreateUpdateViewMixin,
PermissionsMixin, CreateView):
template_name = 'terminal/replay_storage_create_update.html'
def get_type(self):
tp = self.request.GET.get("type")
if tp:
return tp.lower()
return super().get_type()
def get_context_data(self, **kwargs):
context = {
'app': _('Terminal'),
'action': _('Create replay storage'),
'api_action': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class ReplayStorageUpdateView(ReplayStorageCreateUpdateViewMixin,
PermissionsMixin, UpdateView):
template_name = 'terminal/replay_storage_create_update.html'
def get_initial(self):
initial_data = super().get_initial()
for k, v in self.object.meta.items():
_k = "{}_{}".format(self.object.type, k.lower())
initial_data[_k] = v
return initial_data
def get_type(self):
return self.object.type
def get_context_data(self, **kwargs):
context = {
'app': _('Terminal'),
'action': _('Update replay storage'),
'api_action': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class CommandStorageCreateUpdateViewMixin(BaseStorageCreateUpdateViewMixin):
model = CommandStorage
default_type = const.COMMAND_STORAGE_TYPE_ES
form_class = forms.CommandStorageTypeESForm
form_class_choices = {
const.COMMAND_STORAGE_TYPE_ES: forms.CommandStorageTypeESForm
}
class CommandStorageCreateView(CommandStorageCreateUpdateViewMixin,
PermissionsMixin, CreateView):
template_name = 'terminal/command_storage_create_update.html'
def get_type(self):
tp = self.request.GET.get("type")
if tp:
return tp.lower()
return super().get_type()
def get_context_data(self, **kwargs):
context = {
'app': _('Terminal'),
'action': _('Create command storage'),
'api_action': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class CommandStorageUpdateView(CommandStorageCreateUpdateViewMixin,
PermissionsMixin, UpdateView):
template_name = 'terminal/command_storage_create_update.html'
def get_initial(self):
initial_data = super().get_initial()
for k, v in self.object.meta.items():
_k = "{}_{}".format(self.object.type, k.lower())
if k == 'HOSTS':
v = ','.join(v)
initial_data[_k] = v
return initial_data
def get_type(self):
return self.object.type
def get_context_data(self, **kwargs):
context = {
'app': _('Terminal'),
'action': _('Update command storage'),
'api_action': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)

View File

@@ -1,138 +0,0 @@
# ~*~ coding: utf-8 ~*~
#
import time
from django.views.generic import ListView, UpdateView, DeleteView, \
DetailView, View
from django.utils.translation import ugettext as _
from django.shortcuts import redirect
from django.urls import reverse_lazy, reverse
from common.mixins import JSONResponseMixin
from ..models import Terminal
from ..forms import TerminalForm
from common.permissions import PermissionsMixin, IsSuperUser
__all__ = [
"TerminalListView", "TerminalUpdateView", "TerminalDetailView",
"TerminalDeleteView", "TerminalConnectView", "TerminalAcceptView",
"WebTerminalView", 'WebSFTPView',
]
class TerminalListView(PermissionsMixin, ListView):
model = Terminal
template_name = 'terminal/terminal_list.html'
form_class = TerminalForm
permission_classes = [IsSuperUser]
def get_context_data(self, **kwargs):
context = super(TerminalListView, self).get_context_data(**kwargs)
context.update({
'app': _('Sessions'),
'action': _('Terminal list'),
'form': self.form_class()
})
return context
class TerminalUpdateView(PermissionsMixin, UpdateView):
model = Terminal
form_class = TerminalForm
template_name = 'terminal/terminal_update.html'
success_url = reverse_lazy('terminal:terminal-list')
permission_classes = [IsSuperUser]
def get_context_data(self, **kwargs):
context = super(TerminalUpdateView, self).get_context_data(**kwargs)
context.update({'app': _('Sessions'), 'action': _('Update terminal')})
return context
class TerminalDetailView(PermissionsMixin, DetailView):
model = Terminal
template_name = 'terminal/terminal_detail.html'
context_object_name = 'terminal'
permission_classes = [IsSuperUser]
def get_context_data(self, **kwargs):
context = super(TerminalDetailView, self).get_context_data(**kwargs)
context.update({
'app': _('Sessions'),
'action': _('Terminal detail')
})
return context
class TerminalDeleteView(PermissionsMixin, DeleteView):
model = Terminal
template_name = 'delete_confirm.html'
success_url = reverse_lazy('terminal:terminal-list')
permission_classes = [IsSuperUser]
class TerminalAcceptView(PermissionsMixin, JSONResponseMixin, UpdateView):
model = Terminal
form_class = TerminalForm
template_name = 'terminal/terminal_modal_accept.html'
permission_classes = [IsSuperUser]
def form_valid(self, form):
terminal = form.save()
terminal.create_app_user()
terminal.is_accepted = True
terminal.is_active = True
terminal.save()
data = {
'success': True,
'msg': 'success'
}
return self.render_json_response(data)
def form_invalid(self, form):
data = {
'success': False,
'msg': str(form.errors),
}
return self.render_json_response(data)
class TerminalConnectView(PermissionsMixin, DetailView):
"""
Abandon
"""
template_name = 'flash_message_standalone.html'
model = Terminal
permission_classes = [IsSuperUser]
def get_context_data(self, **kwargs):
if self.object.type == 'Web':
context = {
'title': _('Redirect to web terminal'),
'messages': _('Redirect to web terminal') + self.object.url,
'auto_redirect': True,
'interval': 3,
'redirect_url': self.object.url
}
else:
context = {
'title': _('Connect ssh terminal'),
'messages': _('You should use your ssh client tools '
'connect terminal: {} <br /> <br />'
'{}'.format(self.object.name, self.object.url)),
'redirect_url': reverse('terminal:terminal-list')
}
kwargs.update(context)
return super(TerminalConnectView, self).get_context_data(**kwargs)
class WebTerminalView(View):
def get(self, request, *args, **kwargs):
redirect_url = '/luna/?_={}&'.format(int(time.time()))
return redirect(redirect_url + request.GET.urlencode())
class WebSFTPView(View):
def get(self, request, *args, **kwargs):
return redirect('/koko/elfinder/sftp/?' + request.GET.urlencode())