From 8ed36c1781c4396f3d27ced38d4796ed78352a6b Mon Sep 17 00:00:00 2001 From: midoks Date: Thu, 3 Nov 2022 00:11:16 +0800 Subject: [PATCH] webhook 1.0 --- plugins/memcached/bak/index_2022_6_18.py | 242 ----------------------- plugins/webhook/ico.png | Bin 0 -> 805 bytes plugins/webhook/index.html | 32 +++ plugins/webhook/index.py | 196 ++++++++++++++++++ plugins/webhook/info.json | 18 ++ plugins/webhook/install.sh | 33 ++++ plugins/webhook/js/webhook.js | 224 +++++++++++++++++++++ route/__init__.py | 30 ++- 8 files changed, 526 insertions(+), 249 deletions(-) delete mode 100755 plugins/memcached/bak/index_2022_6_18.py create mode 100644 plugins/webhook/ico.png create mode 100755 plugins/webhook/index.html create mode 100755 plugins/webhook/index.py create mode 100755 plugins/webhook/info.json create mode 100755 plugins/webhook/install.sh create mode 100755 plugins/webhook/js/webhook.js diff --git a/plugins/memcached/bak/index_2022_6_18.py b/plugins/memcached/bak/index_2022_6_18.py deleted file mode 100755 index 83e7093de..000000000 --- a/plugins/memcached/bak/index_2022_6_18.py +++ /dev/null @@ -1,242 +0,0 @@ -# coding:utf-8 - -import sys -import io -import os -import time -import re - -sys.path.append(os.getcwd() + "/class/core") -import mw - -app_debug = False -if mw.isAppleSystem(): - app_debug = True - - -def getPluginName(): - return 'memcached' - - -def getPluginDir(): - return mw.getPluginDir() + '/' + getPluginName() - - -def getServerDir(): - return mw.getServerDir() + '/' + getPluginName() - - -def getInitDFile(): - if app_debug: - return '/tmp/' + getPluginName() - return '/etc/init.d/' + getPluginName() - - -def getConf(): - path = getServerDir() + "/init.d/memcached" - return path - - -def getConfTpl(): - path = getPluginDir() + "/init.d/memcached.tpl" - return path - - -def getMemPort(): - path = getConf() - content = mw.readFile(path) - rep = 'PORT\s*=\s*(\d*)' - tmp = re.search(rep, content) - return tmp.groups()[0] - - -def getArgs(): - args = sys.argv[2:] - tmp = {} - args_len = len(args) - - if args_len == 1: - t = args[0].strip('{').strip('}') - t = t.split(':') - tmp[t[0]] = t[1] - elif args_len > 1: - for i in range(len(args)): - t = args[i].split(':') - tmp[t[0]] = t[1] - - return tmp - - -def status(): - data = mw.execShell( - "ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'") - if data[0] == '': - return 'stop' - return 'start' - - -def initDreplace(): - - file_tpl = getConfTpl() - service_path = mw.getServerDir() - - initD_path = getServerDir() + '/init.d' - if not os.path.exists(initD_path): - os.mkdir(initD_path) - file_bin = initD_path + '/memcached' - - if not os.path.exists(file_bin): - content = mw.readFile(file_tpl) - content = content.replace('{$SERVER_PATH}', service_path) - mw.writeFile(file_bin, content) - mw.execShell('chmod +x ' + file_bin) - - return file_bin - - -def memOp(method): - file = initDreplace() - data = mw.execShell(file + ' ' + method) - if data[1] == '': - return 'ok' - return data[1] - - -def start(): - return memOp('start') - - -def stop(): - return memOp('stop') - - -def restart(): - return memOp('restart') - - -def reload(): - return memOp('reload') - - -def runInfo(): - # 获取memcached状态 - import telnetlib - import re - port = getMemPort() - try: - tn = telnetlib.Telnet('127.0.0.1', int(port)) - tn.write(b"stats\n") - tn.write(b"quit\n") - data = tn.read_all() - if type(data) == bytes: - data = data.decode('utf-8') - data = data.replace('STAT', '').replace('END', '').split("\n") - result = {} - res = ['cmd_get', 'get_hits', 'get_misses', 'limit_maxbytes', 'curr_items', 'bytes', - 'evictions', 'limit_maxbytes', 'bytes_written', 'bytes_read', 'curr_connections'] - for d in data: - if len(d) < 3: - continue - t = d.split() - if not t[0] in res: - continue - result[t[0]] = int(t[1]) - result['hit'] = 1 - if result['get_hits'] > 0 and result['cmd_get'] > 0: - result['hit'] = float(result['get_hits']) / \ - float(result['cmd_get']) * 100 - - conf = mw.readFile(getConf()) - result['bind'] = re.search('IP=(.+)', conf).groups()[0] - result['port'] = int(re.search('PORT=(\d+)', conf).groups()[0]) - result['maxconn'] = int(re.search('MAXCONN=(\d+)', conf).groups()[0]) - result['cachesize'] = int( - re.search('CACHESIZE=(\d+)', conf).groups()[0]) - return mw.getJson(result) - except Exception as e: - return mw.getJson({}) - - -def saveConf(): - # 设置memcached缓存大小 - import re - confFile = getConf() - # print confFile - try: - args = getArgs() - content = mw.readFile(confFile) - content = re.sub('IP=.+', 'IP=' + args['ip'], content) - content = re.sub('PORT=\d+', 'PORT=' + args['port'], content) - content = re.sub('MAXCONN=\d+', 'MAXCONN=' + args['maxconn'], content) - content = re.sub('CACHESIZE=\d+', 'CACHESIZE=' + - args['cachesize'], content) - mw.writeFile(confFile, content) - restart() - return 'save ok' - except Exception as e: - pass - return 'fail' - - -def initdStatus(): - if not app_debug: - if mw.isAppleSystem(): - return "Apple Computer does not support" - initd_bin = getInitDFile() - if os.path.exists(initd_bin): - return 'ok' - return 'fail' - - -def initdInstall(): - import shutil - if not app_debug: - if mw.isAppleSystem(): - return "Apple Computer does not support" - - mem_bin = initDreplace() - initd_bin = getInitDFile() - shutil.copyfile(mem_bin, initd_bin) - mw.execShell('chmod +x ' + initd_bin) - mw.execShell('chkconfig --add ' + getPluginName()) - return 'ok' - - -def initdUinstall(): - if not app_debug: - if mw.isAppleSystem(): - return "Apple Computer does not support" - - mw.execShell('chkconfig --del ' + getPluginName()) - initd_bin = getInitDFile() - os.remove(initd_bin) - return 'ok' - -if __name__ == "__main__": - func = sys.argv[1] - if func == 'status': - print(status()) - elif func == 'start': - print(start()) - elif func == 'stop': - print(stop()) - elif func == 'restart': - print(restart()) - elif func == 'reload': - print(reload()) - elif func == 'initd_status': - print(initdStatus()) - elif func == 'initd_install': - print(initdInstall()) - elif func == 'initd_uninstall': - print(initdUinstall()) - elif func == 'run_info': - print(runInfo()) - elif func == 'conf': - print(getConf()) - elif func == 'conf_tpl': - print(getConfTpl()) - elif func == 'save_conf': - print(saveConf()) - else: - print('fail') diff --git a/plugins/webhook/ico.png b/plugins/webhook/ico.png new file mode 100644 index 0000000000000000000000000000000000000000..633088a7e7e5e35eff34efdf163d2d2bf5488121 GIT binary patch literal 805 zcmeAS@N?(olHy`uVBq!ia0vp^20*OA!3-q(BRide6mzkYX9x!e$L)vy4}jct0X`wF z|NsBzpLJJg=53J~w}qzP7MOltX!-+@X}86v-4>W}M|k>8p{ch;rrsBwdPjK1U5FZ> ztibe}Kq=v=AX%X)ci~b%aiECc)SCi8@#(jLDnSa67$7Tv#)35hl>xbE3P4(r)q}Nz zlz~+?M>l^5y4SnKM_d+P!=CnKO6a{r~Sa zbzvjW6wU&V$YKTtzQZ8Qcszea3Q$m{#5JNMI6tkVJh3R1!7(L2DOJHOvnaJZzbLy{ z!8zFM#hy()Ky_jubkmrLf{q-kLyVXd3OJB4_Wz&TE6I&)0^KMFHa5&|*>0pB6mG~#${X?18 zaIcB-*?VA-R7-D(;i`;{ADE=mxlHe?@i+vpJ$&HQ#yz1|PjRmhS+O$1qO&ql*Gac= zZZ+eFbxEh!Gja8O`_BW-6zW(B*sABi> z`Se>SHn!M5s%KA$5|G>8$l3BWo!j8|iFdahPMrzoUa?u}v9q%5M6(V5m+i>*a7k}p zk73@5&PoDF}ozG#zmXI8kn|CbmG$fBV_Jg1hf~-8b(&dGX2Bo%4A6cD+CPX7StO zh09~J=Gf%Fwf4Pucjo!^U%oVH3O5D!$TdIPP{+9MYhC5V)<=thamC>2>gTe~DWM4f Dx`1TB literal 0 HcmV?d00001 diff --git a/plugins/webhook/index.html b/plugins/webhook/index.html new file mode 100755 index 000000000..6672a2d9e --- /dev/null +++ b/plugins/webhook/index.html @@ -0,0 +1,32 @@ + +
+ + + + + + + + + + + + + +
名称添加时间近期调用调用次数密钥操作
+
+ + \ No newline at end of file diff --git a/plugins/webhook/index.py b/plugins/webhook/index.py new file mode 100755 index 000000000..a2fe7a073 --- /dev/null +++ b/plugins/webhook/index.py @@ -0,0 +1,196 @@ +# coding:utf-8 + +import sys +import io +import os +import time +import re +import json + +sys.path.append(os.getcwd() + "/class/core") +import mw + +app_debug = False +if mw.isAppleSystem(): + app_debug = True + + +def getPluginName(): + return 'webhook' + + +def getPluginDir(): + return mw.getPluginDir() + '/' + getPluginName() + + +def getServerDir(): + return mw.getServerDir() + '/' + getPluginName() + + +def getArgs(): + args = sys.argv[2:] + tmp = {} + args_len = len(args) + + if args_len == 1: + t = args[0].strip('{').strip('}') + t = t.split(':') + tmp[t[0]] = t[1] + elif args_len > 1: + for i in range(len(args)): + t = args[i].split(':') + tmp[t[0]] = t[1] + + return tmp + + +def checkArgs(data, ck=[]): + for i in range(len(ck)): + if not ck[i] in data: + return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!')) + return (True, mw.returnJson(True, 'ok')) + + +def getCfgFilePath(): + return getServerDir() + "/cfg.json" + + +def initCfg(): + cfg = getCfgFilePath() + data = [] + mw.writeFile(cfg, json.dumps(data)) + + +def getCfg(): + cfg = getCfgFilePath() + if not os.path.exists(cfg): + initCfg() + + data = mw.readFile(cfg) + data = json.loads(data) + return data + + +def addCfg(val): + cfg = getCfgFilePath() + data = getCfg() + data.append(val) + mw.writeFile(cfg, json.dumps(data)) + + +def status(): + return 'start' + + +def addHook(): + args = getArgs() + data = checkArgs(args, ['title', "shell"]) + if not data[0]: + return data[1] + + hook = {} + hook['title'] = args['title'] + hook['access_key'] = mw.getRandomString(48) + hook['count'] = 0 + hook['addtime'] = int(time.time()) + hook['uptime'] = 0 + + script_dir = getServerDir() + "/scripts" + if not os.path.exists(script_dir): + os.mkdir(script_dir) + + addCfg(hook) + shellFile = script_dir + '/' + hook['access_key'] + mw.writeFile(shellFile, args['shell']) + return mw.returnJson(True, '添加成功!') + + +def getList(): + data = getCfg() + + rdata = {} + rdata['list'] = data + rdata['script_dir'] = getServerDir() + "/scripts" + return mw.returnJson(True, 'ok', rdata) + + +def getLog(): + args = getArgs() + check_arg = checkArgs(args, ['path']) + if not check_arg[0]: + return check_arg[1] + + logPath = args['path'] + + content = mw.getLastLine(logPath, 100) + return mw.returnJson(True, 'ok', content) + + +def runShellArgs(args): + data = getCfg() + for i in range(len(data)): + if data[i]['access_key'] == args['access_key']: + script_dir = getServerDir() + "/scripts" + shellFile = script_dir + '/' + args['access_key'] + param = '' + if hasattr(args, 'param'): + param = args['param'] + os.system("bash {} \"{}\" >> {}.log &".format( + shellFile, param.replace('"', r'\"'), shellFile)) + data[i]['count'] += 1 + data[i]['uptime'] = int(time.time()) + mw.writeFile(getCfgFilePath(), json.dumps(data)) + return mw.returnJson(True, '运行成功!') + return mw.returnJson(False, '指定Hook不存在!') + + +def runShell(): + args = getArgs() + check_arg = checkArgs(args, ['access_key']) + if not check_arg[0]: + return check_arg[1] + + return runShellArgs(args) + + +def delHook(): + args = getArgs() + check_arg = checkArgs(args, ['access_key']) + if not check_arg[0]: + return check_arg[1] + + data = getCfg() + newdata = [] + for hook in data: + if hook['access_key'] == args['access_key']: + continue + newdata.append(hook) + + jsonFile = getCfgFilePath() + shellFile = getServerDir() + "/scripts/" + args['access_key'] + if not os.path.exists(shellFile): + return mw.returnJson(False, '删除失败!') + os.remove(shellFile) + log_file = "{}.log".format(shellFile) + if os.path.exists(log_file): + os.remove(log_file) + + mw.writeFile(jsonFile, json.dumps(newdata)) + return mw.returnJson(True, '删除成功!') + +if __name__ == "__main__": + func = sys.argv[1] + if func == 'status': + print(status()) + elif func == "add_hook": + print(addHook()) + elif func == "get_list": + print(getList()) + elif func == "run_shell": + print(runShell()) + elif func == 'del_hook': + print(delHook()) + elif func == 'get_log': + print(getLog()) + else: + print('error') diff --git a/plugins/webhook/info.json b/plugins/webhook/info.json new file mode 100755 index 000000000..b4e5f279d --- /dev/null +++ b/plugins/webhook/info.json @@ -0,0 +1,18 @@ +{ + "sort": 7, + "ps": "WebHook,可设置回调脚本,通常用于第三方回调通知!", + "name": "webhook", + "title": "WebHook", + "shell": "install.sh", + "versions":["1.0"], + "updates":["1.0"], + "tip": "soft", + "checks": "server/webhook", + "path": "server/webhook", + "display": 1, + "author": "", + "date": "2022-11-02", + "home": "", + "type": 0, + "pid": "4" +} \ No newline at end of file diff --git a/plugins/webhook/install.sh b/plugins/webhook/install.sh new file mode 100755 index 000000000..ff52c3bee --- /dev/null +++ b/plugins/webhook/install.sh @@ -0,0 +1,33 @@ +#!/bin/bash +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin +export PATH + +curPath=`pwd` +rootPath=$(dirname "$curPath") +rootPath=$(dirname "$rootPath") +serverPath=$(dirname "$rootPath") + +install_tmp=${rootPath}/tmp/mw_install.pl + +VERSION=1.0 + +Install_App() +{ + echo '正在安装脚本文件...' > $install_tmp + mkdir -p $serverPath/webhook + echo "${VERSION}" > $serverPath/webhook/version.pl + echo '安装完成' > $install_tmp +} + +Uninstall_App() +{ + rm -rf $serverPath/redis + echo "Uninstall_App" > $install_tmp +} + +action=$1 +if [ "${1}" == 'install' ];then + Install_App +else + Uninstall_App +fi diff --git a/plugins/webhook/js/webhook.js b/plugins/webhook/js/webhook.js new file mode 100755 index 000000000..dbe6167f2 --- /dev/null +++ b/plugins/webhook/js/webhook.js @@ -0,0 +1,224 @@ + +function whPost(method, args,callback){ + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + + var req_data = {}; + req_data['name'] = 'webhook'; + req_data['func'] = method; + + if (typeof(args) == 'string'){ + req_data['args'] = JSON.stringify(toArrayObject(args)); + } else { + req_data['args'] = JSON.stringify(args); + } + + $.post('/plugins/run', req_data, function(data) { + layer.close(loadT); + if (!data.status){ + //错误展示10S + layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']}); + return; + } + + if(typeof(callback) == 'function'){ + callback(data); + } + },'json'); +} + +function whPostCallbak(method, version, args,callback){ + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + + var req_data = {}; + req_data['name'] = 'webhook'; + req_data['func'] = method; + args['version'] = version; + + if (typeof(args) == 'string'){ + req_data['args'] = JSON.stringify(toArrayObject(args)); + } else { + req_data['args'] = JSON.stringify(args); + } + + $.post('/plugins/callback', req_data, function(data) { + layer.close(loadT); + if (!data.status){ + layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + if(typeof(callback) == 'function'){ + callback(data); + } + },'json'); +} + +var whEditor = null; + +//添加 +function addHook(){ + layer.open({ + type: 1, + area: '600px', + title: '添加Hook', + closeBtn: 1, + shift: 5, + shadeClose: false, + btn:['提交','关闭'], + content: "
\ +
\ + 名称\ +
\ +
\ +
\ + 执行脚本\ +
\ + \ +
\ +
\ +
", + success:function(){ + + $("#hook_shell").empty().text(''); + $(".CodeMirror").remove(); + whEditor = CodeMirror.fromTextArea(document.getElementById("hook_shell"), { + extraKeys: { + "Ctrl-Space": "autocomplete", + "Ctrl-F": "findPersistent", + "Ctrl-H": "replaceAll", + "Ctrl-S": function() {} + }, + lineNumbers: true, + matchBrackets:true, + mode:"sh", + }); + + $(".CodeMirror-scroll").css({"height":"300px","margin":0,"padding":0}); + whEditor.focus(); + }, + yes:function(indexs){ + var loadT = layer.msg("提交中...",{icon:16,time:0}); + var data = { + title: $("#hook_title").val(), + shell: whEditor.getValue(), + } + whPost('add_hook', data, function(rdata){ + var rdata = $.parseJSON(rdata.data); + if (!rdata.status){ + layer.msg(rdata.msg,{icon:2}); + return; + } + layer.close(indexs); + showMsg(rdata.msg, function(){ + getHookList(); + }, {icon:1}, 2000); + }); + } + }); +} +//获取列表 +function getHookList(){ + whPost('get_list', {}, function(rdata){ + var rdata = $.parseJSON(rdata.data); + var zbody = ''; + var mlist = rdata.data.list; + var script_dir = rdata.data.script_dir; + for(var i=0;i'+mlist[i].title+'' + +''+getLocalTime(mlist[i].addtime)+'' + +''+getLocalTime(mlist[i].uptime)+'' + +''+mlist[i].count+'' + +'查看密钥' + +'测试 | ' + +'编辑 | ' + +'日志 | ' + +'删除' + +'' + } + $("#zipBody").html(zbody); + }); +} + +//查看密钥 +function showWebHookCode(url,code){ + layer.open({ + type:1, + title:'查看密钥', + area: '600px', + shadeClose:false, + closeBtn:2, + content:'
\ +
密钥
\ +
\ + WebHook使用方法:
\ + GET/POST:
\ + '+window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '')+'/hook?access_key='+code+'&param=aaa
\ + @param access_key string HOOK密钥
\ + @param param string 自定义参数(在hook脚本中使用$1接收)
\ +
\ +
' + }) +} + +//查看日志 +function getLogs(path){ + + + whPost('get_log', {"path":path}, function(rdata){ + var rdata = $.parseJSON(rdata.data); + if (!rdata.status){ + layer.msg(rdata.msg,{icon:2}); + } + + layer.open({ + type:1, + title:'任务执行日志', + area: ['600px','400px'], + shadeClose:false, + closeBtn:2, + content:'
\ + \ +
', + success:function(){ + $('[name="site_logs"]').scrollTop($('[name="site_logs"]')[0].scrollHeight) + } + }); + + + }); +} + +//运行 +function runHook(key){ + whPost('run_shell', {"access_key":key}, function(rdata){ + var rdata = $.parseJSON(rdata.data); + if (!rdata.status){ + layer.msg(rdata.msg,{icon:2}); + } + + showMsg(rdata.msg,function(){ + getHookList(); + },{icon:1},2000); + }); +} +//删除 +function deleteHook(key, title){ + layer.confirm('删除Hook-['+ title +']',{ + title:'是否删除Hook-['+ title +']任务,是否继续' + },function(){ + whPost('del_hook', {"access_key":key}, function(rdata){ + var rdata = $.parseJSON(rdata.data); + if (!rdata.status){ + layer.msg(rdata.msg,{icon:2}); + } + + showMsg(rdata.msg,function(){ + getHookList(); + },{icon:1},2000); + }); + }); +} + + + diff --git a/route/__init__.py b/route/__init__.py index 625b2924d..ced9bbcd4 100755 --- a/route/__init__.py +++ b/route/__init__.py @@ -134,13 +134,29 @@ def publicObject(toObject, func, action=None, get=None): return mw.getJson(data) -@app.route("/debug") -def debug(): - print(sys.version_info) - print(session) - os = mw.getOs() - print(os) - return mw.getLocalIp() +# @app.route("/debug") +# def debug(): +# print(sys.version_info) +# print(session) +# os = mw.getOs() +# print(os) +# return mw.getLocalIp() + +# 仅针对webhook插件 +@app.route("/hook") +def webhook(): + input_args = { + 'access_key': request.args.get('access_key', '').strip(), + 'params': request.args.get('params', '').strip() + } + + wh_install_path = mw.getServerDir() + '/webhook' + if not os.path.exists(wh_install_path): + return mw.returnJson(False, '请先安装WebHook插件!') + + sys.path.append('plugins/webhook') + import index + return index.runShellArgs(input_args) @app.route('/close')