diff --git a/app/common/__init__.py b/app/common/__init__.py index baf8c672767e72dce4c18cb60699c7183d8965b2..2629661e0659a720418988bac392ec98226899d2 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/index/__init__.py b/app/intapp/controller/index/__init__.py index 0e70a9d15a40ad8eb55f5c4c21e32af9f17a0078..a4f463e4888c6d4bc95a4cd663d69f9952b3a6d0 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/common/model.py b/app/intapp/controller/index/common/model.py index 0a9b6372198a94bffeb9c27371ab9ff249448ff8..26bc1f21968e60e5602013607d12c43f16aeff5a 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 4e40c2e5b34a2fb0a9c993e200fb45bbb2263ea6..8116b777919a1815a4f0ac3ffc14c0e95974867a 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 dbcb02453b4a1d3b8719f06538be901747f3de0c..9707eaa56901ef7a50bba1098713950af1e5c26f 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/index/socket.py b/app/intapp/controller/index/socket.py deleted file mode 100644 index 6ce438dae8a647ddbedaba45271794840090d757..0000000000000000000000000000000000000000 --- 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 2ee8933f3892e916be49936b7b3f9d7f4ca6e027..0000000000000000000000000000000000000000 --- a/app/intapp/controller/index/tpl/socket/shell.html +++ /dev/null @@ -1,145 +0,0 @@ - - - -
- -