mirror of https://github.com/jumpserver/jumpserver
add webterminal
parent
c50cdd2976
commit
91f0800e26
|
@ -13,7 +13,6 @@ https://docs.djangoproject.com/en/1.10/ref/settings/
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
@ -22,11 +21,11 @@ sys.path.append(os.path.dirname(BASE_DIR))
|
||||||
# Import project config setting
|
# Import project config setting
|
||||||
try:
|
try:
|
||||||
from config import config as env_config, env
|
from config import config as env_config, env
|
||||||
|
|
||||||
CONFIG = env_config.get(env, 'default')()
|
CONFIG = env_config.get(env, 'default')()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
CONFIG = type('_', (), {'__getattr__': None})()
|
CONFIG = type('_', (), {'__getattr__': None})()
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
|
||||||
|
|
||||||
|
@ -38,13 +37,13 @@ DEBUG = CONFIG.DEBUG or False
|
||||||
|
|
||||||
ALLOWED_HOSTS = CONFIG.ALLOWED_HOSTS or []
|
ALLOWED_HOSTS = CONFIG.ALLOWED_HOSTS or []
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'users.apps.UsersConfig',
|
'users.apps.UsersConfig',
|
||||||
'assets.apps.AssetsConfig',
|
'assets.apps.AssetsConfig',
|
||||||
'perms.apps.PermsConfig',
|
'perms.apps.PermsConfig',
|
||||||
|
'webterminal.apps.WebterminalConfig',
|
||||||
'ops.apps.OpsConfig',
|
'ops.apps.OpsConfig',
|
||||||
'audits.apps.AuditsConfig',
|
'audits.apps.AuditsConfig',
|
||||||
'common.apps.CommonConfig',
|
'common.apps.CommonConfig',
|
||||||
|
@ -55,6 +54,8 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'ws4redis',
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -80,6 +81,9 @@ TEMPLATES = [
|
||||||
'django.template.context_processors.request',
|
'django.template.context_processors.request',
|
||||||
'django.contrib.auth.context_processors.auth',
|
'django.contrib.auth.context_processors.auth',
|
||||||
'django.contrib.messages.context_processors.messages',
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
'django.template.context_processors.static',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'ws4redis.context_processors.default',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -87,7 +91,6 @@ TEMPLATES = [
|
||||||
|
|
||||||
WSGI_APPLICATION = 'jumpserver.wsgi.application'
|
WSGI_APPLICATION = 'jumpserver.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
||||||
|
|
||||||
|
@ -110,7 +113,6 @@ else:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
@ -129,7 +131,6 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
||||||
|
|
||||||
|
@ -143,7 +144,6 @@ USE_L10N = True
|
||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/1.10/howto/static-files/
|
# https://docs.djangoproject.com/en/1.10/howto/static-files/
|
||||||
|
|
||||||
|
@ -166,4 +166,28 @@ AUTH_USER_MODEL = 'users.User'
|
||||||
BOOTSTRAP_COLUMN_COUNT = 11
|
BOOTSTRAP_COLUMN_COUNT = 11
|
||||||
|
|
||||||
# Init data or generate fake data source for development
|
# Init data or generate fake data source for development
|
||||||
FIXTURE_DIRS = [os.path.join(BASE_DIR, 'fixtures'), ]
|
FIXTURE_DIRS = [os.path.join(BASE_DIR, 'fixtures'), ]
|
||||||
|
|
||||||
|
# This setting is required to override the Django's main loop, when running in
|
||||||
|
# development mode, such as ./manage runserver
|
||||||
|
WSGI_APPLICATION = 'ws4redis.django_runserver.application'
|
||||||
|
|
||||||
|
# URL that distinguishes websocket connections from normal requests
|
||||||
|
WEBSOCKET_URL = '/ws/'
|
||||||
|
# WebSocket Redis
|
||||||
|
WS4REDIS_CONNECTION = {
|
||||||
|
'host': '127.0.0.1',
|
||||||
|
'port': 6379,
|
||||||
|
'db': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the number of seconds each message shall persited
|
||||||
|
WS4REDIS_EXPIRE = 3600
|
||||||
|
|
||||||
|
WS4REDIS_HEARTBEAT = 'love you'
|
||||||
|
|
||||||
|
WS4REDIS_PREFIX = 'demo'
|
||||||
|
|
||||||
|
SESSION_ENGINE = 'redis_sessions.session'
|
||||||
|
|
||||||
|
SESSION_REDIS_PREFIX = 'session'
|
|
@ -22,6 +22,7 @@ urlpatterns = [
|
||||||
url(r'^$', TemplateView.as_view(template_name='base.html')),
|
url(r'^$', TemplateView.as_view(template_name='base.html')),
|
||||||
url(r'^users/', include('users.urls')),
|
url(r'^users/', include('users.urls')),
|
||||||
url(r'^assets/', include('assets.urls')),
|
url(r'^assets/', include('assets.urls')),
|
||||||
|
url(r'^terminal/', include('webterminal.urls')),
|
||||||
# url(r'^admin/', admin.site.urls),
|
# url(r'^admin/', admin.site.urls),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div id="term">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="termChangBar">
|
||||||
|
<input type="number" min="100" value="100" placeholder="col" id="term-col"/>
|
||||||
|
<input type="number" min="35" value="35" placeholder="row" id="term-row"/>
|
||||||
|
<button id="col-row">修改窗口大小</button>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block custom_foot_js %}
|
||||||
|
<script type="application/javascript" src="/static/js/jquery-2.1.1.js"></script>
|
||||||
|
<script type="application/javascript" src="/static/js/term.js"></script>
|
||||||
|
<script>/**
|
||||||
|
* Created by liuzheng on 3/3/16.
|
||||||
|
*/
|
||||||
|
var rowHeight = 1;
|
||||||
|
var colWidth = 1;
|
||||||
|
function WSSHClient() {
|
||||||
|
}
|
||||||
|
WSSHClient.prototype._generateEndpoint = function (options) {
|
||||||
|
console.log(options);
|
||||||
|
if (window.location.protocol == 'https:') {
|
||||||
|
var protocol = 'wss://';
|
||||||
|
} else {
|
||||||
|
var protocol = 'ws://';
|
||||||
|
}
|
||||||
|
|
||||||
|
var endpoint = protocol + document.URL.match(RegExp('//(.*?)/'))[1] + '/ws/foobar?subscribe-broadcast&publish-broadcast&echo';
|
||||||
|
return endpoint;
|
||||||
|
};
|
||||||
|
WSSHClient.prototype.connect = function (options) {
|
||||||
|
var endpoint = this._generateEndpoint(options);
|
||||||
|
|
||||||
|
if (window.WebSocket) {
|
||||||
|
this._connection = new WebSocket(endpoint);
|
||||||
|
}
|
||||||
|
else if (window.MozWebSocket) {
|
||||||
|
this._connection = MozWebSocket(endpoint);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
options.onError('WebSocket Not Supported');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._connection.onopen = function () {
|
||||||
|
options.onConnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
this._connection.onmessage = function (evt) {
|
||||||
|
try {
|
||||||
|
options.onData(evt.data);
|
||||||
|
} catch (e) {
|
||||||
|
var data = JSON.parse(evt.data.toString());
|
||||||
|
options.onError(data.error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._connection.onclose = function (evt) {
|
||||||
|
options.onClose();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
WSSHClient.prototype.send = function (data) {
|
||||||
|
this._connection.send(JSON.stringify({'data': data}));
|
||||||
|
};
|
||||||
|
|
||||||
|
function openTerminal(options) {
|
||||||
|
var client = new WSSHClient();
|
||||||
|
var rowHeight, colWidth;
|
||||||
|
try {
|
||||||
|
rowHeight = localStorage.getItem('term-row');
|
||||||
|
colWidth = localStorage.getItem('term-col');
|
||||||
|
} catch (err) {
|
||||||
|
rowHeight = 35;
|
||||||
|
colWidth = 100
|
||||||
|
}
|
||||||
|
if (rowHeight) {
|
||||||
|
} else {
|
||||||
|
rowHeight = 35
|
||||||
|
}
|
||||||
|
if (colWidth) {
|
||||||
|
} else {
|
||||||
|
colWidth = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
var term = new Terminal({
|
||||||
|
rows: rowHeight,
|
||||||
|
cols: colWidth,
|
||||||
|
useStyle: true,
|
||||||
|
screenKeys: true
|
||||||
|
});
|
||||||
|
term.open();
|
||||||
|
term.on('data', function (data) {
|
||||||
|
client.send(data)
|
||||||
|
});
|
||||||
|
$('.terminal').detach().appendTo('#term');
|
||||||
|
//term.resize(colWidth, rowHeight);
|
||||||
|
term.write('Connecting...');
|
||||||
|
client.connect($.extend(options, {
|
||||||
|
onError: function (error) {
|
||||||
|
term.write('Error: ' + error + '\r\n');
|
||||||
|
},
|
||||||
|
onConnect: function () {
|
||||||
|
// Erase our connecting message
|
||||||
|
client.send({'resize': {'rows': rowHeight, 'cols': colWidth}});
|
||||||
|
term.write('\r');
|
||||||
|
},
|
||||||
|
onClose: function () {
|
||||||
|
term.write('Connection Reset By Peer');
|
||||||
|
},
|
||||||
|
onData: function (data) {
|
||||||
|
if (data == "love you")
|
||||||
|
console.log(data);
|
||||||
|
else
|
||||||
|
term.write(data);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
//rowHeight = 0.0 + 1.00 * $('.terminal').height() / 24;
|
||||||
|
//colWidth = 0.0 + 1.00 * $('.terminal').width() / 80;
|
||||||
|
return {'term': term, 'client': client};
|
||||||
|
}
|
||||||
|
|
||||||
|
//function resize() {
|
||||||
|
// $('.terminal').css('width', window.innerWidth - 25);
|
||||||
|
// console.log(window.innerWidth);
|
||||||
|
// console.log(window.innerWidth - 10);
|
||||||
|
// var rows = Math.floor(window.innerHeight / rowHeight) - 2;
|
||||||
|
// var cols = Math.floor(window.innerWidth / colWidth) - 1;
|
||||||
|
//
|
||||||
|
// return {rows: rows, cols: cols};
|
||||||
|
//}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
var options = {};
|
||||||
|
|
||||||
|
$('#ssh').show();
|
||||||
|
var term_client = openTerminal(options);
|
||||||
|
console.log(rowHeight);
|
||||||
|
// by liuzheng712 because it will bring record bug
|
||||||
|
//window.onresize = function () {
|
||||||
|
// var geom = resize();
|
||||||
|
// console.log(geom);
|
||||||
|
// term_client.term.resize(geom.cols, geom.rows);
|
||||||
|
// term_client.client.send({'resize': {'rows': geom.rows, 'cols': geom.cols}});
|
||||||
|
// $('#ssh').show();
|
||||||
|
//}
|
||||||
|
try {
|
||||||
|
$('#term-row')[0].value = localStorage.getItem('term-row');
|
||||||
|
$('#term-col')[0].value = localStorage.getItem('term-col');
|
||||||
|
} catch (err) {
|
||||||
|
$('#term-row')[0].value = 35;
|
||||||
|
$('#term-col')[0].value = 100;
|
||||||
|
}
|
||||||
|
$('#col-row').click(function () {
|
||||||
|
var col = $('#term-col').val();
|
||||||
|
var row = $('#term-row').val();
|
||||||
|
localStorage.setItem('term-col', col);
|
||||||
|
localStorage.setItem('term-row', row);
|
||||||
|
term_client.term.resize(col, row);
|
||||||
|
term_client.client.send({'resize': {'rows': row, 'cols': col}});
|
||||||
|
$('#ssh').show();
|
||||||
|
});
|
||||||
|
$(".terminal").mouseleave(function () {
|
||||||
|
$(".termChangBar").slideDown();
|
||||||
|
});
|
||||||
|
$(".terminal").mouseenter(function () {
|
||||||
|
$(".termChangBar").slideUp();
|
||||||
|
})
|
||||||
|
});</script>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,11 @@
|
||||||
|
# coding:utf-8
|
||||||
|
from django.conf.urls import url
|
||||||
|
from .views import *
|
||||||
|
from django.contrib import admin
|
||||||
|
admin.autodiscover()
|
||||||
|
|
||||||
|
app_name = 'webterminal'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', TerminalView.as_view(), name='webterminal'),
|
||||||
|
]
|
|
@ -1,3 +1,28 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.views.generic.list import ListView
|
||||||
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
|
from django.views.generic.detail import DetailView
|
||||||
|
from django.views.generic.base import TemplateView
|
||||||
|
from django.views import View
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from ws4redis.redis_store import RedisMessage
|
||||||
|
from ws4redis.publisher import RedisPublisher
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
class TerminalView(TemplateView):
|
||||||
|
template_name = 'main.html'
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
welcome = RedisMessage('Hello everybody') # create a welcome message to be sent to everybody
|
||||||
|
RedisPublisher(facility='foobar', broadcast=True).publish_message(welcome)
|
||||||
|
return super(TerminalView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
redis_publisher = RedisPublisher(facility='foobar', groups=[request.POST.get('group')])
|
||||||
|
message = RedisMessage(request.POST.get('message'))
|
||||||
|
redis_publisher.publish_message(message)
|
||||||
|
return HttpResponse('OK')
|
||||||
|
|
Loading…
Reference in New Issue