From 44c6061d2f19229d40d16aa0708873e54a4823fa Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 24 Aug 2020 11:26:00 +0800 Subject: [PATCH 1/4] kun --- app/common/__init__.py | 2 +- app/intapp/controller/__init__.py | 3 +- app/intapp/controller/index/common/model.py | 84 ++-- app/intapp/controller/index/install.txt | 4 +- app/intapp/controller/index/role.txt | 10 - app/intapp/controller/terminal/__init__.py | 2 + .../controller/terminal/common/__init__.py | 2 + .../controller/terminal/common/autoload.py | 10 + .../terminal/common/file/sqlite/.gitignore | 1 + .../controller/terminal/common/model.py | 64 +++ app/intapp/controller/terminal/index.py | 12 + app/intapp/controller/terminal/install.txt | 1 + app/intapp/controller/terminal/role.txt | 11 + app/intapp/controller/terminal/socket.py | 376 ++++++++++++++++++ .../controller/terminal/tpl/socket/shell.html | 145 +++++++ .../terminal/tpl/socket/shelllog.html | 154 +++++++ .../terminal/tpl/socket/terminallist.html | 231 +++++++++++ server.sh | 3 +- 18 files changed, 1057 insertions(+), 58 deletions(-) create mode 100644 app/intapp/controller/terminal/__init__.py create mode 100644 app/intapp/controller/terminal/common/__init__.py create mode 100644 app/intapp/controller/terminal/common/autoload.py create mode 100644 app/intapp/controller/terminal/common/file/sqlite/.gitignore create mode 100644 app/intapp/controller/terminal/common/model.py create mode 100644 app/intapp/controller/terminal/index.py create mode 100644 app/intapp/controller/terminal/install.txt create mode 100644 app/intapp/controller/terminal/role.txt create mode 100644 app/intapp/controller/terminal/socket.py create mode 100644 app/intapp/controller/terminal/tpl/socket/shell.html create mode 100644 app/intapp/controller/terminal/tpl/socket/shelllog.html create mode 100644 app/intapp/controller/terminal/tpl/socket/terminallist.html diff --git a/app/common/__init__.py b/app/common/__init__.py index baf8c67..2629661 100644 --- a/app/common/__init__.py +++ b/app/common/__init__.py @@ -40,7 +40,7 @@ def serlogin(username,sign,timestamp,random,types="session"): systemrolelist=[ #系统菜单权限 {'title':'首页','icon':config.domain['kcwebimg']+'/icon/home.png','url':'/intapp/index/index/home',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'管理员','icon':config.domain['kcwebimg']+'/icon/admin.png','url':'/intapp/index/admin',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, - {'title':'终端管理','icon':config.domain['kcwebimg']+'/icon/terminal.png','url':'/intapp/index/socket/terminallist',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, + # {'title':'终端管理','icon':config.domain['kcwebimg']+'/icon/terminal.png','url':'/intapp/index/socket/terminallist',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'导航管理','icon':config.domain['kcwebimg']+'/icon/menu.png','url':'/intapp/index/menu',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'模块管理','icon':config.domain['kcwebimg']+'/icon/modular.png','url':'/intapp/index/modular',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'插件管理','icon':config.domain['kcwebimg']+'/icon/plug.png','url':'/intapp/index/plug',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, diff --git a/app/intapp/controller/__init__.py b/app/intapp/controller/__init__.py index 6a03892..4af8bec 100644 --- a/app/intapp/controller/__init__.py +++ b/app/intapp/controller/__init__.py @@ -1,2 +1,3 @@ -from . import index \ No newline at end of file +from . import index +from . import terminal \ No newline at end of file diff --git a/app/intapp/controller/index/common/model.py b/app/intapp/controller/index/common/model.py index 0a9b637..26bc1f2 100644 --- a/app/intapp/controller/index/common/model.py +++ b/app/intapp/controller/index/common/model.py @@ -33,48 +33,48 @@ try: except: model_intapp_interval=model_intapp_interval() model_intapp_interval.create_table() -class model_intapp_terminal(modelsqliteintapp): - "终端列表" - table="terminal" - fields={ - "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 - "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), - "title":model.dbtype.varchar(LEN=128,DEFAULT=''), - "host":model.dbtype.varchar(LEN=32,DEFAULT=''), - "port":model.dbtype.varchar(LEN=32,DEFAULT=''), - "username":model.dbtype.varchar(LEN=32,DEFAULT=''), - "password":model.dbtype.varchar(LEN=32,DEFAULT=''), - "blacklist":model.dbtype.text(), #命令黑名单 - "whitelist":model.dbtype.text(), #命令白名单 - "types":model.dbtype.varchar(LEN=32,DEFAULT='共享连接'), #连接方式 - "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 - "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 - } -try: - sqlite('terminal',model_intapp_index_path).find() -except: - model_intapp_terminal=model_intapp_terminal() - model_intapp_terminal.create_table() -class model_intapp_shelllog(modelsqliteintapp): - "终端操作日志" - table="shelllog" - fields={ - "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 - "uid":model.dbtype.int(LEN=11), - "icon":model.dbtype.varchar(LEN=256,DEFAULT=''), #头像地址 - "name":model.dbtype.varchar(LEN=64,DEFAULT=''), - "host":model.dbtype.varchar(LEN=32,DEFAULT=''), - "port":model.dbtype.varchar(LEN=32,DEFAULT=''), - "username":model.dbtype.varchar(LEN=32,DEFAULT=''), - "password":model.dbtype.varchar(LEN=32,DEFAULT=''), - "cmd":model.dbtype.varchar(LEN=2000,DEFAULT=''), #命令 - "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 - } -try: - sqlite('shelllog',model_intapp_index_path).find() -except: - model_intapp_shelllog=model_intapp_shelllog() - model_intapp_shelllog.create_table() +# class model_intapp_terminal(modelsqliteintapp): +# "终端列表" +# table="terminal" +# fields={ +# "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 +# "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), +# "title":model.dbtype.varchar(LEN=128,DEFAULT=''), +# "host":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "port":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "username":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "password":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "blacklist":model.dbtype.text(), #命令黑名单 +# "whitelist":model.dbtype.text(), #命令白名单 +# "types":model.dbtype.varchar(LEN=32,DEFAULT='共享连接'), #连接方式 +# "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 +# "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 +# } +# try: +# sqlite('terminal',model_intapp_index_path).find() +# except: +# model_intapp_terminal=model_intapp_terminal() +# model_intapp_terminal.create_table() +# class model_intapp_shelllog(modelsqliteintapp): +# "终端操作日志" +# table="shelllog" +# fields={ +# "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 +# "uid":model.dbtype.int(LEN=11), +# "icon":model.dbtype.varchar(LEN=256,DEFAULT=''), #头像地址 +# "name":model.dbtype.varchar(LEN=64,DEFAULT=''), +# "host":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "port":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "username":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "password":model.dbtype.varchar(LEN=32,DEFAULT=''), +# "cmd":model.dbtype.varchar(LEN=2000,DEFAULT=''), #命令 +# "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 +# } +# try: +# sqlite('shelllog',model_intapp_index_path).find() +# except: +# model_intapp_shelllog=model_intapp_shelllog() +# model_intapp_shelllog.create_table() def sqlite(table=None,configss=model_intapp_index_path): """sqlite数据库操作实例 diff --git a/app/intapp/controller/index/install.txt b/app/intapp/controller/index/install.txt index 4e40c2e..8116b77 100644 --- a/app/intapp/controller/index/install.txt +++ b/app/intapp/controller/index/install.txt @@ -1,2 +1,2 @@ -psutil==5.7.0 -pexpect==4.8.0 \ No newline at end of file +pexpect==4.8.0 +psutil==5.7.0 \ No newline at end of file diff --git a/app/intapp/controller/index/role.txt b/app/intapp/controller/index/role.txt index dbcb024..9707eaa 100644 --- a/app/intapp/controller/index/role.txt +++ b/app/intapp/controller/index/role.txt @@ -68,13 +68,3 @@ shell执行能力,/intapp/index/index/shell 阿里云列表,/intapp/index/setup/aliyunosslist 从阿里云备份点恢复,/intapp/index/setup/aliyunossdownload -命令行页面,/intapp/index/socket/shell -终端列表页面,/intapp/index/socket/terminallist -命令日志页面,/intapp/index/socket/shelllog -删除令日志,/intapp/index/socket/deleteshelllog -获命令日志列表,/intapp/index/socket/getshelllog -获取终端列表,/intapp/index/socket/getterminallist -添加终端,/intapp/index/socket/addtermina -删除终端,/intapp/index/socket/delete -修改终端配置,/intapp/index/socket/update -查看ssh密码,/intapp/index/socket/getterminalpwd diff --git a/app/intapp/controller/terminal/__init__.py b/app/intapp/controller/terminal/__init__.py new file mode 100644 index 0000000..9470ed6 --- /dev/null +++ b/app/intapp/controller/terminal/__init__.py @@ -0,0 +1,2 @@ +from . import index +from . import socket \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/__init__.py b/app/intapp/controller/terminal/common/__init__.py new file mode 100644 index 0000000..60767ac --- /dev/null +++ b/app/intapp/controller/terminal/common/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from .model import * \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/autoload.py b/app/intapp/controller/terminal/common/autoload.py new file mode 100644 index 0000000..c4bee80 --- /dev/null +++ b/app/intapp/controller/terminal/common/autoload.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from app.intapp.common import * +import subprocess +def get_process_id(name): + try: + child = subprocess.Popen(['pgrep', '-f', name],stdout=subprocess.PIPE, shell=False) + response = child.communicate()[0] + return [int(pid) for pid in response.split()] + except: + return [] diff --git a/app/intapp/controller/terminal/common/file/sqlite/.gitignore b/app/intapp/controller/terminal/common/file/sqlite/.gitignore new file mode 100644 index 0000000..5a8b5eb --- /dev/null +++ b/app/intapp/controller/terminal/common/file/sqlite/.gitignore @@ -0,0 +1 @@ +terminal \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/model.py b/app/intapp/controller/terminal/common/model.py new file mode 100644 index 0000000..bd65798 --- /dev/null +++ b/app/intapp/controller/terminal/common/model.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +from .autoload import * +# 可以在这里初始化数据库 +model_intapp_terminal_path=os.path.split(os.path.realpath(__file__))[0]+"/file/sqlite/terminal" #数据存放目录 +class modelsqliteintapp(model.model): + config={'type':'sqlite'} + config={'type':'sqlite','db':model_intapp_terminal_path} + model.dbtype.conf=config +class model_intapp_terminal(modelsqliteintapp): + "终端列表" + table="terminal" + fields={ + "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 + "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), + "title":model.dbtype.varchar(LEN=128,DEFAULT=''), + "host":model.dbtype.varchar(LEN=32,DEFAULT=''), + "port":model.dbtype.varchar(LEN=32,DEFAULT=''), + "username":model.dbtype.varchar(LEN=32,DEFAULT=''), + "password":model.dbtype.varchar(LEN=32,DEFAULT=''), + "blacklist":model.dbtype.text(), #命令黑名单 + "whitelist":model.dbtype.text(), #命令白名单 + "types":model.dbtype.varchar(LEN=32,DEFAULT='共享连接'), #连接方式 + "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 + "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 + } +try: + sqlite('terminal',model_intapp_terminal_path).find() +except: + model_intapp_terminal=model_intapp_terminal() + model_intapp_terminal.create_table() +class model_intapp_shelllog(modelsqliteintapp): + "终端操作日志" + table="shelllog" + fields={ + "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 + "uid":model.dbtype.int(LEN=11), + "icon":model.dbtype.varchar(LEN=256,DEFAULT=''), #头像地址 + "name":model.dbtype.varchar(LEN=64,DEFAULT=''), + "host":model.dbtype.varchar(LEN=32,DEFAULT=''), + "port":model.dbtype.varchar(LEN=32,DEFAULT=''), + "username":model.dbtype.varchar(LEN=32,DEFAULT=''), + "password":model.dbtype.varchar(LEN=32,DEFAULT=''), + "cmd":model.dbtype.varchar(LEN=2000,DEFAULT=''), #命令 + "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 + } +try: + sqlite('shelllog',model_intapp_terminal_path).find() +except: + model_intapp_shelllog=model_intapp_shelllog() + model_intapp_shelllog.create_table() +def sqlite(table=None,configss=model_intapp_terminal_path): + """sqlite数据库操作实例 + + 参数 table:表名 + + 参数 configss 数据库配置 可以传数据库名字符串 + """ + dbs=kcwsqlite.sqlite() + if table is None: + return dbs + elif configss: + return dbs.connect(configss).table(table) + else: + return dbs.connect(config.sqlite).table(table) \ No newline at end of file diff --git a/app/intapp/controller/terminal/index.py b/app/intapp/controller/terminal/index.py new file mode 100644 index 0000000..419f449 --- /dev/null +++ b/app/intapp/controller/terminal/index.py @@ -0,0 +1,12 @@ +from .common import * +def index(): + if 'Linux' in get_sysinfo()['platform']: + if not os.path.isfile("/usr/bin/python3.6terminal"): + os.system("ln -s /usr/local/python/python3.6/bin/python3 /usr/bin/python3.6terminal") + if not get_process_id('python3.6terminal'): + cmd="nohup python3.6terminal server.py intapp/terminal/socket/start --cli > server.log 2>&1 &" + os.system(cmd) + elif 'Windows' in get_sysinfo()['platform']: + cmd="start /b python server.py intapp/terminal/socket/start --cli" + os.system(cmd) + return response.redirect("/intapp/terminal/socket/terminallist") diff --git a/app/intapp/controller/terminal/install.txt b/app/intapp/controller/terminal/install.txt new file mode 100644 index 0000000..0b6e7ee --- /dev/null +++ b/app/intapp/controller/terminal/install.txt @@ -0,0 +1 @@ +paramiko==5.7.0 \ No newline at end of file diff --git a/app/intapp/controller/terminal/role.txt b/app/intapp/controller/terminal/role.txt new file mode 100644 index 0000000..3083e49 --- /dev/null +++ b/app/intapp/controller/terminal/role.txt @@ -0,0 +1,11 @@ + +命令行页面,/intapp/terminal/socket/shell +终端列表页面,/intapp/terminal/socket/terminallist +命令日志页面,/intapp/terminal/socket/shelllog +删除令日志,/intapp/terminal/socket/deleteshelllog +获命令日志列表,/intapp/terminal/socket/getshelllog +获取终端列表,/intapp/terminal/socket/getterminallist +添加终端,/intapp/terminal/socket/addtermina +删除终端,/intapp/terminal/socket/delete +修改终端配置,/intapp/terminal/socket/update +查看ssh密码,/intapp/terminal/socket/getterminalpwd diff --git a/app/intapp/controller/terminal/socket.py b/app/intapp/controller/terminal/socket.py new file mode 100644 index 0000000..6ce438d --- /dev/null +++ b/app/intapp/controller/terminal/socket.py @@ -0,0 +1,376 @@ +from .common import * +import paramiko +from urllib import parse +class sockets(kcwebsocket): + trans = {} + channel = {} + terminal={} + cmdstr="" + def __successjson(self,data=[],code=0,msg="成功"): + res={ + "code":code, + "msg":msg, + "time":int(times()), + "data":data + } + return json_encode(res) + def __errorjson(self,data=[],code=1,msg="失败",status='400 error'): + return self.__successjson(data=data,code=code,msg=msg) + def __setterminal(self,clientid,id,userinfo): + "设置终端信息" + try: + self.terminal[clientid] + except: + self.terminal[clientid]=sqlite("terminal").where("id",id).find() + self.terminal[clientid]['id']=id + self.terminal[clientid]['userinfo']=userinfo + if self.terminal[clientid]['blacklist']: #命令黑名单 + self.terminal[clientid]['blacklist']=self.terminal[clientid]['blacklist'].split(",") + else: + self.terminal[clientid]['blacklist']=[] + if self.terminal[clientid]['whitelist']: #命令白名单 + self.terminal[clientid]['whitelist']=self.terminal[clientid]['whitelist'].split(",") + else: + self.terminal[clientid]['whitelist']=[] + async def onConnect(self,clientid,params): + "#当客户端发来连接时触发的回调函数" + try: + uid=params['uid'] + userinfo=get_cache(uid) + if not userinfo: + await self.send_client(clientid,self.__errorjson(msg="您尚未登录")) + return False + del_cache(uid) + authkey=get_cache("websocket") + del_cache("websocket") + id=str(params['id']) + self.__setterminal(clientid,id,userinfo) + if params['authkey']!=authkey: + await self.send_client(clientid,self.__successjson(msg="认证失败")) + return False + else: + if self.terminal[clientid]['types']=='共享连接': + await self.joinGroup(clientid,"Group"+id) #加入组 + try: + self.trans[id] + self.channel[id] + except Exception as e: + self.trans[id] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) + self.trans[id].start_client() + self.trans[id].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) + self.channel[id] = self.trans[id].open_session()# 打开一个通道 + self.channel[id].settimeout(7200) + self.channel[id].get_pty()# 获取一个终端 + self.channel[id].invoke_shell()# 激活器 + self.channel[id].setblocking(False) + while True: + await asyncio.sleep(0.002) + try: + rst = self.channel[id].recv(1024) + except:pass + else: + rst = rst.decode('utf8') + if rst: + resdata=rst.split("\n") + if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 + if(self.cmdstr): + self.cmdstr = self.cmdstr[:-1] + elif '\b' in rst: #多个删除符 + cmdstr=rst.split("\b") + for k in cmdstr: + if not k: + self.cmdstr = self.cmdstr[:-1] + for k in cmdstr: + if k: + self.cmdstr+=k + elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: + self.cmdstr+=rst + try: + await self.sendToGroup("Group"+id,self.__successjson(rst)) + except: + await self.sendToGroup("Group"+id,self.__errorjson("获取执行结果失败")) + else: + await self.send_client(clientid,self.__successjson("连接成功\n当前使用的ssh服务是一个共享连接\n你发送的命令会被该组的所有人看到\n["+self.terminal[clientid]['username']+"@"+self.terminal[clientid]['host']+":"+self.terminal[clientid]['port']+" ]# ")) + else: #独立连接(为每个客户端分配一个连接) + self.trans[id+clientid] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) + self.trans[id+clientid].start_client() + self.trans[id+clientid].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) + self.channel[id+clientid] = self.trans[id+clientid].open_session()# 打开一个通道 + self.channel[id+clientid].settimeout(7200) + self.channel[id+clientid].get_pty()# 获取一个终端 + self.channel[id+clientid].invoke_shell()# 激活器 + self.channel[id+clientid].setblocking(False) + while True: + await asyncio.sleep(0.002) + try: + rst = self.channel[id+clientid].recv(1024) + except:pass + else: + rst = rst.decode('utf8') + if rst: + resdata=rst.split("\n") + if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 + if(self.cmdstr): + self.cmdstr = self.cmdstr[:-1] + elif '\b' in rst: #多个删除符 + cmdstr=rst.split("\b") + for k in cmdstr: + if not k: + self.cmdstr = self.cmdstr[:-1] + for k in cmdstr: + if k: + self.cmdstr+=k + elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: + self.cmdstr+=rst + try: + await self.send_client(clientid,self.__successjson(rst)) + except: + await self.send_client(clientid,self.__errorjson("获取执行结果失败")) + await self.send_client(clientid,self.__successjson("连接成功")) + return True + except Exception as e: + if config.app['app_debug']: + print("连接失败error",clientid,traceback.format_exc()) + await self.send_client(clientid,self.__errorjson(msg="认证失败error"+str(e))) + return False + async def onMessage(self,clientid,recv_text): + "当客户端发来数据时触发的回调函数" + await asyncio.sleep(0.001) + id=self.terminal[clientid]['id'] + try: + data=json_decode(recv_text) + except: + await self.send_client(clientid,self.__errorjson(msg="必须是标准json字符串格式")) + else: + try: + types=data['types'] + except: + await self.send_client(clientid,self.__errorjson(msg="消息格式错误,缺少types")) + else: + if types=='cmd': + cmd=parse.unquote(data['cmd']) + # try: + # self.cmdstr=parse.unquote(data['cmdstr']) + # except KeyError: + # self.cmdstr='' + zxstatus=False + errmsg='' + # if '\u001b[A'==cmd or '\u001b[B'==cmd: #禁止方向键上下 + # zxstatus=False + # errmsg="方向键上和方向键下被禁止" + # else: + # zxstatus=True + if '\u001b[D'==cmd or '\u001b[C'==cmd: #禁止方向键左右 + errmsg="方向键左和方向键右被禁止" + else: + if self.cmdstr: + if len(self.cmdstr) > 2000: + errmsg="该命令不允许执行,因为您的命令字符超过2000" + elif self.terminal[clientid]['whitelist']: #命令白名单 + for k in self.terminal[clientid]['whitelist']: + if k == self.cmdstr: + zxstatus=True + errmsg="该命令不允许执行,因为您的命令不在白名单中" + elif self.terminal[clientid]['blacklist']: #命令黑名单 + zxstatus=True + for k in self.terminal[clientid]['blacklist']: + if k in self.cmdstr: + zxstatus=False + errmsg="该命令不允许执行,因为您的命令出现了被禁用的命令‘"+str(k)+"’" + break + else: + zxstatus=True + if zxstatus: + if self.terminal[clientid]['types']=='共享连接': + if ('\n' in cmd or '\r' in cmd) and self.cmdstr: + try: + sqlite("shelllog",model_intapp_index_path).insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) + except: + print("该命令未被执行,因为无法记录日志",traceback.format_exc()) + self.channel[id].send("\n") + await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) + else: + self.channel[id].send(cmd) + self.cmdstr='' + else: + self.channel[id].send(cmd) + # await self.send_client(clientid,self.__errorjson(cmd,msg="你的命令是")) + else: #独立连接 + if ('\n' in cmd or '\r' in cmd) and self.cmdstr: + try: + sqlite("shelllog",model_intapp_index_path).insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) + except: + print("该命令未被执行,因为无法记录日志",traceback.format_exc()) + self.channel[id].send("\n") + await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) + else: + self.channel[id+clientid].send(cmd) + self.cmdstr='' + else: + self.channel[id+clientid].send(cmd) + else: + if self.terminal[clientid]['types']=='共享连接': + self.channel[id].send("\b") + else:#独立连接 + self.channel[id+clientid].send("\b") + await self.send_client(clientid,self.__errorjson(msg=errmsg)) + else: + await self.send_client(clientid,self.__errorjson(msg="暂不支持types为"+str(types)+"的消息")) + async def onClose(self,clientid): + "客户端与服务端连接断开时触发的回调函数" + id=self.terminal[clientid]['id'] + if self.terminal[clientid]['types']=='共享连接': + pass + else:#独立连接 + self.channel[id+clientid].close() + self.trans[id+clientid].close() + del self.channel[id+clientid] + del self.trans[id+clientid] + await self.sendToGroup("Group"+id,clientid+",已退出") #给当前组户发送消息 + print("onClose",clientid) +def start(): + if config.app['cli']: #cli模式下运行 + socket=sockets() + socket.start(ip='0.0.0.0',port='39020') + +def shell(id=''): + "命令行页面" + id=str(id) + if not id: + item=sqlite("terminal").where("host","127.0.0.1").field("id").find() + if not item: + return "请先配置终端" + else: + id=item['id'] + authkey=md5(randoms()) + set_cache("websocket",authkey,10) + set_cache(str(G.userinfo['id']),G.userinfo,10) + return response.tpl(WebSocketaddress="ws://"+request.HEADER.HTTP_HOST()+":39020?authkey="+authkey+"&id="+id+"&uid="+str(G.userinfo['id'])) +def terminallist(): + "终端列表页面" + return response.tpl() +def shelllog(): + "命令日志页面" + return response.tpl() +def deleteshelllog(): + "删除令日志" + try: + id=request.get_json() + sqlite("shelllog").where('id','in',id).delete() + except: + return errorjson(msg="失败") + else: + return successjson() +def getshelllog(id=0): + "获命令日志列表" + if id: + return successjson(sqlite("shelllog").field('id,uid,icon,name,host,port,username,cmd,addtime').find(id)) + where=None + kw=request.args.get('kw') + pagenow=request.args.get('pagenow') + pagesize=request.args.get('pagesize') + if kw: + where=[("uid","like","%"+str(kw)+"%"),'or',("name","like","%"+str(kw)+"%"),'or',("cmd","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] + if not pagenow: + pagenow=1 + else: + pagenow=int(pagenow) + if not pagesize: + pagesize=10 + else: + pagesize=int(pagesize) + lists=sqlite("shelllog").field("id,uid,icon,name,host,port,username,cmd,addtime").order("id desc").where(where).page(pagenow,pagesize).select() + count=sqlite("shelllog").where(where).count() + data=return_list(lists,count,pagenow,pagesize) + return successjson(data) +def getterminalpwd(id=0,tab='terminal'): + "获取终端密码" + if id: + return successjson(sqlite(tab).field('password').find(id)) + else: + return errorjson(msg="id不能为空") +def getterminallist(id=0): + "获取终端列表" + if id: + return successjson(sqlite("terminal").field('id,icon,title,host,port,types,username,blacklist,whitelist,addtime,updtime').find(id)) + where=None + kw=request.args.get('kw') + pagenow=request.args.get('pagenow') + pagesize=request.args.get('pagesize') + if kw: + where=[("title","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] + if not pagenow: + pagenow=1 + else: + pagenow=int(pagenow) + if not pagesize: + pagesize=10 + else: + pagesize=int(pagesize) + lists=sqlite("terminal").field("id,title,icon,host,port,types,username,addtime,blacklist,whitelist,updtime").where(where).page(pagenow,pagesize).select() + count=sqlite("terminal").where(where).count() + data=return_list(lists,count,pagenow,pagesize) + return successjson(data) +def addtermina(): + "添加终端" + data=request.get_json() + data['addtime']=times() + data['updtime']=times() + if sqlite("terminal").where("host",data['host']).count(): + return errorjson(msg="服务器"+data['host']+"已在列表中,请务重复添加") + if data['host'] and data['port'] and data['username'] and len(data['password'])>5: + try: + trans = paramiko.Transport((data['host'],int(data['port']))) + trans.start_client() + trans.auth_password(username=data['username'], password=data['password']) + channel = trans.open_session() + channel.settimeout(7200) + channel.get_pty() + channel.invoke_shell() + except: + return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") + else: + trans.close() + channel.close() + sqlite("terminal").insert(data) + else: + return errorjson(msg="配置信息格式错误") + return successjson() +def delete(): + "删除终端" + try: + id=request.get_json() + sqlite("terminal").where('id','in',id).delete() + except: + return errorjson(msg="失败") + else: + return successjson() +def update(id=0): + "修改终端配置" + data=request.get_json() + if not id: + id=data['id'] + try: + data['updtime']=times() + except:pass + else: + t=sqlite("terminal").where("id",id).find() + if len(data['password'])>5 and (t['host']!=data['host'] or t['port']!=data['port'] or t['username']!=data['username'] or t['password']!=data['password']): + try: + trans = paramiko.Transport((data['host'],int(data['port']))) + trans.start_client() + trans.auth_password(username=data['username'], password=data['password']) + channel = trans.open_session() + channel.settimeout(7200) + channel.get_pty() + channel.invoke_shell() + except: + return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") + else: + trans.close() + channel.close() + sqlite("terminal").where("id",id).update(data) + else: + del data['password'] + sqlite("terminal").where("id",id).update(data) + return successjson() \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shell.html b/app/intapp/controller/terminal/tpl/socket/shell.html new file mode 100644 index 0000000..2ee8933 --- /dev/null +++ b/app/intapp/controller/terminal/tpl/socket/shell.html @@ -0,0 +1,145 @@ + + + + + +kcwebplus + + + + + + + + + + + + + + + + + +
+
+
+ + + + \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shelllog.html b/app/intapp/controller/terminal/tpl/socket/shelllog.html new file mode 100644 index 0000000..c0f69e0 --- /dev/null +++ b/app/intapp/controller/terminal/tpl/socket/shelllog.html @@ -0,0 +1,154 @@ + + + + +kcwebplus + + + + + + + + + + + + + + + + + + + +
+
+    + + + 搜索 + + 终端管理 +
+
+ + + + + + + + + + + + + + + + + + + +
+    删除选中  + + +
+
+
+ + + diff --git a/app/intapp/controller/terminal/tpl/socket/terminallist.html b/app/intapp/controller/terminal/tpl/socket/terminallist.html new file mode 100644 index 0000000..dce0a22 --- /dev/null +++ b/app/intapp/controller/terminal/tpl/socket/terminallist.html @@ -0,0 +1,231 @@ + + + + +kcwebplus + + + + + + + + + + + + + + + + + + + +
+
+    + + + 搜索 + 添加服务器 + + 命令日志 +
+
+ + + + + + + + + + + + + + + + + + + + + +
+    删除选中  + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 优先级大于命令黑名单,不填写表示不启用,否则在终端完整匹配该命令才能被执行 + + + + 优先级小于命令白名单,不填写表示不启用,否则在终端输入的命令只要包含该命令将会被阻止 + + + + 取 消 + 修改 + 添加 + + +
+ + + diff --git a/server.sh b/server.sh index c90b1db..6dc40ea 100644 --- a/server.sh +++ b/server.sh @@ -3,5 +3,4 @@ chmod -R 777 /kcwebplus nohup ./server --h 0.0.0.0 --p 39001 --w 1 start > server.log 2>&1 & nohup ./server --h 0.0.0.0 --p 39002 --w 2 start > server.log 2>&1 & nohup ./server --h 0.0.0.0 --p 39003 --w 2 start > server.log 2>&1 & -nohup python3.6kcw_plus server.py intapp/index/pub/clistartplan --cli > server.log 2>&1 & -nohup python3.6kcw_plus server.py intapp/index/socket/start --cli > server.log 2>&1 & \ No newline at end of file +nohup python3.6kcw_plus server.py intapp/index/pub/clistartplan --cli > server.log 2>&1 & \ No newline at end of file -- Gitee From 9e9470bba8d3cc28ac892807976a3f035096bbfc Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 24 Aug 2020 11:57:44 +0800 Subject: [PATCH 2/4] kun --- app/intapp/controller/__init__.py | 3 +- app/intapp/controller/index/__init__.py | 3 +- app/intapp/controller/index/socket.py | 376 ------------------ .../controller/index/tpl/socket/shell.html | 145 ------- .../controller/index/tpl/socket/shelllog.html | 154 ------- .../index/tpl/socket/terminallist.html | 231 ----------- app/intapp/controller/terminal/__init__.py | 2 - .../controller/terminal/common/__init__.py | 2 - .../controller/terminal/common/autoload.py | 10 - .../terminal/common/file/sqlite/.gitignore | 1 - .../controller/terminal/common/model.py | 64 --- app/intapp/controller/terminal/index.py | 12 - app/intapp/controller/terminal/install.txt | 1 - app/intapp/controller/terminal/role.txt | 11 - app/intapp/controller/terminal/socket.py | 376 ------------------ .../controller/terminal/tpl/socket/shell.html | 145 ------- .../terminal/tpl/socket/shelllog.html | 154 ------- .../terminal/tpl/socket/terminallist.html | 231 ----------- 18 files changed, 2 insertions(+), 1919 deletions(-) delete mode 100644 app/intapp/controller/index/socket.py delete mode 100644 app/intapp/controller/index/tpl/socket/shell.html delete mode 100644 app/intapp/controller/index/tpl/socket/shelllog.html delete mode 100644 app/intapp/controller/index/tpl/socket/terminallist.html delete mode 100644 app/intapp/controller/terminal/__init__.py delete mode 100644 app/intapp/controller/terminal/common/__init__.py delete mode 100644 app/intapp/controller/terminal/common/autoload.py delete mode 100644 app/intapp/controller/terminal/common/file/sqlite/.gitignore delete mode 100644 app/intapp/controller/terminal/common/model.py delete mode 100644 app/intapp/controller/terminal/index.py delete mode 100644 app/intapp/controller/terminal/install.txt delete mode 100644 app/intapp/controller/terminal/role.txt delete mode 100644 app/intapp/controller/terminal/socket.py delete mode 100644 app/intapp/controller/terminal/tpl/socket/shell.html delete mode 100644 app/intapp/controller/terminal/tpl/socket/shelllog.html delete mode 100644 app/intapp/controller/terminal/tpl/socket/terminallist.html diff --git a/app/intapp/controller/__init__.py b/app/intapp/controller/__init__.py index 4af8bec..6a03892 100644 --- a/app/intapp/controller/__init__.py +++ b/app/intapp/controller/__init__.py @@ -1,3 +1,2 @@ -from . import index -from . import terminal \ No newline at end of file +from . import index \ No newline at end of file diff --git a/app/intapp/controller/index/__init__.py b/app/intapp/controller/index/__init__.py index 0e70a9d..a4f463e 100644 --- a/app/intapp/controller/index/__init__.py +++ b/app/intapp/controller/index/__init__.py @@ -6,5 +6,4 @@ from . import admin from . import plan from . import task from . import setup -from . import menu -from . import socket \ No newline at end of file +from . import menu \ No newline at end of file diff --git a/app/intapp/controller/index/socket.py b/app/intapp/controller/index/socket.py deleted file mode 100644 index 6ce438d..0000000 --- a/app/intapp/controller/index/socket.py +++ /dev/null @@ -1,376 +0,0 @@ -from .common import * -import paramiko -from urllib import parse -class sockets(kcwebsocket): - trans = {} - channel = {} - terminal={} - cmdstr="" - def __successjson(self,data=[],code=0,msg="成功"): - res={ - "code":code, - "msg":msg, - "time":int(times()), - "data":data - } - return json_encode(res) - def __errorjson(self,data=[],code=1,msg="失败",status='400 error'): - return self.__successjson(data=data,code=code,msg=msg) - def __setterminal(self,clientid,id,userinfo): - "设置终端信息" - try: - self.terminal[clientid] - except: - self.terminal[clientid]=sqlite("terminal").where("id",id).find() - self.terminal[clientid]['id']=id - self.terminal[clientid]['userinfo']=userinfo - if self.terminal[clientid]['blacklist']: #命令黑名单 - self.terminal[clientid]['blacklist']=self.terminal[clientid]['blacklist'].split(",") - else: - self.terminal[clientid]['blacklist']=[] - if self.terminal[clientid]['whitelist']: #命令白名单 - self.terminal[clientid]['whitelist']=self.terminal[clientid]['whitelist'].split(",") - else: - self.terminal[clientid]['whitelist']=[] - async def onConnect(self,clientid,params): - "#当客户端发来连接时触发的回调函数" - try: - uid=params['uid'] - userinfo=get_cache(uid) - if not userinfo: - await self.send_client(clientid,self.__errorjson(msg="您尚未登录")) - return False - del_cache(uid) - authkey=get_cache("websocket") - del_cache("websocket") - id=str(params['id']) - self.__setterminal(clientid,id,userinfo) - if params['authkey']!=authkey: - await self.send_client(clientid,self.__successjson(msg="认证失败")) - return False - else: - if self.terminal[clientid]['types']=='共享连接': - await self.joinGroup(clientid,"Group"+id) #加入组 - try: - self.trans[id] - self.channel[id] - except Exception as e: - self.trans[id] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) - self.trans[id].start_client() - self.trans[id].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) - self.channel[id] = self.trans[id].open_session()# 打开一个通道 - self.channel[id].settimeout(7200) - self.channel[id].get_pty()# 获取一个终端 - self.channel[id].invoke_shell()# 激活器 - self.channel[id].setblocking(False) - while True: - await asyncio.sleep(0.002) - try: - rst = self.channel[id].recv(1024) - except:pass - else: - rst = rst.decode('utf8') - if rst: - resdata=rst.split("\n") - if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 - if(self.cmdstr): - self.cmdstr = self.cmdstr[:-1] - elif '\b' in rst: #多个删除符 - cmdstr=rst.split("\b") - for k in cmdstr: - if not k: - self.cmdstr = self.cmdstr[:-1] - for k in cmdstr: - if k: - self.cmdstr+=k - elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: - self.cmdstr+=rst - try: - await self.sendToGroup("Group"+id,self.__successjson(rst)) - except: - await self.sendToGroup("Group"+id,self.__errorjson("获取执行结果失败")) - else: - await self.send_client(clientid,self.__successjson("连接成功\n当前使用的ssh服务是一个共享连接\n你发送的命令会被该组的所有人看到\n["+self.terminal[clientid]['username']+"@"+self.terminal[clientid]['host']+":"+self.terminal[clientid]['port']+" ]# ")) - else: #独立连接(为每个客户端分配一个连接) - self.trans[id+clientid] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) - self.trans[id+clientid].start_client() - self.trans[id+clientid].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) - self.channel[id+clientid] = self.trans[id+clientid].open_session()# 打开一个通道 - self.channel[id+clientid].settimeout(7200) - self.channel[id+clientid].get_pty()# 获取一个终端 - self.channel[id+clientid].invoke_shell()# 激活器 - self.channel[id+clientid].setblocking(False) - while True: - await asyncio.sleep(0.002) - try: - rst = self.channel[id+clientid].recv(1024) - except:pass - else: - rst = rst.decode('utf8') - if rst: - resdata=rst.split("\n") - if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 - if(self.cmdstr): - self.cmdstr = self.cmdstr[:-1] - elif '\b' in rst: #多个删除符 - cmdstr=rst.split("\b") - for k in cmdstr: - if not k: - self.cmdstr = self.cmdstr[:-1] - for k in cmdstr: - if k: - self.cmdstr+=k - elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: - self.cmdstr+=rst - try: - await self.send_client(clientid,self.__successjson(rst)) - except: - await self.send_client(clientid,self.__errorjson("获取执行结果失败")) - await self.send_client(clientid,self.__successjson("连接成功")) - return True - except Exception as e: - if config.app['app_debug']: - print("连接失败error",clientid,traceback.format_exc()) - await self.send_client(clientid,self.__errorjson(msg="认证失败error"+str(e))) - return False - async def onMessage(self,clientid,recv_text): - "当客户端发来数据时触发的回调函数" - await asyncio.sleep(0.001) - id=self.terminal[clientid]['id'] - try: - data=json_decode(recv_text) - except: - await self.send_client(clientid,self.__errorjson(msg="必须是标准json字符串格式")) - else: - try: - types=data['types'] - except: - await self.send_client(clientid,self.__errorjson(msg="消息格式错误,缺少types")) - else: - if types=='cmd': - cmd=parse.unquote(data['cmd']) - # try: - # self.cmdstr=parse.unquote(data['cmdstr']) - # except KeyError: - # self.cmdstr='' - zxstatus=False - errmsg='' - # if '\u001b[A'==cmd or '\u001b[B'==cmd: #禁止方向键上下 - # zxstatus=False - # errmsg="方向键上和方向键下被禁止" - # else: - # zxstatus=True - if '\u001b[D'==cmd or '\u001b[C'==cmd: #禁止方向键左右 - errmsg="方向键左和方向键右被禁止" - else: - if self.cmdstr: - if len(self.cmdstr) > 2000: - errmsg="该命令不允许执行,因为您的命令字符超过2000" - elif self.terminal[clientid]['whitelist']: #命令白名单 - for k in self.terminal[clientid]['whitelist']: - if k == self.cmdstr: - zxstatus=True - errmsg="该命令不允许执行,因为您的命令不在白名单中" - elif self.terminal[clientid]['blacklist']: #命令黑名单 - zxstatus=True - for k in self.terminal[clientid]['blacklist']: - if k in self.cmdstr: - zxstatus=False - errmsg="该命令不允许执行,因为您的命令出现了被禁用的命令‘"+str(k)+"’" - break - else: - zxstatus=True - if zxstatus: - if self.terminal[clientid]['types']=='共享连接': - if ('\n' in cmd or '\r' in cmd) and self.cmdstr: - try: - sqlite("shelllog",model_intapp_index_path).insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) - except: - print("该命令未被执行,因为无法记录日志",traceback.format_exc()) - self.channel[id].send("\n") - await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) - else: - self.channel[id].send(cmd) - self.cmdstr='' - else: - self.channel[id].send(cmd) - # await self.send_client(clientid,self.__errorjson(cmd,msg="你的命令是")) - else: #独立连接 - if ('\n' in cmd or '\r' in cmd) and self.cmdstr: - try: - sqlite("shelllog",model_intapp_index_path).insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) - except: - print("该命令未被执行,因为无法记录日志",traceback.format_exc()) - self.channel[id].send("\n") - await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) - else: - self.channel[id+clientid].send(cmd) - self.cmdstr='' - else: - self.channel[id+clientid].send(cmd) - else: - if self.terminal[clientid]['types']=='共享连接': - self.channel[id].send("\b") - else:#独立连接 - self.channel[id+clientid].send("\b") - await self.send_client(clientid,self.__errorjson(msg=errmsg)) - else: - await self.send_client(clientid,self.__errorjson(msg="暂不支持types为"+str(types)+"的消息")) - async def onClose(self,clientid): - "客户端与服务端连接断开时触发的回调函数" - id=self.terminal[clientid]['id'] - if self.terminal[clientid]['types']=='共享连接': - pass - else:#独立连接 - self.channel[id+clientid].close() - self.trans[id+clientid].close() - del self.channel[id+clientid] - del self.trans[id+clientid] - await self.sendToGroup("Group"+id,clientid+",已退出") #给当前组户发送消息 - print("onClose",clientid) -def start(): - if config.app['cli']: #cli模式下运行 - socket=sockets() - socket.start(ip='0.0.0.0',port='39020') - -def shell(id=''): - "命令行页面" - id=str(id) - if not id: - item=sqlite("terminal").where("host","127.0.0.1").field("id").find() - if not item: - return "请先配置终端" - else: - id=item['id'] - authkey=md5(randoms()) - set_cache("websocket",authkey,10) - set_cache(str(G.userinfo['id']),G.userinfo,10) - return response.tpl(WebSocketaddress="ws://"+request.HEADER.HTTP_HOST()+":39020?authkey="+authkey+"&id="+id+"&uid="+str(G.userinfo['id'])) -def terminallist(): - "终端列表页面" - return response.tpl() -def shelllog(): - "命令日志页面" - return response.tpl() -def deleteshelllog(): - "删除令日志" - try: - id=request.get_json() - sqlite("shelllog").where('id','in',id).delete() - except: - return errorjson(msg="失败") - else: - return successjson() -def getshelllog(id=0): - "获命令日志列表" - if id: - return successjson(sqlite("shelllog").field('id,uid,icon,name,host,port,username,cmd,addtime').find(id)) - where=None - kw=request.args.get('kw') - pagenow=request.args.get('pagenow') - pagesize=request.args.get('pagesize') - if kw: - where=[("uid","like","%"+str(kw)+"%"),'or',("name","like","%"+str(kw)+"%"),'or',("cmd","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] - if not pagenow: - pagenow=1 - else: - pagenow=int(pagenow) - if not pagesize: - pagesize=10 - else: - pagesize=int(pagesize) - lists=sqlite("shelllog").field("id,uid,icon,name,host,port,username,cmd,addtime").order("id desc").where(where).page(pagenow,pagesize).select() - count=sqlite("shelllog").where(where).count() - data=return_list(lists,count,pagenow,pagesize) - return successjson(data) -def getterminalpwd(id=0,tab='terminal'): - "获取终端密码" - if id: - return successjson(sqlite(tab).field('password').find(id)) - else: - return errorjson(msg="id不能为空") -def getterminallist(id=0): - "获取终端列表" - if id: - return successjson(sqlite("terminal").field('id,icon,title,host,port,types,username,blacklist,whitelist,addtime,updtime').find(id)) - where=None - kw=request.args.get('kw') - pagenow=request.args.get('pagenow') - pagesize=request.args.get('pagesize') - if kw: - where=[("title","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] - if not pagenow: - pagenow=1 - else: - pagenow=int(pagenow) - if not pagesize: - pagesize=10 - else: - pagesize=int(pagesize) - lists=sqlite("terminal").field("id,title,icon,host,port,types,username,addtime,blacklist,whitelist,updtime").where(where).page(pagenow,pagesize).select() - count=sqlite("terminal").where(where).count() - data=return_list(lists,count,pagenow,pagesize) - return successjson(data) -def addtermina(): - "添加终端" - data=request.get_json() - data['addtime']=times() - data['updtime']=times() - if sqlite("terminal").where("host",data['host']).count(): - return errorjson(msg="服务器"+data['host']+"已在列表中,请务重复添加") - if data['host'] and data['port'] and data['username'] and len(data['password'])>5: - try: - trans = paramiko.Transport((data['host'],int(data['port']))) - trans.start_client() - trans.auth_password(username=data['username'], password=data['password']) - channel = trans.open_session() - channel.settimeout(7200) - channel.get_pty() - channel.invoke_shell() - except: - return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") - else: - trans.close() - channel.close() - sqlite("terminal").insert(data) - else: - return errorjson(msg="配置信息格式错误") - return successjson() -def delete(): - "删除终端" - try: - id=request.get_json() - sqlite("terminal").where('id','in',id).delete() - except: - return errorjson(msg="失败") - else: - return successjson() -def update(id=0): - "修改终端配置" - data=request.get_json() - if not id: - id=data['id'] - try: - data['updtime']=times() - except:pass - else: - t=sqlite("terminal").where("id",id).find() - if len(data['password'])>5 and (t['host']!=data['host'] or t['port']!=data['port'] or t['username']!=data['username'] or t['password']!=data['password']): - try: - trans = paramiko.Transport((data['host'],int(data['port']))) - trans.start_client() - trans.auth_password(username=data['username'], password=data['password']) - channel = trans.open_session() - channel.settimeout(7200) - channel.get_pty() - channel.invoke_shell() - except: - return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") - else: - trans.close() - channel.close() - sqlite("terminal").where("id",id).update(data) - else: - del data['password'] - sqlite("terminal").where("id",id).update(data) - return successjson() \ No newline at end of file diff --git a/app/intapp/controller/index/tpl/socket/shell.html b/app/intapp/controller/index/tpl/socket/shell.html deleted file mode 100644 index 2ee8933..0000000 --- a/app/intapp/controller/index/tpl/socket/shell.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - -kcwebplus - - - - - - - - - - - - - - - - - -
-
-
- - - - \ No newline at end of file diff --git a/app/intapp/controller/index/tpl/socket/shelllog.html b/app/intapp/controller/index/tpl/socket/shelllog.html deleted file mode 100644 index 5a0c144..0000000 --- a/app/intapp/controller/index/tpl/socket/shelllog.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - -kcwebplus - - - - - - - - - - - - - - - - - - - -
-
-    - - - 搜索 - - 终端管理 -
-
- - - - - - - - - - - - - - - - - - - -
-    删除选中  - - -
-
-
- - - diff --git a/app/intapp/controller/index/tpl/socket/terminallist.html b/app/intapp/controller/index/tpl/socket/terminallist.html deleted file mode 100644 index 5e6e601..0000000 --- a/app/intapp/controller/index/tpl/socket/terminallist.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - -kcwebplus - - - - - - - - - - - - - - - - - - - -
-
-    - - - 搜索 - 添加服务器 - - 命令日志 -
-
- - - - - - - - - - - - - - - - - - - - - -
-    删除选中  - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 优先级大于命令黑名单,不填写表示不启用,否则在终端完整匹配该命令才能被执行 - - - - 优先级小于命令白名单,不填写表示不启用,否则在终端输入的命令只要包含该命令将会被阻止 - - - - 取 消 - 修改 - 添加 - - -
- - - diff --git a/app/intapp/controller/terminal/__init__.py b/app/intapp/controller/terminal/__init__.py deleted file mode 100644 index 9470ed6..0000000 --- a/app/intapp/controller/terminal/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import index -from . import socket \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/__init__.py b/app/intapp/controller/terminal/common/__init__.py deleted file mode 100644 index 60767ac..0000000 --- a/app/intapp/controller/terminal/common/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -from .model import * \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/autoload.py b/app/intapp/controller/terminal/common/autoload.py deleted file mode 100644 index c4bee80..0000000 --- a/app/intapp/controller/terminal/common/autoload.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -from app.intapp.common import * -import subprocess -def get_process_id(name): - try: - child = subprocess.Popen(['pgrep', '-f', name],stdout=subprocess.PIPE, shell=False) - response = child.communicate()[0] - return [int(pid) for pid in response.split()] - except: - return [] diff --git a/app/intapp/controller/terminal/common/file/sqlite/.gitignore b/app/intapp/controller/terminal/common/file/sqlite/.gitignore deleted file mode 100644 index 5a8b5eb..0000000 --- a/app/intapp/controller/terminal/common/file/sqlite/.gitignore +++ /dev/null @@ -1 +0,0 @@ -terminal \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/model.py b/app/intapp/controller/terminal/common/model.py deleted file mode 100644 index bd65798..0000000 --- a/app/intapp/controller/terminal/common/model.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -from .autoload import * -# 可以在这里初始化数据库 -model_intapp_terminal_path=os.path.split(os.path.realpath(__file__))[0]+"/file/sqlite/terminal" #数据存放目录 -class modelsqliteintapp(model.model): - config={'type':'sqlite'} - config={'type':'sqlite','db':model_intapp_terminal_path} - model.dbtype.conf=config -class model_intapp_terminal(modelsqliteintapp): - "终端列表" - table="terminal" - fields={ - "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 - "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), - "title":model.dbtype.varchar(LEN=128,DEFAULT=''), - "host":model.dbtype.varchar(LEN=32,DEFAULT=''), - "port":model.dbtype.varchar(LEN=32,DEFAULT=''), - "username":model.dbtype.varchar(LEN=32,DEFAULT=''), - "password":model.dbtype.varchar(LEN=32,DEFAULT=''), - "blacklist":model.dbtype.text(), #命令黑名单 - "whitelist":model.dbtype.text(), #命令白名单 - "types":model.dbtype.varchar(LEN=32,DEFAULT='共享连接'), #连接方式 - "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 - "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 - } -try: - sqlite('terminal',model_intapp_terminal_path).find() -except: - model_intapp_terminal=model_intapp_terminal() - model_intapp_terminal.create_table() -class model_intapp_shelllog(modelsqliteintapp): - "终端操作日志" - table="shelllog" - fields={ - "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 - "uid":model.dbtype.int(LEN=11), - "icon":model.dbtype.varchar(LEN=256,DEFAULT=''), #头像地址 - "name":model.dbtype.varchar(LEN=64,DEFAULT=''), - "host":model.dbtype.varchar(LEN=32,DEFAULT=''), - "port":model.dbtype.varchar(LEN=32,DEFAULT=''), - "username":model.dbtype.varchar(LEN=32,DEFAULT=''), - "password":model.dbtype.varchar(LEN=32,DEFAULT=''), - "cmd":model.dbtype.varchar(LEN=2000,DEFAULT=''), #命令 - "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 - } -try: - sqlite('shelllog',model_intapp_terminal_path).find() -except: - model_intapp_shelllog=model_intapp_shelllog() - model_intapp_shelllog.create_table() -def sqlite(table=None,configss=model_intapp_terminal_path): - """sqlite数据库操作实例 - - 参数 table:表名 - - 参数 configss 数据库配置 可以传数据库名字符串 - """ - dbs=kcwsqlite.sqlite() - if table is None: - return dbs - elif configss: - return dbs.connect(configss).table(table) - else: - return dbs.connect(config.sqlite).table(table) \ No newline at end of file diff --git a/app/intapp/controller/terminal/index.py b/app/intapp/controller/terminal/index.py deleted file mode 100644 index 419f449..0000000 --- a/app/intapp/controller/terminal/index.py +++ /dev/null @@ -1,12 +0,0 @@ -from .common import * -def index(): - if 'Linux' in get_sysinfo()['platform']: - if not os.path.isfile("/usr/bin/python3.6terminal"): - os.system("ln -s /usr/local/python/python3.6/bin/python3 /usr/bin/python3.6terminal") - if not get_process_id('python3.6terminal'): - cmd="nohup python3.6terminal server.py intapp/terminal/socket/start --cli > server.log 2>&1 &" - os.system(cmd) - elif 'Windows' in get_sysinfo()['platform']: - cmd="start /b python server.py intapp/terminal/socket/start --cli" - os.system(cmd) - return response.redirect("/intapp/terminal/socket/terminallist") diff --git a/app/intapp/controller/terminal/install.txt b/app/intapp/controller/terminal/install.txt deleted file mode 100644 index 0b6e7ee..0000000 --- a/app/intapp/controller/terminal/install.txt +++ /dev/null @@ -1 +0,0 @@ -paramiko==5.7.0 \ No newline at end of file diff --git a/app/intapp/controller/terminal/role.txt b/app/intapp/controller/terminal/role.txt deleted file mode 100644 index 3083e49..0000000 --- a/app/intapp/controller/terminal/role.txt +++ /dev/null @@ -1,11 +0,0 @@ - -命令行页面,/intapp/terminal/socket/shell -终端列表页面,/intapp/terminal/socket/terminallist -命令日志页面,/intapp/terminal/socket/shelllog -删除令日志,/intapp/terminal/socket/deleteshelllog -获命令日志列表,/intapp/terminal/socket/getshelllog -获取终端列表,/intapp/terminal/socket/getterminallist -添加终端,/intapp/terminal/socket/addtermina -删除终端,/intapp/terminal/socket/delete -修改终端配置,/intapp/terminal/socket/update -查看ssh密码,/intapp/terminal/socket/getterminalpwd diff --git a/app/intapp/controller/terminal/socket.py b/app/intapp/controller/terminal/socket.py deleted file mode 100644 index 6ce438d..0000000 --- a/app/intapp/controller/terminal/socket.py +++ /dev/null @@ -1,376 +0,0 @@ -from .common import * -import paramiko -from urllib import parse -class sockets(kcwebsocket): - trans = {} - channel = {} - terminal={} - cmdstr="" - def __successjson(self,data=[],code=0,msg="成功"): - res={ - "code":code, - "msg":msg, - "time":int(times()), - "data":data - } - return json_encode(res) - def __errorjson(self,data=[],code=1,msg="失败",status='400 error'): - return self.__successjson(data=data,code=code,msg=msg) - def __setterminal(self,clientid,id,userinfo): - "设置终端信息" - try: - self.terminal[clientid] - except: - self.terminal[clientid]=sqlite("terminal").where("id",id).find() - self.terminal[clientid]['id']=id - self.terminal[clientid]['userinfo']=userinfo - if self.terminal[clientid]['blacklist']: #命令黑名单 - self.terminal[clientid]['blacklist']=self.terminal[clientid]['blacklist'].split(",") - else: - self.terminal[clientid]['blacklist']=[] - if self.terminal[clientid]['whitelist']: #命令白名单 - self.terminal[clientid]['whitelist']=self.terminal[clientid]['whitelist'].split(",") - else: - self.terminal[clientid]['whitelist']=[] - async def onConnect(self,clientid,params): - "#当客户端发来连接时触发的回调函数" - try: - uid=params['uid'] - userinfo=get_cache(uid) - if not userinfo: - await self.send_client(clientid,self.__errorjson(msg="您尚未登录")) - return False - del_cache(uid) - authkey=get_cache("websocket") - del_cache("websocket") - id=str(params['id']) - self.__setterminal(clientid,id,userinfo) - if params['authkey']!=authkey: - await self.send_client(clientid,self.__successjson(msg="认证失败")) - return False - else: - if self.terminal[clientid]['types']=='共享连接': - await self.joinGroup(clientid,"Group"+id) #加入组 - try: - self.trans[id] - self.channel[id] - except Exception as e: - self.trans[id] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) - self.trans[id].start_client() - self.trans[id].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) - self.channel[id] = self.trans[id].open_session()# 打开一个通道 - self.channel[id].settimeout(7200) - self.channel[id].get_pty()# 获取一个终端 - self.channel[id].invoke_shell()# 激活器 - self.channel[id].setblocking(False) - while True: - await asyncio.sleep(0.002) - try: - rst = self.channel[id].recv(1024) - except:pass - else: - rst = rst.decode('utf8') - if rst: - resdata=rst.split("\n") - if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 - if(self.cmdstr): - self.cmdstr = self.cmdstr[:-1] - elif '\b' in rst: #多个删除符 - cmdstr=rst.split("\b") - for k in cmdstr: - if not k: - self.cmdstr = self.cmdstr[:-1] - for k in cmdstr: - if k: - self.cmdstr+=k - elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: - self.cmdstr+=rst - try: - await self.sendToGroup("Group"+id,self.__successjson(rst)) - except: - await self.sendToGroup("Group"+id,self.__errorjson("获取执行结果失败")) - else: - await self.send_client(clientid,self.__successjson("连接成功\n当前使用的ssh服务是一个共享连接\n你发送的命令会被该组的所有人看到\n["+self.terminal[clientid]['username']+"@"+self.terminal[clientid]['host']+":"+self.terminal[clientid]['port']+" ]# ")) - else: #独立连接(为每个客户端分配一个连接) - self.trans[id+clientid] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) - self.trans[id+clientid].start_client() - self.trans[id+clientid].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) - self.channel[id+clientid] = self.trans[id+clientid].open_session()# 打开一个通道 - self.channel[id+clientid].settimeout(7200) - self.channel[id+clientid].get_pty()# 获取一个终端 - self.channel[id+clientid].invoke_shell()# 激活器 - self.channel[id+clientid].setblocking(False) - while True: - await asyncio.sleep(0.002) - try: - rst = self.channel[id+clientid].recv(1024) - except:pass - else: - rst = rst.decode('utf8') - if rst: - resdata=rst.split("\n") - if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 - if(self.cmdstr): - self.cmdstr = self.cmdstr[:-1] - elif '\b' in rst: #多个删除符 - cmdstr=rst.split("\b") - for k in cmdstr: - if not k: - self.cmdstr = self.cmdstr[:-1] - for k in cmdstr: - if k: - self.cmdstr+=k - elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: - self.cmdstr+=rst - try: - await self.send_client(clientid,self.__successjson(rst)) - except: - await self.send_client(clientid,self.__errorjson("获取执行结果失败")) - await self.send_client(clientid,self.__successjson("连接成功")) - return True - except Exception as e: - if config.app['app_debug']: - print("连接失败error",clientid,traceback.format_exc()) - await self.send_client(clientid,self.__errorjson(msg="认证失败error"+str(e))) - return False - async def onMessage(self,clientid,recv_text): - "当客户端发来数据时触发的回调函数" - await asyncio.sleep(0.001) - id=self.terminal[clientid]['id'] - try: - data=json_decode(recv_text) - except: - await self.send_client(clientid,self.__errorjson(msg="必须是标准json字符串格式")) - else: - try: - types=data['types'] - except: - await self.send_client(clientid,self.__errorjson(msg="消息格式错误,缺少types")) - else: - if types=='cmd': - cmd=parse.unquote(data['cmd']) - # try: - # self.cmdstr=parse.unquote(data['cmdstr']) - # except KeyError: - # self.cmdstr='' - zxstatus=False - errmsg='' - # if '\u001b[A'==cmd or '\u001b[B'==cmd: #禁止方向键上下 - # zxstatus=False - # errmsg="方向键上和方向键下被禁止" - # else: - # zxstatus=True - if '\u001b[D'==cmd or '\u001b[C'==cmd: #禁止方向键左右 - errmsg="方向键左和方向键右被禁止" - else: - if self.cmdstr: - if len(self.cmdstr) > 2000: - errmsg="该命令不允许执行,因为您的命令字符超过2000" - elif self.terminal[clientid]['whitelist']: #命令白名单 - for k in self.terminal[clientid]['whitelist']: - if k == self.cmdstr: - zxstatus=True - errmsg="该命令不允许执行,因为您的命令不在白名单中" - elif self.terminal[clientid]['blacklist']: #命令黑名单 - zxstatus=True - for k in self.terminal[clientid]['blacklist']: - if k in self.cmdstr: - zxstatus=False - errmsg="该命令不允许执行,因为您的命令出现了被禁用的命令‘"+str(k)+"’" - break - else: - zxstatus=True - if zxstatus: - if self.terminal[clientid]['types']=='共享连接': - if ('\n' in cmd or '\r' in cmd) and self.cmdstr: - try: - sqlite("shelllog",model_intapp_index_path).insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) - except: - print("该命令未被执行,因为无法记录日志",traceback.format_exc()) - self.channel[id].send("\n") - await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) - else: - self.channel[id].send(cmd) - self.cmdstr='' - else: - self.channel[id].send(cmd) - # await self.send_client(clientid,self.__errorjson(cmd,msg="你的命令是")) - else: #独立连接 - if ('\n' in cmd or '\r' in cmd) and self.cmdstr: - try: - sqlite("shelllog",model_intapp_index_path).insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) - except: - print("该命令未被执行,因为无法记录日志",traceback.format_exc()) - self.channel[id].send("\n") - await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) - else: - self.channel[id+clientid].send(cmd) - self.cmdstr='' - else: - self.channel[id+clientid].send(cmd) - else: - if self.terminal[clientid]['types']=='共享连接': - self.channel[id].send("\b") - else:#独立连接 - self.channel[id+clientid].send("\b") - await self.send_client(clientid,self.__errorjson(msg=errmsg)) - else: - await self.send_client(clientid,self.__errorjson(msg="暂不支持types为"+str(types)+"的消息")) - async def onClose(self,clientid): - "客户端与服务端连接断开时触发的回调函数" - id=self.terminal[clientid]['id'] - if self.terminal[clientid]['types']=='共享连接': - pass - else:#独立连接 - self.channel[id+clientid].close() - self.trans[id+clientid].close() - del self.channel[id+clientid] - del self.trans[id+clientid] - await self.sendToGroup("Group"+id,clientid+",已退出") #给当前组户发送消息 - print("onClose",clientid) -def start(): - if config.app['cli']: #cli模式下运行 - socket=sockets() - socket.start(ip='0.0.0.0',port='39020') - -def shell(id=''): - "命令行页面" - id=str(id) - if not id: - item=sqlite("terminal").where("host","127.0.0.1").field("id").find() - if not item: - return "请先配置终端" - else: - id=item['id'] - authkey=md5(randoms()) - set_cache("websocket",authkey,10) - set_cache(str(G.userinfo['id']),G.userinfo,10) - return response.tpl(WebSocketaddress="ws://"+request.HEADER.HTTP_HOST()+":39020?authkey="+authkey+"&id="+id+"&uid="+str(G.userinfo['id'])) -def terminallist(): - "终端列表页面" - return response.tpl() -def shelllog(): - "命令日志页面" - return response.tpl() -def deleteshelllog(): - "删除令日志" - try: - id=request.get_json() - sqlite("shelllog").where('id','in',id).delete() - except: - return errorjson(msg="失败") - else: - return successjson() -def getshelllog(id=0): - "获命令日志列表" - if id: - return successjson(sqlite("shelllog").field('id,uid,icon,name,host,port,username,cmd,addtime').find(id)) - where=None - kw=request.args.get('kw') - pagenow=request.args.get('pagenow') - pagesize=request.args.get('pagesize') - if kw: - where=[("uid","like","%"+str(kw)+"%"),'or',("name","like","%"+str(kw)+"%"),'or',("cmd","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] - if not pagenow: - pagenow=1 - else: - pagenow=int(pagenow) - if not pagesize: - pagesize=10 - else: - pagesize=int(pagesize) - lists=sqlite("shelllog").field("id,uid,icon,name,host,port,username,cmd,addtime").order("id desc").where(where).page(pagenow,pagesize).select() - count=sqlite("shelllog").where(where).count() - data=return_list(lists,count,pagenow,pagesize) - return successjson(data) -def getterminalpwd(id=0,tab='terminal'): - "获取终端密码" - if id: - return successjson(sqlite(tab).field('password').find(id)) - else: - return errorjson(msg="id不能为空") -def getterminallist(id=0): - "获取终端列表" - if id: - return successjson(sqlite("terminal").field('id,icon,title,host,port,types,username,blacklist,whitelist,addtime,updtime').find(id)) - where=None - kw=request.args.get('kw') - pagenow=request.args.get('pagenow') - pagesize=request.args.get('pagesize') - if kw: - where=[("title","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] - if not pagenow: - pagenow=1 - else: - pagenow=int(pagenow) - if not pagesize: - pagesize=10 - else: - pagesize=int(pagesize) - lists=sqlite("terminal").field("id,title,icon,host,port,types,username,addtime,blacklist,whitelist,updtime").where(where).page(pagenow,pagesize).select() - count=sqlite("terminal").where(where).count() - data=return_list(lists,count,pagenow,pagesize) - return successjson(data) -def addtermina(): - "添加终端" - data=request.get_json() - data['addtime']=times() - data['updtime']=times() - if sqlite("terminal").where("host",data['host']).count(): - return errorjson(msg="服务器"+data['host']+"已在列表中,请务重复添加") - if data['host'] and data['port'] and data['username'] and len(data['password'])>5: - try: - trans = paramiko.Transport((data['host'],int(data['port']))) - trans.start_client() - trans.auth_password(username=data['username'], password=data['password']) - channel = trans.open_session() - channel.settimeout(7200) - channel.get_pty() - channel.invoke_shell() - except: - return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") - else: - trans.close() - channel.close() - sqlite("terminal").insert(data) - else: - return errorjson(msg="配置信息格式错误") - return successjson() -def delete(): - "删除终端" - try: - id=request.get_json() - sqlite("terminal").where('id','in',id).delete() - except: - return errorjson(msg="失败") - else: - return successjson() -def update(id=0): - "修改终端配置" - data=request.get_json() - if not id: - id=data['id'] - try: - data['updtime']=times() - except:pass - else: - t=sqlite("terminal").where("id",id).find() - if len(data['password'])>5 and (t['host']!=data['host'] or t['port']!=data['port'] or t['username']!=data['username'] or t['password']!=data['password']): - try: - trans = paramiko.Transport((data['host'],int(data['port']))) - trans.start_client() - trans.auth_password(username=data['username'], password=data['password']) - channel = trans.open_session() - channel.settimeout(7200) - channel.get_pty() - channel.invoke_shell() - except: - return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") - else: - trans.close() - channel.close() - sqlite("terminal").where("id",id).update(data) - else: - del data['password'] - sqlite("terminal").where("id",id).update(data) - return successjson() \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shell.html b/app/intapp/controller/terminal/tpl/socket/shell.html deleted file mode 100644 index 2ee8933..0000000 --- a/app/intapp/controller/terminal/tpl/socket/shell.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - -kcwebplus - - - - - - - - - - - - - - - - - -
-
-
- - - - \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shelllog.html b/app/intapp/controller/terminal/tpl/socket/shelllog.html deleted file mode 100644 index c0f69e0..0000000 --- a/app/intapp/controller/terminal/tpl/socket/shelllog.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - -kcwebplus - - - - - - - - - - - - - - - - - - - -
-
-    - - - 搜索 - - 终端管理 -
-
- - - - - - - - - - - - - - - - - - - -
-    删除选中  - - -
-
-
- - - diff --git a/app/intapp/controller/terminal/tpl/socket/terminallist.html b/app/intapp/controller/terminal/tpl/socket/terminallist.html deleted file mode 100644 index dce0a22..0000000 --- a/app/intapp/controller/terminal/tpl/socket/terminallist.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - -kcwebplus - - - - - - - - - - - - - - - - - - - -
-
-    - - - 搜索 - 添加服务器 - - 命令日志 -
-
- - - - - - - - - - - - - - - - - - - - - -
-    删除选中  - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 优先级大于命令黑名单,不填写表示不启用,否则在终端完整匹配该命令才能被执行 - - - - 优先级小于命令白名单,不填写表示不启用,否则在终端输入的命令只要包含该命令将会被阻止 - - - - 取 消 - 修改 - 添加 - - -
- - - -- Gitee From b805da5083510e764ee78c8bc9917f105922c88e Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 24 Aug 2020 13:11:43 +0800 Subject: [PATCH 3/4] kun --- app/intapp/controller/terminal/__init__.py | 2 + .../controller/terminal/common/__init__.py | 2 + .../controller/terminal/common/autoload.py | 10 + .../terminal/common/file/sqlite/.gitignore | 1 + .../controller/terminal/common/model.py | 64 +++ app/intapp/controller/terminal/index.py | 12 + app/intapp/controller/terminal/install.txt | 1 + app/intapp/controller/terminal/role.txt | 11 + app/intapp/controller/terminal/socket.py | 376 ++++++++++++++++++ .../controller/terminal/tpl/socket/shell.html | 145 +++++++ .../terminal/tpl/socket/shelllog.html | 154 +++++++ .../terminal/tpl/socket/terminallist.html | 231 +++++++++++ 12 files changed, 1009 insertions(+) create mode 100644 app/intapp/controller/terminal/__init__.py create mode 100644 app/intapp/controller/terminal/common/__init__.py create mode 100644 app/intapp/controller/terminal/common/autoload.py create mode 100644 app/intapp/controller/terminal/common/file/sqlite/.gitignore create mode 100644 app/intapp/controller/terminal/common/model.py create mode 100644 app/intapp/controller/terminal/index.py create mode 100644 app/intapp/controller/terminal/install.txt create mode 100644 app/intapp/controller/terminal/role.txt create mode 100644 app/intapp/controller/terminal/socket.py create mode 100644 app/intapp/controller/terminal/tpl/socket/shell.html create mode 100644 app/intapp/controller/terminal/tpl/socket/shelllog.html create mode 100644 app/intapp/controller/terminal/tpl/socket/terminallist.html diff --git a/app/intapp/controller/terminal/__init__.py b/app/intapp/controller/terminal/__init__.py new file mode 100644 index 0000000..9470ed6 --- /dev/null +++ b/app/intapp/controller/terminal/__init__.py @@ -0,0 +1,2 @@ +from . import index +from . import socket \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/__init__.py b/app/intapp/controller/terminal/common/__init__.py new file mode 100644 index 0000000..60767ac --- /dev/null +++ b/app/intapp/controller/terminal/common/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from .model import * \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/autoload.py b/app/intapp/controller/terminal/common/autoload.py new file mode 100644 index 0000000..c4bee80 --- /dev/null +++ b/app/intapp/controller/terminal/common/autoload.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from app.intapp.common import * +import subprocess +def get_process_id(name): + try: + child = subprocess.Popen(['pgrep', '-f', name],stdout=subprocess.PIPE, shell=False) + response = child.communicate()[0] + return [int(pid) for pid in response.split()] + except: + return [] diff --git a/app/intapp/controller/terminal/common/file/sqlite/.gitignore b/app/intapp/controller/terminal/common/file/sqlite/.gitignore new file mode 100644 index 0000000..5a8b5eb --- /dev/null +++ b/app/intapp/controller/terminal/common/file/sqlite/.gitignore @@ -0,0 +1 @@ +terminal \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/model.py b/app/intapp/controller/terminal/common/model.py new file mode 100644 index 0000000..bd65798 --- /dev/null +++ b/app/intapp/controller/terminal/common/model.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +from .autoload import * +# 可以在这里初始化数据库 +model_intapp_terminal_path=os.path.split(os.path.realpath(__file__))[0]+"/file/sqlite/terminal" #数据存放目录 +class modelsqliteintapp(model.model): + config={'type':'sqlite'} + config={'type':'sqlite','db':model_intapp_terminal_path} + model.dbtype.conf=config +class model_intapp_terminal(modelsqliteintapp): + "终端列表" + table="terminal" + fields={ + "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 + "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), + "title":model.dbtype.varchar(LEN=128,DEFAULT=''), + "host":model.dbtype.varchar(LEN=32,DEFAULT=''), + "port":model.dbtype.varchar(LEN=32,DEFAULT=''), + "username":model.dbtype.varchar(LEN=32,DEFAULT=''), + "password":model.dbtype.varchar(LEN=32,DEFAULT=''), + "blacklist":model.dbtype.text(), #命令黑名单 + "whitelist":model.dbtype.text(), #命令白名单 + "types":model.dbtype.varchar(LEN=32,DEFAULT='共享连接'), #连接方式 + "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 + "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 + } +try: + sqlite('terminal',model_intapp_terminal_path).find() +except: + model_intapp_terminal=model_intapp_terminal() + model_intapp_terminal.create_table() +class model_intapp_shelllog(modelsqliteintapp): + "终端操作日志" + table="shelllog" + fields={ + "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 + "uid":model.dbtype.int(LEN=11), + "icon":model.dbtype.varchar(LEN=256,DEFAULT=''), #头像地址 + "name":model.dbtype.varchar(LEN=64,DEFAULT=''), + "host":model.dbtype.varchar(LEN=32,DEFAULT=''), + "port":model.dbtype.varchar(LEN=32,DEFAULT=''), + "username":model.dbtype.varchar(LEN=32,DEFAULT=''), + "password":model.dbtype.varchar(LEN=32,DEFAULT=''), + "cmd":model.dbtype.varchar(LEN=2000,DEFAULT=''), #命令 + "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 + } +try: + sqlite('shelllog',model_intapp_terminal_path).find() +except: + model_intapp_shelllog=model_intapp_shelllog() + model_intapp_shelllog.create_table() +def sqlite(table=None,configss=model_intapp_terminal_path): + """sqlite数据库操作实例 + + 参数 table:表名 + + 参数 configss 数据库配置 可以传数据库名字符串 + """ + dbs=kcwsqlite.sqlite() + if table is None: + return dbs + elif configss: + return dbs.connect(configss).table(table) + else: + return dbs.connect(config.sqlite).table(table) \ No newline at end of file diff --git a/app/intapp/controller/terminal/index.py b/app/intapp/controller/terminal/index.py new file mode 100644 index 0000000..419f449 --- /dev/null +++ b/app/intapp/controller/terminal/index.py @@ -0,0 +1,12 @@ +from .common import * +def index(): + if 'Linux' in get_sysinfo()['platform']: + if not os.path.isfile("/usr/bin/python3.6terminal"): + os.system("ln -s /usr/local/python/python3.6/bin/python3 /usr/bin/python3.6terminal") + if not get_process_id('python3.6terminal'): + cmd="nohup python3.6terminal server.py intapp/terminal/socket/start --cli > server.log 2>&1 &" + os.system(cmd) + elif 'Windows' in get_sysinfo()['platform']: + cmd="start /b python server.py intapp/terminal/socket/start --cli" + os.system(cmd) + return response.redirect("/intapp/terminal/socket/terminallist") diff --git a/app/intapp/controller/terminal/install.txt b/app/intapp/controller/terminal/install.txt new file mode 100644 index 0000000..79c3562 --- /dev/null +++ b/app/intapp/controller/terminal/install.txt @@ -0,0 +1 @@ +paramiko==2.7.1 \ No newline at end of file diff --git a/app/intapp/controller/terminal/role.txt b/app/intapp/controller/terminal/role.txt new file mode 100644 index 0000000..9f9dd10 --- /dev/null +++ b/app/intapp/controller/terminal/role.txt @@ -0,0 +1,11 @@ +终端列表重定向,/intapp/terminal/index/index +命令行页面,/intapp/terminal/socket/shell +终端列表页面,/intapp/terminal/socket/terminallist +命令日志页面,/intapp/terminal/socket/shelllog +删除令日志,/intapp/terminal/socket/deleteshelllog +获命令日志列表,/intapp/terminal/socket/getshelllog +获取终端列表,/intapp/terminal/socket/getterminallist +添加终端,/intapp/terminal/socket/addtermina +删除终端,/intapp/terminal/socket/delete +修改终端配置,/intapp/terminal/socket/update +查看ssh密码,/intapp/terminal/socket/getterminalpwd diff --git a/app/intapp/controller/terminal/socket.py b/app/intapp/controller/terminal/socket.py new file mode 100644 index 0000000..0ca49a1 --- /dev/null +++ b/app/intapp/controller/terminal/socket.py @@ -0,0 +1,376 @@ +from .common import * +import paramiko +from urllib import parse +class sockets(kcwebsocket): + trans = {} + channel = {} + terminal={} + cmdstr="" + def __successjson(self,data=[],code=0,msg="成功"): + res={ + "code":code, + "msg":msg, + "time":int(times()), + "data":data + } + return json_encode(res) + def __errorjson(self,data=[],code=1,msg="失败",status='400 error'): + return self.__successjson(data=data,code=code,msg=msg) + def __setterminal(self,clientid,id,userinfo): + "设置终端信息" + try: + self.terminal[clientid] + except: + self.terminal[clientid]=sqlite("terminal").where("id",id).find() + self.terminal[clientid]['id']=id + self.terminal[clientid]['userinfo']=userinfo + if self.terminal[clientid]['blacklist']: #命令黑名单 + self.terminal[clientid]['blacklist']=self.terminal[clientid]['blacklist'].split(",") + else: + self.terminal[clientid]['blacklist']=[] + if self.terminal[clientid]['whitelist']: #命令白名单 + self.terminal[clientid]['whitelist']=self.terminal[clientid]['whitelist'].split(",") + else: + self.terminal[clientid]['whitelist']=[] + async def onConnect(self,clientid,params): + "#当客户端发来连接时触发的回调函数" + try: + uid=params['uid'] + userinfo=get_cache(uid) + if not userinfo: + await self.send_client(clientid,self.__errorjson(msg="您尚未登录")) + return False + del_cache(uid) + authkey=get_cache("websocket") + del_cache("websocket") + id=str(params['id']) + self.__setterminal(clientid,id,userinfo) + if params['authkey']!=authkey: + await self.send_client(clientid,self.__successjson(msg="认证失败")) + return False + else: + if self.terminal[clientid]['types']=='共享连接': + await self.joinGroup(clientid,"Group"+id) #加入组 + try: + self.trans[id] + self.channel[id] + except Exception as e: + self.trans[id] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) + self.trans[id].start_client() + self.trans[id].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) + self.channel[id] = self.trans[id].open_session()# 打开一个通道 + self.channel[id].settimeout(7200) + self.channel[id].get_pty()# 获取一个终端 + self.channel[id].invoke_shell()# 激活器 + self.channel[id].setblocking(False) + while True: + await asyncio.sleep(0.002) + try: + rst = self.channel[id].recv(1024) + except:pass + else: + rst = rst.decode('utf8') + if rst: + resdata=rst.split("\n") + if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 + if(self.cmdstr): + self.cmdstr = self.cmdstr[:-1] + elif '\b' in rst: #多个删除符 + cmdstr=rst.split("\b") + for k in cmdstr: + if not k: + self.cmdstr = self.cmdstr[:-1] + for k in cmdstr: + if k: + self.cmdstr+=k + elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: + self.cmdstr+=rst + try: + await self.sendToGroup("Group"+id,self.__successjson(rst)) + except: + await self.sendToGroup("Group"+id,self.__errorjson("获取执行结果失败")) + else: + await self.send_client(clientid,self.__successjson("连接成功\n当前使用的ssh服务是一个共享连接\n你发送的命令会被该组的所有人看到\n["+self.terminal[clientid]['username']+"@"+self.terminal[clientid]['host']+":"+self.terminal[clientid]['port']+" ]# ")) + else: #独立连接(为每个客户端分配一个连接) + self.trans[id+clientid] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) + self.trans[id+clientid].start_client() + self.trans[id+clientid].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) + self.channel[id+clientid] = self.trans[id+clientid].open_session()# 打开一个通道 + self.channel[id+clientid].settimeout(7200) + self.channel[id+clientid].get_pty()# 获取一个终端 + self.channel[id+clientid].invoke_shell()# 激活器 + self.channel[id+clientid].setblocking(False) + while True: + await asyncio.sleep(0.002) + try: + rst = self.channel[id+clientid].recv(1024) + except:pass + else: + rst = rst.decode('utf8') + if rst: + resdata=rst.split("\n") + if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 + if(self.cmdstr): + self.cmdstr = self.cmdstr[:-1] + elif '\b' in rst: #多个删除符 + cmdstr=rst.split("\b") + for k in cmdstr: + if not k: + self.cmdstr = self.cmdstr[:-1] + for k in cmdstr: + if k: + self.cmdstr+=k + elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: + self.cmdstr+=rst + try: + await self.send_client(clientid,self.__successjson(rst)) + except: + await self.send_client(clientid,self.__errorjson("获取执行结果失败")) + await self.send_client(clientid,self.__successjson("连接成功")) + return True + except Exception as e: + if config.app['app_debug']: + print("连接失败error",clientid,traceback.format_exc()) + await self.send_client(clientid,self.__errorjson(msg="认证失败error"+str(e))) + return False + async def onMessage(self,clientid,recv_text): + "当客户端发来数据时触发的回调函数" + await asyncio.sleep(0.001) + id=self.terminal[clientid]['id'] + try: + data=json_decode(recv_text) + except: + await self.send_client(clientid,self.__errorjson(msg="必须是标准json字符串格式")) + else: + try: + types=data['types'] + except: + await self.send_client(clientid,self.__errorjson(msg="消息格式错误,缺少types")) + else: + if types=='cmd': + cmd=parse.unquote(data['cmd']) + # try: + # self.cmdstr=parse.unquote(data['cmdstr']) + # except KeyError: + # self.cmdstr='' + zxstatus=False + errmsg='' + # if '\u001b[A'==cmd or '\u001b[B'==cmd: #禁止方向键上下 + # zxstatus=False + # errmsg="方向键上和方向键下被禁止" + # else: + # zxstatus=True + if '\u001b[D'==cmd or '\u001b[C'==cmd: #禁止方向键左右 + errmsg="方向键左和方向键右被禁止" + else: + if self.cmdstr: + if len(self.cmdstr) > 2000: + errmsg="该命令不允许执行,因为您的命令字符超过2000" + elif self.terminal[clientid]['whitelist']: #命令白名单 + for k in self.terminal[clientid]['whitelist']: + if k == self.cmdstr: + zxstatus=True + errmsg="该命令不允许执行,因为您的命令不在白名单中" + elif self.terminal[clientid]['blacklist']: #命令黑名单 + zxstatus=True + for k in self.terminal[clientid]['blacklist']: + if k in self.cmdstr: + zxstatus=False + errmsg="该命令不允许执行,因为您的命令出现了被禁用的命令‘"+str(k)+"’" + break + else: + zxstatus=True + if zxstatus: + if self.terminal[clientid]['types']=='共享连接': + if ('\n' in cmd or '\r' in cmd) and self.cmdstr: + try: + sqlite("shelllog").insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) + except: + print("该命令未被执行,因为无法记录日志",traceback.format_exc()) + self.channel[id].send("\n") + await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) + else: + self.channel[id].send(cmd) + self.cmdstr='' + else: + self.channel[id].send(cmd) + # await self.send_client(clientid,self.__errorjson(cmd,msg="你的命令是")) + else: #独立连接 + if ('\n' in cmd or '\r' in cmd) and self.cmdstr: + try: + sqlite("shelllog").insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) + except: + print("该命令未被执行,因为无法记录日志",traceback.format_exc()) + self.channel[id].send("\n") + await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) + else: + self.channel[id+clientid].send(cmd) + self.cmdstr='' + else: + self.channel[id+clientid].send(cmd) + else: + if self.terminal[clientid]['types']=='共享连接': + self.channel[id].send("\b") + else:#独立连接 + self.channel[id+clientid].send("\b") + await self.send_client(clientid,self.__errorjson(msg=errmsg)) + else: + await self.send_client(clientid,self.__errorjson(msg="暂不支持types为"+str(types)+"的消息")) + async def onClose(self,clientid): + "客户端与服务端连接断开时触发的回调函数" + id=self.terminal[clientid]['id'] + if self.terminal[clientid]['types']=='共享连接': + pass + else:#独立连接 + self.channel[id+clientid].close() + self.trans[id+clientid].close() + del self.channel[id+clientid] + del self.trans[id+clientid] + await self.sendToGroup("Group"+id,clientid+",已退出") #给当前组户发送消息 + print("onClose",clientid) +def start(): + if config.app['cli']: #cli模式下运行 + socket=sockets() + socket.start(ip='0.0.0.0',port='39020') + +def shell(id=''): + "命令行页面" + id=str(id) + if not id: + item=sqlite("terminal").where("host","127.0.0.1").field("id").find() + if not item: + return "请先配置终端" + else: + id=item['id'] + authkey=md5(randoms()) + set_cache("websocket",authkey,10) + set_cache(str(G.userinfo['id']),G.userinfo,10) + return response.tpl(WebSocketaddress="ws://"+request.HEADER.HTTP_HOST()+":39020?authkey="+authkey+"&id="+id+"&uid="+str(G.userinfo['id'])) +def terminallist(): + "终端列表页面" + return response.tpl() +def shelllog(): + "命令日志页面" + return response.tpl() +def deleteshelllog(): + "删除令日志" + try: + id=request.get_json() + sqlite("shelllog").where('id','in',id).delete() + except: + return errorjson(msg="失败") + else: + return successjson() +def getshelllog(id=0): + "获命令日志列表" + if id: + return successjson(sqlite("shelllog").field('id,uid,icon,name,host,port,username,cmd,addtime').find(id)) + where=None + kw=request.args.get('kw') + pagenow=request.args.get('pagenow') + pagesize=request.args.get('pagesize') + if kw: + where=[("uid","like","%"+str(kw)+"%"),'or',("name","like","%"+str(kw)+"%"),'or',("cmd","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] + if not pagenow: + pagenow=1 + else: + pagenow=int(pagenow) + if not pagesize: + pagesize=10 + else: + pagesize=int(pagesize) + lists=sqlite("shelllog").field("id,uid,icon,name,host,port,username,cmd,addtime").order("id desc").where(where).page(pagenow,pagesize).select() + count=sqlite("shelllog").where(where).count() + data=return_list(lists,count,pagenow,pagesize) + return successjson(data) +def getterminalpwd(id=0,tab='terminal'): + "获取终端密码" + if id: + return successjson(sqlite(tab).field('password').find(id)) + else: + return errorjson(msg="id不能为空") +def getterminallist(id=0): + "获取终端列表" + if id: + return successjson(sqlite("terminal").field('id,icon,title,host,port,types,username,blacklist,whitelist,addtime,updtime').find(id)) + where=None + kw=request.args.get('kw') + pagenow=request.args.get('pagenow') + pagesize=request.args.get('pagesize') + if kw: + where=[("title","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] + if not pagenow: + pagenow=1 + else: + pagenow=int(pagenow) + if not pagesize: + pagesize=10 + else: + pagesize=int(pagesize) + lists=sqlite("terminal").field("id,title,icon,host,port,types,username,addtime,blacklist,whitelist,updtime").where(where).page(pagenow,pagesize).select() + count=sqlite("terminal").where(where).count() + data=return_list(lists,count,pagenow,pagesize) + return successjson(data) +def addtermina(): + "添加终端" + data=request.get_json() + data['addtime']=times() + data['updtime']=times() + if sqlite("terminal").where("host",data['host']).count(): + return errorjson(msg="服务器"+data['host']+"已在列表中,请务重复添加") + if data['host'] and data['port'] and data['username'] and len(data['password'])>5: + try: + trans = paramiko.Transport((data['host'],int(data['port']))) + trans.start_client() + trans.auth_password(username=data['username'], password=data['password']) + channel = trans.open_session() + channel.settimeout(7200) + channel.get_pty() + channel.invoke_shell() + except: + return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") + else: + trans.close() + channel.close() + sqlite("terminal").insert(data) + else: + return errorjson(msg="配置信息格式错误") + return successjson() +def delete(): + "删除终端" + try: + id=request.get_json() + sqlite("terminal").where('id','in',id).delete() + except: + return errorjson(msg="失败") + else: + return successjson() +def update(id=0): + "修改终端配置" + data=request.get_json() + if not id: + id=data['id'] + try: + data['updtime']=times() + except:pass + else: + t=sqlite("terminal").where("id",id).find() + if len(data['password'])>5 and (t['host']!=data['host'] or t['port']!=data['port'] or t['username']!=data['username'] or t['password']!=data['password']): + try: + trans = paramiko.Transport((data['host'],int(data['port']))) + trans.start_client() + trans.auth_password(username=data['username'], password=data['password']) + channel = trans.open_session() + channel.settimeout(7200) + channel.get_pty() + channel.invoke_shell() + except: + return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") + else: + trans.close() + channel.close() + sqlite("terminal").where("id",id).update(data) + else: + del data['password'] + sqlite("terminal").where("id",id).update(data) + return successjson() \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shell.html b/app/intapp/controller/terminal/tpl/socket/shell.html new file mode 100644 index 0000000..2ee8933 --- /dev/null +++ b/app/intapp/controller/terminal/tpl/socket/shell.html @@ -0,0 +1,145 @@ + + + + + +kcwebplus + + + + + + + + + + + + + + + + + +
+
+
+ + + + \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shelllog.html b/app/intapp/controller/terminal/tpl/socket/shelllog.html new file mode 100644 index 0000000..c0f69e0 --- /dev/null +++ b/app/intapp/controller/terminal/tpl/socket/shelllog.html @@ -0,0 +1,154 @@ + + + + +kcwebplus + + + + + + + + + + + + + + + + + + + +
+
+    + + + 搜索 + + 终端管理 +
+
+ + + + + + + + + + + + + + + + + + + +
+    删除选中  + + +
+
+
+ + + diff --git a/app/intapp/controller/terminal/tpl/socket/terminallist.html b/app/intapp/controller/terminal/tpl/socket/terminallist.html new file mode 100644 index 0000000..dce0a22 --- /dev/null +++ b/app/intapp/controller/terminal/tpl/socket/terminallist.html @@ -0,0 +1,231 @@ + + + + +kcwebplus + + + + + + + + + + + + + + + + + + + +
+
+    + + + 搜索 + 添加服务器 + + 命令日志 +
+
+ + + + + + + + + + + + + + + + + + + + + +
+    删除选中  + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 优先级大于命令黑名单,不填写表示不启用,否则在终端完整匹配该命令才能被执行 + + + + 优先级小于命令白名单,不填写表示不启用,否则在终端输入的命令只要包含该命令将会被阻止 + + + + 取 消 + 修改 + 添加 + + +
+ + + -- Gitee From 64d9c1d21da0bf8e0561ac0730ab9404d0e7030f Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 24 Aug 2020 13:12:01 +0800 Subject: [PATCH 4/4] kun --- app/intapp/controller/terminal/__init__.py | 2 - .../controller/terminal/common/__init__.py | 2 - .../controller/terminal/common/autoload.py | 10 - .../terminal/common/file/sqlite/.gitignore | 1 - .../controller/terminal/common/model.py | 64 --- app/intapp/controller/terminal/index.py | 12 - app/intapp/controller/terminal/install.txt | 1 - app/intapp/controller/terminal/role.txt | 11 - app/intapp/controller/terminal/socket.py | 376 ------------------ .../controller/terminal/tpl/socket/shell.html | 145 ------- .../terminal/tpl/socket/shelllog.html | 154 ------- .../terminal/tpl/socket/terminallist.html | 231 ----------- 12 files changed, 1009 deletions(-) delete mode 100644 app/intapp/controller/terminal/__init__.py delete mode 100644 app/intapp/controller/terminal/common/__init__.py delete mode 100644 app/intapp/controller/terminal/common/autoload.py delete mode 100644 app/intapp/controller/terminal/common/file/sqlite/.gitignore delete mode 100644 app/intapp/controller/terminal/common/model.py delete mode 100644 app/intapp/controller/terminal/index.py delete mode 100644 app/intapp/controller/terminal/install.txt delete mode 100644 app/intapp/controller/terminal/role.txt delete mode 100644 app/intapp/controller/terminal/socket.py delete mode 100644 app/intapp/controller/terminal/tpl/socket/shell.html delete mode 100644 app/intapp/controller/terminal/tpl/socket/shelllog.html delete mode 100644 app/intapp/controller/terminal/tpl/socket/terminallist.html diff --git a/app/intapp/controller/terminal/__init__.py b/app/intapp/controller/terminal/__init__.py deleted file mode 100644 index 9470ed6..0000000 --- a/app/intapp/controller/terminal/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import index -from . import socket \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/__init__.py b/app/intapp/controller/terminal/common/__init__.py deleted file mode 100644 index 60767ac..0000000 --- a/app/intapp/controller/terminal/common/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -from .model import * \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/autoload.py b/app/intapp/controller/terminal/common/autoload.py deleted file mode 100644 index c4bee80..0000000 --- a/app/intapp/controller/terminal/common/autoload.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -from app.intapp.common import * -import subprocess -def get_process_id(name): - try: - child = subprocess.Popen(['pgrep', '-f', name],stdout=subprocess.PIPE, shell=False) - response = child.communicate()[0] - return [int(pid) for pid in response.split()] - except: - return [] diff --git a/app/intapp/controller/terminal/common/file/sqlite/.gitignore b/app/intapp/controller/terminal/common/file/sqlite/.gitignore deleted file mode 100644 index 5a8b5eb..0000000 --- a/app/intapp/controller/terminal/common/file/sqlite/.gitignore +++ /dev/null @@ -1 +0,0 @@ -terminal \ No newline at end of file diff --git a/app/intapp/controller/terminal/common/model.py b/app/intapp/controller/terminal/common/model.py deleted file mode 100644 index bd65798..0000000 --- a/app/intapp/controller/terminal/common/model.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -from .autoload import * -# 可以在这里初始化数据库 -model_intapp_terminal_path=os.path.split(os.path.realpath(__file__))[0]+"/file/sqlite/terminal" #数据存放目录 -class modelsqliteintapp(model.model): - config={'type':'sqlite'} - config={'type':'sqlite','db':model_intapp_terminal_path} - model.dbtype.conf=config -class model_intapp_terminal(modelsqliteintapp): - "终端列表" - table="terminal" - fields={ - "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 - "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), - "title":model.dbtype.varchar(LEN=128,DEFAULT=''), - "host":model.dbtype.varchar(LEN=32,DEFAULT=''), - "port":model.dbtype.varchar(LEN=32,DEFAULT=''), - "username":model.dbtype.varchar(LEN=32,DEFAULT=''), - "password":model.dbtype.varchar(LEN=32,DEFAULT=''), - "blacklist":model.dbtype.text(), #命令黑名单 - "whitelist":model.dbtype.text(), #命令白名单 - "types":model.dbtype.varchar(LEN=32,DEFAULT='共享连接'), #连接方式 - "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 - "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 - } -try: - sqlite('terminal',model_intapp_terminal_path).find() -except: - model_intapp_terminal=model_intapp_terminal() - model_intapp_terminal.create_table() -class model_intapp_shelllog(modelsqliteintapp): - "终端操作日志" - table="shelllog" - fields={ - "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 - "uid":model.dbtype.int(LEN=11), - "icon":model.dbtype.varchar(LEN=256,DEFAULT=''), #头像地址 - "name":model.dbtype.varchar(LEN=64,DEFAULT=''), - "host":model.dbtype.varchar(LEN=32,DEFAULT=''), - "port":model.dbtype.varchar(LEN=32,DEFAULT=''), - "username":model.dbtype.varchar(LEN=32,DEFAULT=''), - "password":model.dbtype.varchar(LEN=32,DEFAULT=''), - "cmd":model.dbtype.varchar(LEN=2000,DEFAULT=''), #命令 - "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 - } -try: - sqlite('shelllog',model_intapp_terminal_path).find() -except: - model_intapp_shelllog=model_intapp_shelllog() - model_intapp_shelllog.create_table() -def sqlite(table=None,configss=model_intapp_terminal_path): - """sqlite数据库操作实例 - - 参数 table:表名 - - 参数 configss 数据库配置 可以传数据库名字符串 - """ - dbs=kcwsqlite.sqlite() - if table is None: - return dbs - elif configss: - return dbs.connect(configss).table(table) - else: - return dbs.connect(config.sqlite).table(table) \ No newline at end of file diff --git a/app/intapp/controller/terminal/index.py b/app/intapp/controller/terminal/index.py deleted file mode 100644 index 419f449..0000000 --- a/app/intapp/controller/terminal/index.py +++ /dev/null @@ -1,12 +0,0 @@ -from .common import * -def index(): - if 'Linux' in get_sysinfo()['platform']: - if not os.path.isfile("/usr/bin/python3.6terminal"): - os.system("ln -s /usr/local/python/python3.6/bin/python3 /usr/bin/python3.6terminal") - if not get_process_id('python3.6terminal'): - cmd="nohup python3.6terminal server.py intapp/terminal/socket/start --cli > server.log 2>&1 &" - os.system(cmd) - elif 'Windows' in get_sysinfo()['platform']: - cmd="start /b python server.py intapp/terminal/socket/start --cli" - os.system(cmd) - return response.redirect("/intapp/terminal/socket/terminallist") diff --git a/app/intapp/controller/terminal/install.txt b/app/intapp/controller/terminal/install.txt deleted file mode 100644 index 79c3562..0000000 --- a/app/intapp/controller/terminal/install.txt +++ /dev/null @@ -1 +0,0 @@ -paramiko==2.7.1 \ No newline at end of file diff --git a/app/intapp/controller/terminal/role.txt b/app/intapp/controller/terminal/role.txt deleted file mode 100644 index 9f9dd10..0000000 --- a/app/intapp/controller/terminal/role.txt +++ /dev/null @@ -1,11 +0,0 @@ -终端列表重定向,/intapp/terminal/index/index -命令行页面,/intapp/terminal/socket/shell -终端列表页面,/intapp/terminal/socket/terminallist -命令日志页面,/intapp/terminal/socket/shelllog -删除令日志,/intapp/terminal/socket/deleteshelllog -获命令日志列表,/intapp/terminal/socket/getshelllog -获取终端列表,/intapp/terminal/socket/getterminallist -添加终端,/intapp/terminal/socket/addtermina -删除终端,/intapp/terminal/socket/delete -修改终端配置,/intapp/terminal/socket/update -查看ssh密码,/intapp/terminal/socket/getterminalpwd diff --git a/app/intapp/controller/terminal/socket.py b/app/intapp/controller/terminal/socket.py deleted file mode 100644 index 0ca49a1..0000000 --- a/app/intapp/controller/terminal/socket.py +++ /dev/null @@ -1,376 +0,0 @@ -from .common import * -import paramiko -from urllib import parse -class sockets(kcwebsocket): - trans = {} - channel = {} - terminal={} - cmdstr="" - def __successjson(self,data=[],code=0,msg="成功"): - res={ - "code":code, - "msg":msg, - "time":int(times()), - "data":data - } - return json_encode(res) - def __errorjson(self,data=[],code=1,msg="失败",status='400 error'): - return self.__successjson(data=data,code=code,msg=msg) - def __setterminal(self,clientid,id,userinfo): - "设置终端信息" - try: - self.terminal[clientid] - except: - self.terminal[clientid]=sqlite("terminal").where("id",id).find() - self.terminal[clientid]['id']=id - self.terminal[clientid]['userinfo']=userinfo - if self.terminal[clientid]['blacklist']: #命令黑名单 - self.terminal[clientid]['blacklist']=self.terminal[clientid]['blacklist'].split(",") - else: - self.terminal[clientid]['blacklist']=[] - if self.terminal[clientid]['whitelist']: #命令白名单 - self.terminal[clientid]['whitelist']=self.terminal[clientid]['whitelist'].split(",") - else: - self.terminal[clientid]['whitelist']=[] - async def onConnect(self,clientid,params): - "#当客户端发来连接时触发的回调函数" - try: - uid=params['uid'] - userinfo=get_cache(uid) - if not userinfo: - await self.send_client(clientid,self.__errorjson(msg="您尚未登录")) - return False - del_cache(uid) - authkey=get_cache("websocket") - del_cache("websocket") - id=str(params['id']) - self.__setterminal(clientid,id,userinfo) - if params['authkey']!=authkey: - await self.send_client(clientid,self.__successjson(msg="认证失败")) - return False - else: - if self.terminal[clientid]['types']=='共享连接': - await self.joinGroup(clientid,"Group"+id) #加入组 - try: - self.trans[id] - self.channel[id] - except Exception as e: - self.trans[id] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) - self.trans[id].start_client() - self.trans[id].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) - self.channel[id] = self.trans[id].open_session()# 打开一个通道 - self.channel[id].settimeout(7200) - self.channel[id].get_pty()# 获取一个终端 - self.channel[id].invoke_shell()# 激活器 - self.channel[id].setblocking(False) - while True: - await asyncio.sleep(0.002) - try: - rst = self.channel[id].recv(1024) - except:pass - else: - rst = rst.decode('utf8') - if rst: - resdata=rst.split("\n") - if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 - if(self.cmdstr): - self.cmdstr = self.cmdstr[:-1] - elif '\b' in rst: #多个删除符 - cmdstr=rst.split("\b") - for k in cmdstr: - if not k: - self.cmdstr = self.cmdstr[:-1] - for k in cmdstr: - if k: - self.cmdstr+=k - elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: - self.cmdstr+=rst - try: - await self.sendToGroup("Group"+id,self.__successjson(rst)) - except: - await self.sendToGroup("Group"+id,self.__errorjson("获取执行结果失败")) - else: - await self.send_client(clientid,self.__successjson("连接成功\n当前使用的ssh服务是一个共享连接\n你发送的命令会被该组的所有人看到\n["+self.terminal[clientid]['username']+"@"+self.terminal[clientid]['host']+":"+self.terminal[clientid]['port']+" ]# ")) - else: #独立连接(为每个客户端分配一个连接) - self.trans[id+clientid] = paramiko.Transport((self.terminal[clientid]['host'],int(self.terminal[clientid]['port']))) - self.trans[id+clientid].start_client() - self.trans[id+clientid].auth_password(username=self.terminal[clientid]['username'], password=self.terminal[clientid]['password']) - self.channel[id+clientid] = self.trans[id+clientid].open_session()# 打开一个通道 - self.channel[id+clientid].settimeout(7200) - self.channel[id+clientid].get_pty()# 获取一个终端 - self.channel[id+clientid].invoke_shell()# 激活器 - self.channel[id+clientid].setblocking(False) - while True: - await asyncio.sleep(0.002) - try: - rst = self.channel[id+clientid].recv(1024) - except:pass - else: - rst = rst.decode('utf8') - if rst: - resdata=rst.split("\n") - if '\u001b[K' in rst or '\b\u001b[K' == rst or "\b \b"==rst: #删除符 - if(self.cmdstr): - self.cmdstr = self.cmdstr[:-1] - elif '\b' in rst: #多个删除符 - cmdstr=rst.split("\b") - for k in cmdstr: - if not k: - self.cmdstr = self.cmdstr[:-1] - for k in cmdstr: - if k: - self.cmdstr+=k - elif len(resdata)==1 and self.cmdstr!=rst and "\n" not in rst and '\u0007'!=rst: - self.cmdstr+=rst - try: - await self.send_client(clientid,self.__successjson(rst)) - except: - await self.send_client(clientid,self.__errorjson("获取执行结果失败")) - await self.send_client(clientid,self.__successjson("连接成功")) - return True - except Exception as e: - if config.app['app_debug']: - print("连接失败error",clientid,traceback.format_exc()) - await self.send_client(clientid,self.__errorjson(msg="认证失败error"+str(e))) - return False - async def onMessage(self,clientid,recv_text): - "当客户端发来数据时触发的回调函数" - await asyncio.sleep(0.001) - id=self.terminal[clientid]['id'] - try: - data=json_decode(recv_text) - except: - await self.send_client(clientid,self.__errorjson(msg="必须是标准json字符串格式")) - else: - try: - types=data['types'] - except: - await self.send_client(clientid,self.__errorjson(msg="消息格式错误,缺少types")) - else: - if types=='cmd': - cmd=parse.unquote(data['cmd']) - # try: - # self.cmdstr=parse.unquote(data['cmdstr']) - # except KeyError: - # self.cmdstr='' - zxstatus=False - errmsg='' - # if '\u001b[A'==cmd or '\u001b[B'==cmd: #禁止方向键上下 - # zxstatus=False - # errmsg="方向键上和方向键下被禁止" - # else: - # zxstatus=True - if '\u001b[D'==cmd or '\u001b[C'==cmd: #禁止方向键左右 - errmsg="方向键左和方向键右被禁止" - else: - if self.cmdstr: - if len(self.cmdstr) > 2000: - errmsg="该命令不允许执行,因为您的命令字符超过2000" - elif self.terminal[clientid]['whitelist']: #命令白名单 - for k in self.terminal[clientid]['whitelist']: - if k == self.cmdstr: - zxstatus=True - errmsg="该命令不允许执行,因为您的命令不在白名单中" - elif self.terminal[clientid]['blacklist']: #命令黑名单 - zxstatus=True - for k in self.terminal[clientid]['blacklist']: - if k in self.cmdstr: - zxstatus=False - errmsg="该命令不允许执行,因为您的命令出现了被禁用的命令‘"+str(k)+"’" - break - else: - zxstatus=True - if zxstatus: - if self.terminal[clientid]['types']=='共享连接': - if ('\n' in cmd or '\r' in cmd) and self.cmdstr: - try: - sqlite("shelllog").insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) - except: - print("该命令未被执行,因为无法记录日志",traceback.format_exc()) - self.channel[id].send("\n") - await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) - else: - self.channel[id].send(cmd) - self.cmdstr='' - else: - self.channel[id].send(cmd) - # await self.send_client(clientid,self.__errorjson(cmd,msg="你的命令是")) - else: #独立连接 - if ('\n' in cmd or '\r' in cmd) and self.cmdstr: - try: - sqlite("shelllog").insert({"uid":self.terminal[clientid]['userinfo']['id'],"icon":self.terminal[clientid]['userinfo']['icon'],"name":self.terminal[clientid]['userinfo']['name'],"host":self.terminal[clientid]['host'],"port":str(self.terminal[clientid]['port']),"username":self.terminal[clientid]['username'],"password":self.terminal[clientid]['password'],"cmd":self.cmdstr,"addtime":times()}) - except: - print("该命令未被执行,因为无法记录日志",traceback.format_exc()) - self.channel[id].send("\n") - await self.send_client(clientid,self.__errorjson(msg="该命令未被执行,因为无法记录日志")) - else: - self.channel[id+clientid].send(cmd) - self.cmdstr='' - else: - self.channel[id+clientid].send(cmd) - else: - if self.terminal[clientid]['types']=='共享连接': - self.channel[id].send("\b") - else:#独立连接 - self.channel[id+clientid].send("\b") - await self.send_client(clientid,self.__errorjson(msg=errmsg)) - else: - await self.send_client(clientid,self.__errorjson(msg="暂不支持types为"+str(types)+"的消息")) - async def onClose(self,clientid): - "客户端与服务端连接断开时触发的回调函数" - id=self.terminal[clientid]['id'] - if self.terminal[clientid]['types']=='共享连接': - pass - else:#独立连接 - self.channel[id+clientid].close() - self.trans[id+clientid].close() - del self.channel[id+clientid] - del self.trans[id+clientid] - await self.sendToGroup("Group"+id,clientid+",已退出") #给当前组户发送消息 - print("onClose",clientid) -def start(): - if config.app['cli']: #cli模式下运行 - socket=sockets() - socket.start(ip='0.0.0.0',port='39020') - -def shell(id=''): - "命令行页面" - id=str(id) - if not id: - item=sqlite("terminal").where("host","127.0.0.1").field("id").find() - if not item: - return "请先配置终端" - else: - id=item['id'] - authkey=md5(randoms()) - set_cache("websocket",authkey,10) - set_cache(str(G.userinfo['id']),G.userinfo,10) - return response.tpl(WebSocketaddress="ws://"+request.HEADER.HTTP_HOST()+":39020?authkey="+authkey+"&id="+id+"&uid="+str(G.userinfo['id'])) -def terminallist(): - "终端列表页面" - return response.tpl() -def shelllog(): - "命令日志页面" - return response.tpl() -def deleteshelllog(): - "删除令日志" - try: - id=request.get_json() - sqlite("shelllog").where('id','in',id).delete() - except: - return errorjson(msg="失败") - else: - return successjson() -def getshelllog(id=0): - "获命令日志列表" - if id: - return successjson(sqlite("shelllog").field('id,uid,icon,name,host,port,username,cmd,addtime').find(id)) - where=None - kw=request.args.get('kw') - pagenow=request.args.get('pagenow') - pagesize=request.args.get('pagesize') - if kw: - where=[("uid","like","%"+str(kw)+"%"),'or',("name","like","%"+str(kw)+"%"),'or',("cmd","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] - if not pagenow: - pagenow=1 - else: - pagenow=int(pagenow) - if not pagesize: - pagesize=10 - else: - pagesize=int(pagesize) - lists=sqlite("shelllog").field("id,uid,icon,name,host,port,username,cmd,addtime").order("id desc").where(where).page(pagenow,pagesize).select() - count=sqlite("shelllog").where(where).count() - data=return_list(lists,count,pagenow,pagesize) - return successjson(data) -def getterminalpwd(id=0,tab='terminal'): - "获取终端密码" - if id: - return successjson(sqlite(tab).field('password').find(id)) - else: - return errorjson(msg="id不能为空") -def getterminallist(id=0): - "获取终端列表" - if id: - return successjson(sqlite("terminal").field('id,icon,title,host,port,types,username,blacklist,whitelist,addtime,updtime').find(id)) - where=None - kw=request.args.get('kw') - pagenow=request.args.get('pagenow') - pagesize=request.args.get('pagesize') - if kw: - where=[("title","like","%"+str(kw)+"%"),'or',("host","like","%"+str(kw)+"%")] - if not pagenow: - pagenow=1 - else: - pagenow=int(pagenow) - if not pagesize: - pagesize=10 - else: - pagesize=int(pagesize) - lists=sqlite("terminal").field("id,title,icon,host,port,types,username,addtime,blacklist,whitelist,updtime").where(where).page(pagenow,pagesize).select() - count=sqlite("terminal").where(where).count() - data=return_list(lists,count,pagenow,pagesize) - return successjson(data) -def addtermina(): - "添加终端" - data=request.get_json() - data['addtime']=times() - data['updtime']=times() - if sqlite("terminal").where("host",data['host']).count(): - return errorjson(msg="服务器"+data['host']+"已在列表中,请务重复添加") - if data['host'] and data['port'] and data['username'] and len(data['password'])>5: - try: - trans = paramiko.Transport((data['host'],int(data['port']))) - trans.start_client() - trans.auth_password(username=data['username'], password=data['password']) - channel = trans.open_session() - channel.settimeout(7200) - channel.get_pty() - channel.invoke_shell() - except: - return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") - else: - trans.close() - channel.close() - sqlite("terminal").insert(data) - else: - return errorjson(msg="配置信息格式错误") - return successjson() -def delete(): - "删除终端" - try: - id=request.get_json() - sqlite("terminal").where('id','in',id).delete() - except: - return errorjson(msg="失败") - else: - return successjson() -def update(id=0): - "修改终端配置" - data=request.get_json() - if not id: - id=data['id'] - try: - data['updtime']=times() - except:pass - else: - t=sqlite("terminal").where("id",id).find() - if len(data['password'])>5 and (t['host']!=data['host'] or t['port']!=data['port'] or t['username']!=data['username'] or t['password']!=data['password']): - try: - trans = paramiko.Transport((data['host'],int(data['port']))) - trans.start_client() - trans.auth_password(username=data['username'], password=data['password']) - channel = trans.open_session() - channel.settimeout(7200) - channel.get_pty() - channel.invoke_shell() - except: - return errorjson(msg="无法连接到ssh服务器,请检查配置是否正确") - else: - trans.close() - channel.close() - sqlite("terminal").where("id",id).update(data) - else: - del data['password'] - sqlite("terminal").where("id",id).update(data) - return successjson() \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shell.html b/app/intapp/controller/terminal/tpl/socket/shell.html deleted file mode 100644 index 2ee8933..0000000 --- a/app/intapp/controller/terminal/tpl/socket/shell.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - -kcwebplus - - - - - - - - - - - - - - - - - -
-
-
- - - - \ No newline at end of file diff --git a/app/intapp/controller/terminal/tpl/socket/shelllog.html b/app/intapp/controller/terminal/tpl/socket/shelllog.html deleted file mode 100644 index c0f69e0..0000000 --- a/app/intapp/controller/terminal/tpl/socket/shelllog.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - -kcwebplus - - - - - - - - - - - - - - - - - - - -
-
-    - - - 搜索 - - 终端管理 -
-
- - - - - - - - - - - - - - - - - - - -
-    删除选中  - - -
-
-
- - - diff --git a/app/intapp/controller/terminal/tpl/socket/terminallist.html b/app/intapp/controller/terminal/tpl/socket/terminallist.html deleted file mode 100644 index dce0a22..0000000 --- a/app/intapp/controller/terminal/tpl/socket/terminallist.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - -kcwebplus - - - - - - - - - - - - - - - - - - - -
-
-    - - - 搜索 - 添加服务器 - - 命令日志 -
-
- - - - - - - - - - - - - - - - - - - - - -
-    删除选中  - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 优先级大于命令黑名单,不填写表示不启用,否则在终端完整匹配该命令才能被执行 - - - - 优先级小于命令白名单,不填写表示不启用,否则在终端输入的命令只要包含该命令将会被阻止 - - - - 取 消 - 修改 - 添加 - - -
- - - -- Gitee