pull/109/head
Mr Chen 6 years ago
parent d478a697d2
commit 39851704d1
  1. 6
      app.py
  2. 31
      class/core/public.py
  3. 10
      plugins/webssh/index.html
  4. 24
      plugins/webssh/js/webssh.js
  5. 1
      requirements.txt
  6. 118
      route/__init__.py
  7. 49
      route/static/app/public.js
  8. 32
      route/static/css/site.css
  9. 12
      route/templates/default/layout.html

@ -3,10 +3,12 @@
import sys
import io
import os
from route import app
from route import app, socketio
try:
if __name__ == "__main__":
app.run()
PORT = 7200
HOST = '0.0.0.0'
socketio.run(app, host=HOST, port=PORT)
except Exception as ex:
print ex

@ -851,3 +851,34 @@ def get_string_arr(t):
if s1 == s_arr[i][j]:
t_arr.append(str(i) + str(j))
return t_arr
def getSSHPort():
try:
file = '/etc/ssh/sshd_config'
conf = ReadFile(file)
rep = "#*Port\s+([0-9]+)\s*\n"
port = re.search(rep, conf).groups(0)[0]
return int(port)
except:
return 22
def getSSHStatus():
if os.path.exists('/usr/bin/apt-get'):
status = execShell("service ssh status | grep -P '(dead|stop)'")
else:
import system_api
version = system_api.system_api().getSystemVersion()
if version.find(' Mac ') != -1:
return True
if version.find(' 7.') != -1:
status = execShell("systemctl status sshd.service | grep 'dead'")
else:
status = execShell(
"/etc/init.d/sshd status | grep -e 'stopped' -e '已停'")
if len(status[0]) > 3:
status = False
else:
status = True
return status

@ -1,14 +1,10 @@
<script type="text/javascript">
resetPluginWinWidth(480);
$.getScript( "/plugins/file?name=webssh&f=js/webssh.js", function() {
if ($(".term-box #term").text() != 'W') {
layer.closeAll();
webShell();
web_shell2();
}
});
</script>
<script type="text/javascript">
// if ($(".term-box #term").text() != 'W') {
// layer.closeAll();
// web_shell();
// }
</script>

@ -1,6 +1,6 @@
function web_shell() {
var termCols = 100;
var termRows = 29;
function web_shell2() {
var termCols = 50;
var termRows = 12;
var sendTotal = 0;
if(!socket)socket = io.connect();
var term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true});
@ -9,6 +9,7 @@ function web_shell() {
term.setOption('cursorBlink', true);
socket.on('server_response', function (data) {
console.log('server_response',data);
term.write(data.data);
if (data.data == '\r\n登出\r\n' || data.data == '登出\r\n' || data.data == '\r\nlogout\r\n' || data.data == 'logout\r\n') {
@ -26,6 +27,7 @@ function web_shell() {
}
term.on('data', function (data) {
console.log('data',data);
socket.emit('webssh', data);
});
@ -33,7 +35,7 @@ function web_shell() {
var term_box = layer.open({
type: 1,
title: "宝塔终端",
area: ['920px','640px'],
area: ['480px','360px'],
closeBtn: 2,
shadeClose: false,
content: '<div class="term-box"><div id="term"></div></div>\
@ -109,9 +111,6 @@ function web_shell() {
<li>\
<a onclick="shell_paste_text()" '+ paste_str+'>粘贴选中项</a>\
</li>\
<li>\
<a onclick="shell_translate_text()" ' + style_str + '>翻译</a>\
</li>\
<li>\
<a onclick="shell_to_baidu()" ' + style_str + '>百度搜索</a>\
</li>\
@ -166,17 +165,6 @@ function web_shell() {
}
function shell_translate_text() {
remove_ssh_menu();
var selectText = getCookie('ssh_selection');
var loadT = layer.msg('正在翻译...', { icon: 16, time: 1000 * 60, });
$.get('https://www.bt.cn/api/index/fanyi', { query: selectText }, function (rdata) {
layer.close(loadT);
layer.msg("原文: " + rdata.src + '<br>译文: ' + rdata.dst, { time: 1000 * 10, shadeClose: true, shade: 0.01 });
}, 'JSONP');
gterm.focus();
}
function shell_to_baidu() {
var selectText = getCookie('ssh_selection');
remove_ssh_menu();

@ -1,5 +1,6 @@
flask
flask_session
flask_socketio
gunicorn
psutil
pillow

@ -10,6 +10,7 @@ import uuid
reload(sys)
sys.setdefaultencoding('utf8')
from datetime import timedelta
from flask import Flask
@ -23,18 +24,25 @@ from flask import url_for
from flask_session import Session
sys.path.append(os.getcwd() + "/class/core")
import db
import public
import config_api
app = Flask(__name__, template_folder='templates/default')
app.config.version = config_api.config_api().getVersion()
# app.config['SECRET_KEY'] = os.urandom(24)
# app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:]
app.config['SECRET_KEY'] = uuid.UUID(int=uuid.getnode()).hex[-12:]
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
# socketio
sys.path.append("/usr/local/lib/python2.7/site-packages")
from flask_socketio import SocketIO, emit, send
socketio = SocketIO()
socketio.init_app(app)
try:
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/py_mw_session.db'
@ -195,3 +203,111 @@ def index(reqClass=None, reqAction=None, reqData=None):
eval_str = "__import__('" + className + "')." + className + '()'
newInstance = eval(eval_str)
return publicObject(newInstance, reqAction)
ssh = None
shell = None
try:
import paramiko
ssh = paramiko.SSHClient()
except:
public.execShell('pip install paramiko==2.0.2 &')
def connect_ssh():
global shell, ssh
print 'connect_ssh'
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect('127.0.0.1', public.getSSHPort())
except Exception as e:
print 'connect_ssh:', str(e)
if public.getSSHStatus():
try:
ssh.connect('localhost', public.getSSHPort())
except:
return False
import firewalls
fw = firewalls.firewalls()
get = common.dict_obj()
get.status = '0'
fw.SetSshStatus(get)
ssh.connect('127.0.0.1', public.GetSSHPort())
get.status = '1'
fw.SetSshStatus(get)
shell = ssh.invoke_shell(term='xterm', width=100, height=29)
shell.setblocking(0)
return True
# 取数据对象
def get_input_data(data):
pdata = common.dict_obj()
for key in data.keys():
pdata[key] = str(data[key])
return pdata
@socketio.on('webssh')
def webssh(msg):
emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'})
print 'webssh', msg
if not isLogined():
emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'})
return None
global shell, ssh
ssh_success = True
if not shell:
ssh_success = connect_ssh()
if not shell:
emit('server_response', {
'data': public.getMsg('INIT_WEBSSH_CONN_ERR')})
return
if shell.exit_status_ready():
ssh_success = connect_ssh()
if not ssh_success:
emit('server_response', {
'data': public.getMsg('INIT_WEBSSH_CONN_ERR')})
return
shell.send(msg)
try:
time.sleep(0.005)
recv = shell.recv(4096)
emit('server_response', {'data': recv.decode("utf-8")})
except Exception as ex:
pass
@socketio.on('connect_event')
def connected_msg(msg):
connect_ssh()
if not isLogined():
print 'not login'
emit(pdata.s_response, {'data': public.getMsg('INIT_WEBSSH_LOGOUT')})
return None
global shell, ssh
print 'connect_event:connected_msg', msg
try:
recv = shell.recv(8192)
print recv
print recv.decode("utf-8")
emit('server_response', {'data': recv.decode("utf-8")})
except Exception as e:
print 'connect_event:' + str(e)
@socketio.on('panel')
def websocket_test(data):
pdata = get_input_data(data)
if not isLogined():
emit(pdata.s_response, {
'data': public.returnData(-1, '会话丢失,请重新登陆面板!\r\n')})
return None
mods = ['site', 'ftp', 'database', 'ajax', 'system', 'crontab', 'files',
'config', 'panel_data', 'plugin', 'ssl', 'auth', 'firewall', 'panel_wxapp']
if not pdata['s_module'] in mods:
result = public.returnMsg(False, "INIT_WEBSOCKET_ERR")
else:
result = eval("%s(pdata)" % pdata['s_module'])
if not hasattr(pdata, 's_response'):
pdata.s_response = 'response'
emit(pdata.s_response, {'data': result})

@ -1201,12 +1201,14 @@ function loadImage(){
});
}
var socket, gterm;
function webShell() {
var termCols = 100;
var termRows = 29;
var termCols = 50;
var termRows = 12;
var sendTotal = 0;
if(!socket)socket = io.connect();
if(!socket){
socket = io.connect();
}
var term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true});
term.open();
gterm = term
@ -1236,8 +1238,8 @@ function webShell() {
var term_box = layer.open({
type: 1,
title: "宝塔终端",
area: ['920px','640px'],
title: "本地终端",
area: ['480px','300px'],
closeBtn: 2,
shadeClose: false,
content: '<div class="term-box"><div id="term"></div></div>\
@ -1307,18 +1309,9 @@ function webShell() {
var menudiv = '<ul class="contextmenu">\
<li>\
<a class="shell_copy_btn menu_ssh" data-clipboard-text="'+ selectText + '" ' + style_str + '>复制到剪切板</a>\
</li>\
<li>\
<a onclick="shell_paste_text()" '+ paste_str+'>粘贴选中项</a>\
</li>\
<li>\
<a onclick="shell_translate_text()" ' + style_str + '>翻译</a>\
</li>\
<li>\
<a onclick="shell_to_baidu()" ' + style_str + '>百度搜索</a>\
</li>\
<li><a class="shell_copy_btn menu_ssh" data-clipboard-text="'+ selectText + '" ' + style_str + '>复制到剪切板</a></li>\
<li><a onclick="shell_paste_text()" '+ paste_str+'>粘贴选中项</a></li>\
<li><a onclick="shell_to_baidu()" ' + style_str + '>百度搜索</a></li>\
</ul>';
$("body").append(menudiv);
$(".contextmenu").css({
@ -1370,16 +1363,16 @@ function webShell() {
}
function shell_translate_text() {
remove_ssh_menu();
var selectText = getCookie('ssh_selection');
var loadT = layer.msg('正在翻译...', { icon: 16, time: 1000 * 60, });
$.get('https://www.bt.cn/api/index/fanyi', { query: selectText }, function (rdata) {
layer.close(loadT);
layer.msg("原文: " + rdata.src + '<br>译文: ' + rdata.dst, { time: 1000 * 10, shadeClose: true, shade: 0.01 });
}, 'JSONP');
gterm.focus();
}
// function shell_translate_text() {
// remove_ssh_menu();
// var selectText = getCookie('ssh_selection');
// var loadT = layer.msg('正在翻译...', { icon: 16, time: 1000 * 60, });
// $.get('https://www.bt.cn/api/index/fanyi', { query: selectText }, function (rdata) {
// layer.close(loadT);
// layer.msg("原文: " + rdata.src + '<br>译文: ' + rdata.dst, { time: 1000 * 10, shadeClose: true, shade: 0.01 });
// }, 'JSONP');
// gterm.focus();
// }
function shell_to_baidu() {
var selectText = getCookie('ssh_selection');

@ -4646,4 +4646,34 @@ select[disabled]{
}
.btswitch-btn.bt-waf-firewall{
width:2.4em;height:1.4em;margin-bottom: 0
}
}
/*6.0终端样式*/
.term-box{
padding:0 10px 10px;
background-color:#333333;
}
.shell-text-input .bt-input-text-shell{
width:100%;
padding:10px 10px 0;
border:0 none;
height:60px;
overflow:auto;
resize:none;
}
.shell-text-input .bt-input-text-shell:focus,.shell-text-input .bt-input-text-shell:active{
border:0 none;
outline:none;
}
.shell-btn-group{
height:30px;
position:absolute;
bottom:10px;
right:10px;
}
.shell_btn_close{
margin-right:8px;
}

@ -39,15 +39,23 @@
</div>
</div>
<button style="display: none;" id="bt_copys" class="bt_copy" data-clipboard-text=""></button>
<link rel="stylesheet" href="/static/build/xterm.css?v={{config.version}}">
<link rel="stylesheet" href="/static/build/addons/fullscreen/fullscreen.css?v={{config.version}}">
<script src="/static/js/jquery-1.10.2.min.js?v={{config.version}}"></script>
<script src="/static/js/bootstrap.min.js?v={{config.version}}"></script>
<script src="/static/layer/layer.js?v={{config.version}}"></script>
<script src="/static/js/jquery.fly.min.js?v={{config.version}}"></script>
<script src="/static/js/clipboard.min.js?v={{config.version}}"></script>
<script src="/static/build/xterm.js?v={{config.version}}"></script>
<script src="/static/build/addons/attach/attach.js?v={{config.version}}"></script>
<script src="/static/build/addons/fit/fit.js?v={{config.version}}"></script>
<script src="/static/build/addons/fullscreen/fullscreen.js?v={{config.version}}"></script>
<script src="/static/js/socket.io.min.js?v={{config.version}}"></script>
<script src="/static/build/addons/winptyCompat/winptyCompat.js?v={{config.version}}"></script>
<script src="/static/app/public.js?v={{config.version}}"></script>
<script src="/static/js/echarts.min.js?v={{config.version}}"></script>
<script type="text/javascript" src="/static/js/jquery.dragsort-0.5.2.min.js?v={{config.version}}"></script>
<script src="/static/js/socket.io.min.js?v={{config.version}}"></script>
<script src="/static/js/jquery.dragsort-0.5.2.min.js?v={{config.version}}"></script>
{% block content %}{% endblock %}
<div class="footer bgw">mdserver-web &copy;2018-∞ 面板 (<a style="color:#20a53a;" target="_blank" href="//github.com/midoks/mdserver-web">源码</a>)<a style="margin-left:20px;color:#20a53a;" href="//github.com/midoks/mdserver-web/wiki/mdserver-web" target="_blank">wiki</a>
</div>

Loading…
Cancel
Save