Compare commits

...
151 Commits
Author SHA1 Message Date
Mr Chen 696797f125 Merge pull request #350 from midoks/dev
0.12.2
2023-01-27 14:41:55 +08:00
midoks fcfad78506 Update .gitignore 2023-01-27 14:40:57 +08:00
midoks 4787d6e7bb 0.12.2
* 开放菜单权限配置。
* 升级SSH终端2.0。
* 增加已安装类型。
* 加入切换linux软件源的命令。
* iptables安装优化。
* 网站统计POST获取数据优化。
* mysql[apt/yum]迁移优化。
* 优化防火墙导入。
* 图标可设置。
* 各种细节优化。
2023-01-27 14:39:46 +08:00
midoks 80ef6dbe4c 描述修改 2023-01-27 13:40:35 +08:00
midoks 78cdad5fb8 Update install.sh 2023-01-27 13:36:06 +08:00
midoks 274f0638ac Update install.sh 2023-01-27 13:35:45 +08:00
midoks 1e97b146db up 2023-01-27 13:33:11 +08:00
midoks fbbc506de9 Update .gitignore 2023-01-27 02:16:32 +08:00
midoks 58ec4c2c30 简单加密 2023-01-27 01:19:26 +08:00
midoks a2298ade04 Update webssh.js 2023-01-27 00:53:34 +08:00
midoks d5fc464603 ssh update 90% 2023-01-27 00:40:06 +08:00
midoks c952be4e45 up 2023-01-26 22:49:55 +08:00
midoks 17a92518b4 Update term-websocketio.js 2023-01-26 19:35:51 +08:00
midoks c7154eea7b Update files.js 2023-01-26 19:35:43 +08:00
midoks 7cab1492c0 Update ssh_terminal.py 2023-01-26 04:21:49 +08:00
midoks 77b6391d9e Update ssh_terminal.py 2023-01-26 04:21:25 +08:00
midoks 08a91ed0f2 ssh终端收尾阶段 2023-01-26 04:11:51 +08:00
midoks b4d090021c up 2023-01-26 03:14:50 +08:00
midoks bf064d89f4 up 2023-01-26 02:06:02 +08:00
midoks 7314071634 ssh优化 2023-01-26 02:05:39 +08:00
midoks 49a606baa2 Update mw.tpl 2023-01-25 19:55:54 +08:00
midoks aaabe5628e Update debian.sh 2023-01-25 19:54:39 +08:00
midoks ea03373363 Update ssh_terminal.py 2023-01-25 19:42:17 +08:00
midoks 515d25648f ssh优化 2023-01-25 17:17:14 +08:00
midoks a30792178a up 2023-01-25 16:50:10 +08:00
midoks 1c74ce3c58 ssh 60% 2023-01-25 16:20:03 +08:00
midoks 832f3b45eb up 2023-01-25 03:20:55 +08:00
midoks 2c3ad7ea99 Update webstats_common.lua 2023-01-23 20:30:01 +08:00
midoks 6b3dae6169 Update webstats_common.lua 2023-01-23 20:21:00 +08:00
midoks d387546986 Update requirements.txt 2023-01-23 04:21:52 +08:00
midoks 6929c5a173 Update requirements.txt 2023-01-23 04:21:02 +08:00
midoks d66e9d7fc6 up 2023-01-23 04:09:25 +08:00
midoks 17470600e9 Update app.py 2023-01-23 04:06:43 +08:00
midoks d1017ddb5c Create term.js 2023-01-23 03:45:55 +08:00
midoks 67161e62ce Update cli.sh 2023-01-23 03:44:44 +08:00
midoks 87ad51f6ad up 2023-01-22 18:34:46 +08:00
midoks 2239d178f4 Update site.css 2023-01-22 15:33:22 +08:00
midoks 4ff95f057c 增加已安装类型 2023-01-22 15:33:14 +08:00
midoks f32ba65596 Update webssh.js 2023-01-22 13:28:42 +08:00
midoks d3db79a4ed webssh 55% 2023-01-22 03:17:09 +08:00
midoks ddc8cde44c Delete cmd.json 2023-01-22 01:32:42 +08:00
midoks 719ad042c7 webssh 50% 2023-01-22 01:31:47 +08:00
midoks 9134dfb1a9 Update index.css 2023-01-20 03:02:45 +08:00
midoks 9611834a9d up 2023-01-20 02:54:55 +08:00
midoks 8d5cc2e926 Update __init__.py 2023-01-20 02:34:45 +08:00
midoks 01b9c51247 Update __init__.py 2023-01-20 02:31:59 +08:00
midoks 21ca9d8874 优化ssh并兼容mac 2023-01-20 02:31:43 +08:00
midoks d2d5a0e12f up 2023-01-20 02:11:07 +08:00
midoks ad2e9958f8 Update mw.tpl 2023-01-19 22:24:15 +08:00
midoks 7cf64673f9 加入切换linux软件源的命令 2023-01-19 22:18:35 +08:00
midoks c49bc6f823 Update README.md 2023-01-19 18:04:00 +08:00
midoks 24e6c57eec Update firewall.js 2023-01-18 17:58:23 +08:00
midoks a6842f2679 Update firewall_api.py 2023-01-18 17:42:56 +08:00
midoks 42ba0ea285 优化iptables判断 2023-01-18 17:27:33 +08:00
midoks 19e6055b7c Update install.sh 2023-01-18 01:38:18 +08:00
midoks 1388c697e0 iptables安装优化 2023-01-18 01:38:06 +08:00
midoks 2a97c0f8b3 Update plugin_menu.html 2023-01-18 01:12:24 +08:00
midoks 8aa4084373 Update plugins_api.py 2023-01-18 01:03:23 +08:00
midoks 4e16773ed8 Update layout.html 2023-01-18 00:57:38 +08:00
midoks b4b9b6eb1f Create plugin_menu.html 2023-01-18 00:57:30 +08:00
midoks b35ae736a3 up 2023-01-18 00:57:25 +08:00
midoks ec78197317 Update plugins_api.py 2023-01-17 15:58:27 +08:00
midoks 1558e93f33 Update .gitignore 2023-01-17 15:37:22 +08:00
midoks 99a15ffc82 Update mw.py 2023-01-17 03:46:04 +08:00
Mr Chen 2b0b697a6a Merge pull request #343 from midoks/dev
修复iptables和firewalld同时存在,导致识别出错2。
2023-01-17 00:17:30 +08:00
midoks a93953a61d Update firewall_api.py 2023-01-17 00:04:56 +08:00
Mr Chen 1ce68581af Merge pull request #342 from midoks/dev
修复iptables和firewalld同时存在,导致识别出错。
2023-01-16 23:53:17 +08:00
midoks df5979a4cf Update firewall_api.py 2023-01-16 23:48:26 +08:00
midoks 9197dcbe03 Update firewall_api.py 2023-01-16 23:48:05 +08:00
midoks 4100824c43 Update firewall_api.py 2023-01-16 23:39:16 +08:00
midoks c22b2b3774 Update firewall_api.py 2023-01-16 23:34:46 +08:00
midoks 0fbd3163e2 up 2023-01-16 23:30:12 +08:00
midoks 500171ed66 Update mw.py 2023-01-16 21:43:38 +08:00
midoks 1c6b6f1090 Update mw.py 2023-01-16 21:43:18 +08:00
midoks fc8a54c4b3 Update app.py 2023-01-16 02:04:12 +08:00
midoks 4ade42380d Update layout.html 2023-01-14 22:43:40 +08:00
midoks 6b2c21ab47 Update install.sh 2023-01-14 20:01:54 +08:00
Mr Chen 6f5ea82a58 Merge pull request #340 from midoks/dev
修复Webhook 插件BUG
2023-01-14 16:53:51 +08:00
midoks 73c849931c #338
已经优化
2023-01-14 16:51:38 +08:00
midoks 39d76f5621 #338 2023-01-14 16:42:22 +08:00
Mr Chen bc435ea848 Merge pull request #339 from midoks/dev
修复网站统计-设置站点配置产生的问题。
2023-01-14 15:31:45 +08:00
midoks ed82dd3c12 Update webstats_common.lua 2023-01-14 15:14:51 +08:00
midoks 0a5a86625f 修复设置错误 2023-01-14 13:46:59 +08:00
midoks 53f56c949b Update sg11.sh 2023-01-13 00:55:49 +08:00
midoks 7e61e37d80 up 2023-01-12 19:49:31 +08:00
midoks c05d0244db Update xhprof.js 2023-01-12 17:50:56 +08:00
midoks 226d0addc5 图标可设置 2023-01-12 14:31:12 +08:00
midoks 35cce35ff3 #334 2023-01-11 17:47:49 +08:00
midoks 9450103c4b 文字优化 2023-01-11 12:01:44 +08:00
Mr Chen 4478f005e7 Merge pull request #333 from midoks/dev
mysql[apt/yum]迁移功能优化
2023-01-10 17:49:27 +08:00
midoks 71be0e3196 Update index.py 2023-01-10 17:47:38 +08:00
midoks e6a79216c4 mysql[apt/yum]迁移优化 2023-01-10 17:45:03 +08:00
midoks 3f12d4b8d6 Update index.py 2023-01-10 17:41:06 +08:00
midoks 683f041b1d Update update_dev.sh 2023-01-10 17:37:33 +08:00
midoks e08cebd48e Update update_dev.sh 2023-01-10 17:32:27 +08:00
midoks d02dea3150 Update update_dev.sh 2023-01-10 17:32:17 +08:00
midoks 18bb92c9e2 Update update_dev.sh 2023-01-10 17:29:08 +08:00
midoks f9b45ee4d9 优化更新脚本 2023-01-10 17:25:38 +08:00
midoks dcbc86ea5c Update index.py 2023-01-10 17:08:26 +08:00
midoks 300728cb17 Update index.py 2023-01-10 17:04:58 +08:00
midoks 51aa028f97 Update index.py 2023-01-10 17:03:36 +08:00
midoks e30ac33cea Update index.py 2023-01-10 16:59:14 +08:00
midoks 1c2f3c4378 Update __init__.py 2023-01-10 01:06:58 +08:00
Mr Chen 17eadfccff Merge pull request #332 from midoks/dev
优化mysql初始化
2023-01-09 23:36:58 +08:00
midoks b55a6d3bd9 Update index.py 2023-01-09 23:31:00 +08:00
Mr Chen 48936e7918 Merge pull request #331 from midoks/dev
php-apt/php-yum安装优化
2023-01-09 15:14:59 +08:00
midoks 1a99c53cb6 composer和php-apt的优化 2023-01-09 15:10:14 +08:00
midoks a8b5df25d0 php-yum优化 2023-01-09 14:46:08 +08:00
midoks 73b4be90f5 Update install.sh 2023-01-09 14:33:15 +08:00
midoks 1ecf12ab5c php-yum update 2023-01-09 14:08:02 +08:00
midoks 758da44141 up 2023-01-09 11:39:52 +08:00
midoks 8aa44408cc Update install.sh 2023-01-09 11:27:34 +08:00
Mr Chen ccf4ab7d81 Merge pull request #330 from midoks/dev
OP防火墙和phpmyadmin轻微优化
2023-01-08 15:21:28 +08:00
midoks 61766a8942 Update init.lua 2023-01-08 13:49:42 +08:00
midoks ce9ac280c7 Update index.py 2023-01-08 13:04:22 +08:00
Mr Chen 94bd8cbe8e Merge pull request #329 from midoks/dev
修复绑定域名问题
2023-01-07 23:31:21 +08:00
midoks 705f2445ee Update site_api.py 2023-01-07 23:24:33 +08:00
Mr Chen bc8d16f2c2 Merge pull request #328 from midoks/dev
OpenResty配置优化
2023-01-07 23:01:09 +08:00
midoks fe9eb7dc38 Update cert_api.py 2023-01-07 19:39:01 +08:00
midoks 94195b5246 优化防火墙导入 2023-01-07 19:21:12 +08:00
midoks 24009267be Update index.py 2023-01-07 16:02:27 +08:00
midoks c28412aea5 Update index.py 2023-01-07 15:55:56 +08:00
midoks 847b9d569b Update index.py 2023-01-07 15:49:37 +08:00
midoks b3c3a4457d op防火墙优化
1.适配openresty配置修改。
2.加入一个测试功能,便于测试。
2023-01-07 15:36:44 +08:00
midoks 89a84f5ca0 Update lua.conf 2023-01-07 15:08:27 +08:00
midoks 4432fa15cc Update lua.conf 2023-01-07 14:17:33 +08:00
midoks c6a600299d Update lua.conf 2023-01-07 12:29:50 +08:00
midoks 082b0ebcc3 openresty 默认开启 2023-01-07 12:23:50 +08:00
midoks 828436b772 Update webstats_common.lua 2023-01-07 03:00:55 +08:00
midoks 658a727fe3 Update index.py 2023-01-07 01:42:52 +08:00
midoks bedd6e5409 Update index.py 2023-01-07 01:02:47 +08:00
midoks ef8bc8bf57 Update index.py 2023-01-07 01:00:52 +08:00
midoks a22f89797a Update index.py 2023-01-07 00:50:20 +08:00
midoks eaf341cda6 Update index.py 2023-01-07 00:37:20 +08:00
midoks 58d69d734d 优化【网站统计】强制获取日志POST信息。 2023-01-07 00:15:54 +08:00
midoks e19f7702db Update tool_task.py 2023-01-06 20:52:07 +08:00
midoks b546a39f29 Update index.py 2023-01-06 20:32:12 +08:00
midoks 81b570214a Update index.py 2023-01-06 20:29:26 +08:00
midoks 44401f5944 Update webstats_common.lua 2023-01-06 20:12:31 +08:00
midoks 4ad190586a 调试请求日志 2023-01-06 20:08:27 +08:00
midoks 25bca124b4 Update index.py 2023-01-06 18:09:06 +08:00
midoks 98165bb449 修复网站统计-监控配置 2023-01-06 18:00:22 +08:00
midoks 6693edb924 Update install.sh 2023-01-06 16:03:02 +08:00
Mr Chen bae1beec3e Merge pull request #327 from midoks/dev
修复网站统计【初始安装】不可用
2023-01-06 12:34:01 +08:00
midoks 0682ca4d4d #326
修复
2023-01-06 12:31:26 +08:00
midoks 5bc10bebd0 Update index.py 2023-01-06 12:17:21 +08:00
Mr Chen 25df8b430b Merge pull request #325 from midoks/dev
修复子域名绑定没有正常删除问题
2023-01-06 00:27:22 +08:00
midoks 4f8fc31ca3 修复子域名绑定没有正常删除问题 2023-01-06 00:25:21 +08:00
Mr Chen a44f54e719 Merge pull request #324 from midoks/dev
修复绑定域名问题
2023-01-05 21:41:09 +08:00
midoks 12068046ec 修复绑定域名问题 2023-01-05 21:31:39 +08:00
midoks d6f57e5ea7 Update install.sh 2023-01-04 21:24:40 +08:00
96 changed files with 3291 additions and 689 deletions
+4
View File
@@ -156,6 +156,9 @@ data/bind_domain.pl
plugins/l2tp
plugins/openlitespeed
plugins/migration_api
plugins/system_safe
plugins/tamper_proof
plugins/gdrive
plugins/mtproxy
plugins/zimg
@@ -164,6 +167,7 @@ plugins/mail
plugins/fastdfs
plugins/v2ray
plugins/frp
plugins/file_search
debug.out
+10 -8
View File
@@ -72,7 +72,6 @@ PHP[72-81]支持phpMyAdmin[5.2.0]
# 特别赞助
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
- [奈飞丝 - 奈飞中国 Netflix MOD首发](https://naifeis.com/index.php#/register?code=k7P7V6Ur)
# AD - VPS推荐 - 🙏
@@ -92,14 +91,17 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
```
### 版本更新 0.12.1
### 版本更新 0.12.2
* mysql/mariadb/mysql-apt/mysql-yum增加新的同步方式[同步账户]。
* pureftp安装时自动放行端口。
* 面板ssl,添加【申请Lets证书】功能。
* 站点子域名绑定优化。
* 修复添加数据库名字判断。
* 增加PHP52的隐藏和显示指令。
* 开放菜单权限配置。
* 升级SSH终端2.0。
* 增加已安装类型。
* 加入切换linux软件源的命令。
* iptables安装优化。
* 网站统计POST获取数据优化。
* mysql[apt/yum]迁移优化。
* 优化防火墙导入。
* 图标可设置。
* 各种细节优化。
+5 -3
View File
@@ -20,6 +20,8 @@
import sys
import io
import os
sys.dont_write_bytecode = True
from route import app, socketio
@@ -38,12 +40,12 @@ try:
PORT = int(f.read())
f.close()
HOST = '0.0.0.0'
# HOST = '0.0.0.0'
# app.run(host=HOST, port=PORT)
http_server = WSGIServer(
(HOST, PORT), app, handler_class=WebSocketHandler)
http_server.serve_forever()
socketio.run(app, host=HOST, port=PORT)
except Exception as ex:
print(ex)
+3 -1
View File
@@ -371,7 +371,9 @@ fi
response = urllib.request.urlopen(req, timeout=timeout)
return response
except Exception as ex:
raise Exception("requestsPost: {}".format(str(ex)))
self.getError()
raise Exception("requestsPost: {}".format(self.getError(str(ex))))
def getRequestJson(self, response):
try:
+13 -4
View File
@@ -27,7 +27,7 @@ from flask import request
class config_api:
__version = '0.12.1'
__version = '0.12.2'
__api_addr = 'data/api.json'
def __init__(self):
@@ -781,12 +781,21 @@ class config_api:
"id=?", (1,)).getField('username')
# databases hook 获取
database_file = 'data/hook_database.json'
if os.path.exists(database_file):
df = mw.readFile(database_file)
database_hook_file = 'data/hook_database.json'
if os.path.exists(database_hook_file):
df = mw.readFile(database_hook_file)
df = json.loads(df)
data['hook_database'] = df
else:
data['hook_database'] = []
# menu hook 获取
menu_hook_file = 'data/hook_menu.json'
if os.path.exists(menu_hook_file):
df = mw.readFile(menu_hook_file)
df = json.loads(df)
data['hook_menu'] = df
else:
data['hook_menu'] = []
return data
+63 -62
View File
@@ -28,10 +28,14 @@ from flask import request
class firewall_api:
__isFirewalld = False
__isIptables = False
__isUfw = False
__isMac = False
def __init__(self):
iptables_file = mw.systemdCfgDir() + '/iptables.service'
if os.path.exists(iptables_file):
self.__isIptables = True
if os.path.exists('/usr/sbin/firewalld'):
self.__isFirewalld = True
if os.path.exists('/usr/sbin/ufw'):
@@ -55,13 +59,15 @@ class firewall_api:
if self.__isUfw:
mw.execShell('ufw deny from ' + address + ' to any')
else:
if self.__isFirewalld:
if self.__isIptables:
cmd = 'iptables -I INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
elif self.__isFirewalld:
cmd = 'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="' + \
address + '" drop\''
mw.execShell(cmd)
else:
cmd = 'iptables -I INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
pass
msg = mw.getInfo('屏蔽IP[{1}]成功!', (address,))
mw.writeLog("防火墙管理", msg)
@@ -117,15 +123,14 @@ class firewall_api:
address = port
if self.__isUfw:
mw.execShell('ufw delete deny from ' + address + ' to any')
elif self.__isIptables:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
elif self.__isFirewalld:
mw.execShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
else:
if self.__isFirewalld:
mw.execShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
elif self.__isMac:
pass
else:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
pass
msg = mw.getInfo('解除IP[{1}]的屏蔽!', (address,))
mw.writeLog("防火墙管理", msg)
@@ -144,15 +149,16 @@ class firewall_api:
return mw.returnJson(False, '失败,不能删除当前面板端口!')
if self.__isUfw:
mw.execShell('ufw delete allow ' + port + '/tcp')
elif self.__isIptables:
mw.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
elif self.__isFirewalld:
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
else:
if self.__isFirewalld:
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
else:
mw.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
pass
msg = mw.getInfo('删除防火墙放行端口[{1}]成功!', (port,))
mw.writeLog("防火墙管理", msg)
mw.M('firewall').where("id=?", (sid,)).delete()
@@ -249,24 +255,15 @@ class firewall_api:
conf = re.sub(rep, "Port " + port + "\n", conf)
mw.writeFile(file, conf)
if self.__isFirewalld:
mw.execShell('setenforce 0')
mw.execShell(
'sed -i "s#SELINUX=enforcing#SELINUX=disabled#" /etc/selinux/config')
mw.execShell("systemctl restart sshd.service")
elif self.__isUfw:
mw.execShell('ufw allow ' + port + '/tcp')
self.addAcceptPortArgs(port, 'SSH端口修改', 'port')
if self.__isUfw:
mw.execShell("service ssh restart")
else:
mw.execShell(
'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
elif self.__isIptables:
mw.execShell("/etc/init.d/sshd restart")
self.firewallReload()
# mw.M('firewall').where(
# "ps=?", ('SSH远程管理服务',)).setField('port', port)
msg = "改SSH端口为[{}]成功!".format(port)
mw.writeLog("防火墙管理", msg)
elif self.__isFirewalld:
mw.execShell("systemctl restart sshd.service")
else:
return mw.returnJson(False, '修改失败!')
return mw.returnJson(True, '修改成功!')
def setSshStatusApi(self):
@@ -349,10 +346,11 @@ class firewall_api:
mw.execShell('service iptables stop')
else:
# 重新导入数据
_list = mw.M('firewall').field('id,port,ps,addtime').limit(
'0,1000').order('id desc').select()
mw.execShell('iptables -P INPUT DROP')
mw.execShell('iptables -P OUTPUT ACCEPT')
for x in _list:
port = x['port']
if mw.isIpAddr(port):
@@ -365,26 +363,28 @@ class firewall_api:
mw.execShell('service iptables start')
def setFw(self, status):
if self.__isIptables:
self.setFwIptables(status)
return mw.returnData(True, '设置成功!')
if status == '1':
if self.__isUfw:
mw.execShell('/usr/sbin/ufw disable')
if self.__isFirewalld:
elif self.__isFirewalld:
mw.execShell('systemctl stop firewalld.service')
mw.execShell('systemctl disable firewalld.service')
elif self.__isMac:
pass
else:
self.setFwIptables(status)
pass
else:
if self.__isUfw:
mw.execShell("echo 'y'| ufw enable")
if self.__isFirewalld:
elif self.__isFirewalld:
mw.execShell('systemctl start firewalld.service')
mw.execShell('systemctl enable firewalld.service')
elif self.__isMac:
pass
else:
self.setFwIptables(status)
pass
return mw.returnData(True, '设置成功!')
@@ -438,27 +438,28 @@ class firewall_api:
def addAcceptPort(self, port):
if self.__isUfw:
mw.execShell('ufw allow ' + port + '/tcp')
elif self.__isIptables:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
mw.execShell(cmd)
elif self.__isFirewalld:
port = port.replace(':', '-')
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
mw.execShell(cmd)
elif self.__isMac:
pass
else:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
mw.execShell(cmd)
pass
return True
def firewallReload(self):
if self.__isUfw:
mw.execShell('/usr/sbin/ufw reload')
return
if self.__isFirewalld:
mw.execShell('firewall-cmd --reload')
elif self.__isMac:
pass
else:
elif self.__isIptables:
mw.execShell('service iptables save')
mw.execShell('service iptables restart')
elif self.__isFirewalld:
mw.execShell('firewall-cmd --reload')
else:
pass
def getFwStatus(self):
if self.__isUfw:
@@ -467,17 +468,17 @@ class firewall_api:
if data[0].strip() == 'inactive':
return False
return True
if self.__isFirewalld:
cmd = "ps -ef|grep firewalld |grep -v grep | awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
return False
return True
elif self.__isMac:
return False
else:
elif self.__isIptables:
cmd = "systemctl status iptables | grep 'inactive'"
data = mw.execShell(cmd)
if data[0] != '':
return False
return True
elif self.__isFirewalld:
cmd = "ps -ef|grep firewalld |grep -v grep | awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
return False
return True
else:
return False
+127 -9
View File
@@ -454,16 +454,30 @@ def getDate():
return time.strftime('%Y-%m-%d %X', time.localtime())
def getDataFromInt(val):
time_format = '%Y-%m-%d %H:%M:%S'
time_str = time.localtime(val)
return time.strftime(time_format, time_str)
def writeLog(stype, msg, args=()):
# 写日志
try:
import time
import db
import json
from flask import session
uid = 1
if 'uid' in session:
uid = session['uid']
return writeDbLog(stype, msg, args, uid)
except Exception as e:
print(getTracebackInfo())
return False
def writeDbLog(stype, msg, args=(), uid=1):
try:
import time
import db
import json
sql = db.Sql()
mdate = time.strftime('%Y-%m-%d %X', time.localtime())
wmsg = getInfo(msg, args)
@@ -565,28 +579,37 @@ def dePunycode(domain):
def enCrypt(key, strings):
# 加密字符串
try:
import base64
_key = md5(key).encode('utf-8')
_key = base64.urlsafe_b64encode(_key)
if type(strings) != bytes:
strings = strings.encode('utf-8')
import cryptography
from cryptography.fernet import Fernet
f = Fernet(key)
f = Fernet(_key)
result = f.encrypt(strings)
return result.decode('utf-8')
except:
# print(get_error_info())
print(getTracebackInfo())
return strings
def deCrypt(key, strings):
# 解密字符串
try:
import base64
_key = md5(key).encode('utf-8')
_key = base64.urlsafe_b64encode(_key)
if type(strings) != bytes:
strings = strings.decode('utf-8')
strings = strings.encode('utf-8')
from cryptography.fernet import Fernet
f = Fernet(key)
f = Fernet(_key)
result = f.decrypt(strings).decode('utf-8')
return result
except:
# print(get_error_info())
print(getTracebackInfo())
return strings
@@ -1267,6 +1290,10 @@ def toSize(size):
return str(round(size, 2)) + ' ' + b
def getPathSuffix(path):
return os.path.splitext(path)[-1]
def getMacAddress():
# 获取mac
import uuid
@@ -1475,8 +1502,95 @@ def getMyORMDb():
o = ormDb.ORM()
return o
##################### ssh start #########################################
def getSshDir():
if isAppleSystem():
user = execShell("who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
return '/Users/' + user + '/.ssh'
return '/root/.ssh'
def createRsa():
# ssh-keygen -t rsa -P "" -C "midoks@163.com"
ssh_dir = getSshDir()
# mw.execShell("rm -f /root/.ssh/*")
if not os.path.exists(ssh_dir + '/authorized_keys'):
execShell('touch ' + ssh_dir + '/authorized_keys')
if not os.path.exists(ssh_dir + '/id_rsa.pub') and os.path.exists(ssh_dir + '/id_rsa'):
execShell('echo y | ssh-keygen -q -t rsa -P "" -f ' +
ssh_dir + '/id_rsa')
else:
execShell('ssh-keygen -q -t rsa -P "" -f ' + ssh_dir + '/id_rsa')
execShell('cat ' + ssh_dir + '/id_rsa.pub >> ' +
ssh_dir + '/authorized_keys')
execShell('chmod 600 ' + ssh_dir + '/authorized_keys')
def createSshInfo():
ssh_dir = getSshDir()
if not os.path.exists(ssh_dir + '/id_rsa') or not os.path.exists(ssh_dir + '/id_rsa.pub'):
createRsa()
# 检查是否写入authorized_keys
data = execShell("cat " + ssh_dir + "/id_rsa.pub | awk '{print $3}'")
if data[0] != "":
cmd = "cat " + ssh_dir + "/authorized_keys | grep " + data[0]
ak_data = execShell(cmd)
if ak_data[0] == "":
cmd = 'cat ' + ssh_dir + '/id_rsa.pub >> ' + ssh_dir + '/authorized_keys'
execShell(cmd)
execShell('chmod 600 ' + ssh_dir + '/authorized_keys')
def connectSsh():
import paramiko
ssh = paramiko.SSHClient()
createSshInfo()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
port = getSSHPort()
try:
ssh.connect('127.0.0.1', port, timeout=5)
except Exception as e:
ssh.connect('localhost', port, timeout=5)
except Exception as e:
ssh.connect(getHostAddr(), port, timeout=30)
except Exception as e:
return False
shell = ssh.invoke_shell(term='xterm', width=83, height=21)
shell.setblocking(0)
return shell
def clearSsh():
# 服务器IP
ip = getHostAddr()
sh = '''
#!/bin/bash
PLIST=`who | grep localhost | awk '{print $2}'`
for i in $PLIST
do
ps -t /dev/$i |grep -v TTY | awk '{print $1}' | xargs kill -9
done
# getHostAddr
PLIST=`who | grep "${ip}" | awk '{print $2}'`
for i in $PLIST
do
ps -t /dev/$i |grep -v TTY | awk '{print $1}' | xargs kill -9
done
'''
if not isAppleSystem():
info = execShell(sh)
print(info[0], info[1])
##################### ssh end #########################################
# ---------------------------------------------------------------------------------
# 打印相关
# 打印相关 START
# ---------------------------------------------------------------------------------
@@ -1495,3 +1609,7 @@ def echoEnd(tag):
def echoInfo(msg):
print("|-{}".format(msg))
# ---------------------------------------------------------------------------------
# 打印相关 END
# ---------------------------------------------------------------------------------
+79 -15
View File
@@ -27,7 +27,7 @@ import sys
import threading
import multiprocessing
from flask import render_template
from flask import request
@@ -75,12 +75,35 @@ class plugins_api:
data = self.getPluginList(sType, int(sPage))
return mw.getJson(data)
def menuGetAbsPath(self, tag, path):
if path[0:1] == '/':
return path
else:
return mw.getPluginDir() + '/' + tag + '/' + path
def menuApi(self):
import config_api
data = config_api.config_api().get()
tag = request.args.get('tag', '')
menu_file = 'data/hook_menu.json'
content = ''
if os.path.exists(menu_file):
t = mw.readFile(menu_file)
tlist = json.loads(t)
for menu_data in tlist:
if 'path' in menu_data:
tpath = self.menuGetAbsPath(tag, menu_data['path'])
content = mw.readFile(tpath)
data['plugin_content'] = content
return render_template('plugin_menu.html', data=data)
def fileApi(self):
name = request.args.get('name', '')
if name.strip() == '':
return ''
f = request.args.get('f', '')
if f.strip() == '':
return ''
@@ -88,8 +111,16 @@ class plugins_api:
if not os.path.exists(file):
return ''
c = open(file, 'rb').read()
return c
suffix = mw.getPathSuffix(file)
if suffix == '.css':
content = mw.readFile(file)
from flask import Response
from flask import make_response
v = Response(content, headers={
'Content-Type': 'text/css; charset="utf-8"'})
return make_response(v)
content = open(file, 'rb').read()
return content
def indexListApi(self):
data = self.getIndexList()
@@ -214,10 +245,7 @@ class plugins_api:
isNeedAdd = False
if isNeedAdd:
tmp = {}
tmp['title'] = info['title']
tmp['name'] = info['name']
data.append(tmp)
data.append(info)
mw.writeFile(hookPath, json.dumps(data))
def hookUninstallFile(self, hook_name, info):
@@ -233,21 +261,39 @@ class plugins_api:
mw.writeFile(hookPath, json.dumps(data))
def hookInstall(self, info):
valid_hook = ['backup', 'database']
valid_list_hook = ['menu']
if 'hook' in info:
hooks = info['hook']
for x in hooks:
if x in ['backup', 'database']:
self.hookInstallFile(x, info)
return True
for h in hooks:
hooks_type = type(h)
if hooks_type == dict:
tag = h['tag']
if tag in valid_list_hook:
self.hookInstallFile(tag, h[tag])
elif hooks_type == str:
for x in hooks:
if x in valid_hook:
self.hookInstallFile(x, info)
return True
return False
def hookUninstall(self, info):
valid_hook = ['backup', 'database']
valid_list_hook = ['menu']
if 'hook' in info:
hooks = info['hook']
for x in hooks:
if x in ['backup', 'database']:
self.hookUninstallFile(x, info)
return True
for h in hooks:
hooks_type = type(h)
if hooks_type == dict:
tag = h['tag']
if tag in valid_list_hook:
self.hookUninstallFile(tag, h[tag])
elif hooks_type == str:
for x in hooks:
if x in valid_hook:
self.hookUninstallFile(x, info)
return True
return False
def uninstallOldApi(self):
@@ -618,6 +664,7 @@ class plugins_api:
"ps": info['ps'],
"dependnet": "",
"mutex": "",
"icon": "",
"path": path,
"install_checks": checks,
"uninsatll_checks": checks,
@@ -632,6 +679,9 @@ class plugins_api:
"uninstall_pre_inspection": False,
}
if 'icon' in info:
pInfo['icon'] = info['icon']
if checks.find('VERSION') > -1:
pInfo['install_checks'] = checks.replace(
'VERSION', info['versions'])
@@ -677,6 +727,7 @@ class plugins_api:
def makeList(self, data, sType='0'):
plugins_info = []
# 相应类型
if (data['pid'] == sType):
if type(data['versions']) == list and 'coexist' in data and data['coexist']:
tmp_data = self.makeCoexist(data)
@@ -687,6 +738,7 @@ class plugins_api:
plugins_info.append(pg)
return plugins_info
# 全部
if sType == '0':
if type(data['versions']) == list and 'coexist' in data and data['coexist']:
tmp_data = self.makeCoexist(data)
@@ -696,6 +748,18 @@ class plugins_api:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# 已经安装
if sType == '-1':
if type(data['versions']) == list and 'coexist' in data and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
if tmp_data[index]['setup']:
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
if pg['setup']:
plugins_info.append(pg)
# print plugins_info, data
return plugins_info
+28 -1
View File
@@ -1243,7 +1243,18 @@ class site_api:
opid = mw.M('domain').where(
"name=? AND (port=? OR pid=?)", (domain_name, domain_port, pid,)).getField('pid')
if opid > 0:
# print(opid)
is_bind = False
if type(opid) == list and len(opid) > 0:
is_bind = True
if type(opid) == int and opid > 0:
is_bind = True
if type(opid) == str and int(opid) > 0:
is_bind = True
if is_bind:
return mw.returnJson(False, '您添加的域名[{}],已绑定!'.format(domain_name))
# if mw.M('sites').where('id=?', (opid,)).count():
# return mw.returnJson(False, '指定域名已绑定过!')
@@ -2577,6 +2588,22 @@ location ^~ {from} {\n\
mw.execShell('rm -rf ' + ssl_acme_dir)
mw.M('sites').where("id=?", (sid,)).delete()
# binding domain delete
binding_list = mw.M('binding').field(
'id,domain').where("pid=?", (sid,)).select()
for x in binding_list:
wlog = mw.getLogsDir() + "/" + webname + "_" + x['domain'] + ".log"
wlog_error = mw.getLogsDir() + "/" + webname + "_" + \
x['domain'] + ".error.log"
if os.path.exists(wlog):
mw.execShell('rm -rf ' + wlog)
if os.path.exists(wlog_error):
mw.execShell('rm -rf ' + wlog_error)
mw.M('binding').where("pid=?", (sid,)).delete()
mw.restartWeb()
return mw.returnJson(True, '站点删除成功!')
+456
View File
@@ -0,0 +1,456 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# SSH终端操作
# ---------------------------------------------------------------------------------
import json
import time
import os
import sys
import socket
import threading
import re
from io import BytesIO, StringIO
import mw
import paramiko
from flask_socketio import SocketIO, emit, send
class ssh_terminal:
__debug_file = 'logs/terminal.log'
__log_type = 'SSH终端'
# websocketio 唯一标识
__sid = ''
__host = None
__type = '0'
__port = 22
__user = None
__pass = None
__pkey = None
__key_passwd = None
__rep_ssh_config = False
__rep_ssh_service = False
__sshd_config_backup = None
__ssh = None
__tp = None
__ps = None
__ssh_list = {}
__ssh_last_request_time = {}
def __init__(self):
ht = threading.Thread(target=self.heartbeat)
ht.start()
def debug(self, msg):
msg = "{} - {}:{} => {} \n".format(mw.formatDate(),
self.__host, self.__port, msg)
if not mw.isDebugMode():
return
mw.writeFile(self.__debug_file, msg, 'a+')
def returnMsg(self, status, msg):
return {'status': status, 'msg': msg}
def restartSsh(self, act='reload'):
'''
重启ssh 无参数传递
'''
version = mw.readFile('/etc/redhat-release')
if not os.path.exists('/etc/redhat-release'):
mw.execShell('service ssh ' + act)
elif version.find(' 7.') != -1 or version.find(' 8.') != -1:
mw.execShell("systemctl " + act + " sshd.service")
else:
mw.execShell("/etc/init.d/sshd " + act)
def isRunning(self, rep=False):
try:
if rep and self.__rep_ssh_service:
self.restartSsh('stop')
return True
status = self.getSshStatus()
if not status:
self.restartSsh('start')
self.__rep_ssh_service = True
return True
return False
except:
return False
def setSshdConfig(self, rep=False):
self.isRunning(rep)
if rep and not self.__rep_ssh_config:
return False
try:
sshd_config_file = '/etc/ssh/sshd_config'
if not os.path.exists(sshd_config_file):
return False
sshd_config = mw.readFile(sshd_config_file)
if not sshd_config:
return False
if rep:
if self.__sshd_config_backup:
mw.writeFile(sshd_config_file, self.__sshd_config_backup)
self.restartSsh()
return True
pin = r'^\s*PubkeyAuthentication\s+(yes|no)'
pubkey_status = re.findall(pin, sshd_config, re.I)
if pubkey_status:
if pubkey_status[0] == 'yes':
pubkey_status = True
else:
pubkey_status = False
pin = r'^\s*RSAAuthentication\s+(yes|no)'
rsa_status = re.findall(pin, sshd_config, re.I)
if rsa_status:
if rsa_status[0] == 'yes':
rsa_status = True
else:
rsa_status = False
self._sshd_config_backup = sshd_config
is_write = False
if not pubkey_status:
sshd_config = re.sub(
r'\n#?PubkeyAuthentication\s\w+', '\nPubkeyAuthentication yes', sshd_config)
is_write = True
if not rsa_status:
sshd_config = re.sub(
r'\n#?RSAAuthentication\s\w+', '\nRSAAuthentication yes', sshd_config)
is_write = True
if is_write:
mw.writeFile(sshd_config_file, sshd_config)
self.__rep_ssh_config = True
self.restartSsh()
else:
self.__sshd_config_backup = None
return True
except:
return False
def setSid(self, sid):
self.__sid = sid
def connect(self, sid):
# self.connectBySocket()
if self.__host in ['127.0.0.1', 'localhost']:
return self.connectLocalSsh(sid)
else:
return self.connectBySocket(sid)
def connectLocalSsh(self, sid):
mw.createSshInfo()
self.__ps = paramiko.SSHClient()
self.__ps.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.__port = mw.getSSHPort()
try:
self.__ps.connect(self.__host, self.__port, timeout=60)
except Exception as e:
self.__ps.connect('127.0.0.1', self.__port)
except Exception as e:
self.__ps.connect('localhost', self.__port)
except Exception as e:
self.setSshdConfig(True)
self.__ps.close()
e = str(e)
if e.find('websocket error!') != -1:
return self.returnMsg(True, '连接成功')
if e.find('Authentication timeout') != -1:
self.debug("认证超时{}".format(e))
return self.returnMsg(False, '认证超时,请按回车重试!{}'.format(e))
if e.find('Connection reset by peer') != -1:
self.debug('目标服务器主动拒绝连接')
return self.returnMsg(False, '目标服务器主动拒绝连接')
if e.find('Error reading SSH protocol banner') != -1:
self.debug('协议头响应超时')
return self.returnMsg(False, '协议头响应超时,与目标服务器之间的网络质量太糟糕:' + e)
if not e:
self.debug('SSH协议握手超时')
return self.returnMsg(False, "SSH协议握手超时,与目标服务器之间的网络质量太糟糕")
err = mw.getTracebackInfo()
self.debug(err)
return self.returnMsg(False, "未知错误: {}".format(err))
self.debug('local-ssh:认证成功,正在构建会话通道')
ssh = self.__ps.invoke_shell(
term='xterm', width=83, height=21)
ssh.setblocking(0)
self.__ssh_list[sid] = ssh
mw.writeLog(self.__log_type, '成功登录到SSH服务器 [{}:{}]'.format(
self.__host, self.__port))
self.debug('local-ssh:通道已构建')
return self.returnMsg(True, '连接成功!')
def connectBySocket(self, sid):
if not self.__host:
return self.returnMsg(False, '错误的连接地址')
if not self.__user:
self.__user = 'root'
if not self.__port:
self.__port = 22
self.setSshdConfig(True)
num = 0
while num < 5:
num += 1
try:
self.debug('正在尝试第{}次连接'.format(num))
if self.__rep_ssh_config:
time.sleep(0.1)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2 + num)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 8192)
sock.connect((self.__host, self.__port))
break
except Exception as e:
if num == 5:
self.setSshdConfig(True)
self.debug('重试连接失败,{}'.format(e))
return self.returnMsg(False, '连接目标服务器失败, {}:{}'.format(self.__host, self.__port))
else:
time.sleep(0.2)
# print(self.__host, sock)
self.__tp = paramiko.Transport(sock)
try:
self.__tp.start_client()
self.__tp.banner_timeout = 60
if not self.__pass and not self.__pkey:
return self.returnMsg(False, '密码或私钥不能都为空: {}:{}'.format(self.__host, self.__port))
if self.__pkey != '' and self.__type != '0':
self.debug('正在认证私钥')
p_file = StringIO(str(self.__pkey.replace('\\n', '\n')))
# p_file = "/tmp/t_ssh_pkey.txt"
# mw.writeFile(p_file, self.__pkey.replace('\\n', '\n'))
# mw.execShell('chmod 600 ' + p_file)
try:
p_file.seek(0)
pkey = paramiko.RSAKey.from_private_key(p_file)
except:
try:
p_file.seek(0) # 重置游标
pkey = paramiko.Ed25519Key.from_private_key(
p_file)
except:
try:
p_file.seek(0)
pkey = paramiko.ECDSAKey.from_private_key(p_file)
except:
p_file.seek(0)
pkey = paramiko.DSSKey.from_private_key(p_file)
self.__tp.auth_publickey(username=self.__user, key=pkey)
else:
try:
self.__tp.auth_none(self.__user)
except Exception as e:
e = str(e)
if e.find('keyboard-interactive') >= 0:
self._auth_interactive()
else:
self.debug('正在认证密码')
self.__tp.auth_password(
username=self.__user, password=self.__pass)
except Exception as e:
self.setSshdConfig(True)
self.__tp.close()
e = str(e)
# print(e)
if e.find('Authentication timeout') != -1:
self.debug("认证超时{}".format(e))
return self.returnMsg(False, '认证超时,请按回车重试!{}'.format(e))
if e.find('Authentication failed') != -1:
self.debug('认证失败{}'.format(e))
return self.returnMsg(False, '帐号或密码错误: {}'.format(e + "," + self.__user + "@" + self.__host + ":" + str(self.__port)))
if e.find('Bad authentication type; allowed types') != -1:
self.debug('认证失败{}'.format(e))
if self.__host in ['127.0.0.1', 'localhost'] and self.__pass == 'none':
return self.returnMsg(False, '帐号或密码错误: {}'.format("Authentication failed ," + self.__user + "@" + self.__host + ":" + str(self.__port)))
return self.returnMsg(False, '不支持的身份验证类型: {}'.format(e))
if e.find('Connection reset by peer') != -1:
self.debug('目标服务器主动拒绝连接')
return self.returnMsg(False, '目标服务器主动拒绝连接')
if e.find('Error reading SSH protocol banner') != -1:
self.debug('协议头响应超时')
return self.returnMsg(False, '协议头响应超时,与目标服务器之间的网络质量太糟糕:' + e)
if not e:
self.debug('SSH协议握手超时')
return self.returnMsg(False, "SSH协议握手超时,与目标服务器之间的网络质量太糟糕")
err = mw.getTracebackInfo()
self.debug(err)
return self.returnMsg(False, "未知错误: {}".format(err))
self.debug('认证成功,正在构建会话通道')
ssh = self.__tp.open_session()
ssh.get_pty(term='xterm', width=100, height=34)
ssh.invoke_shell()
self.__ssh_list[sid] = ssh
mw.writeLog(self.__log_type, '成功登录到SSH服务器 [{}:{}]'.format(
self.__host, self.__port))
self.debug('通道已构建')
return self.returnMsg(True, '连接成功.')
def getSshInfo(self, file):
rdata = mw.readFile(file)
destr = mw.deCrypt('mdserver-web', rdata)
return json.loads(destr)
def setAttr(self, sid, info):
self.__host = info['host'].strip()
# 外部连接获取
if not self.__host in ['127.0.0.1', 'localhost']:
dst_info = mw.getServerDir() + '/webssh/host/' + self.__host + '/info.json'
if os.path.exists(dst_info):
info = self.getSshInfo(dst_info)
if 'type' in info:
self.__type = info['type']
if 'port' in info:
self.__port = int(info['port'])
if 'username' in info:
self.__user = info['username']
if 'pkey' in info:
self.__pkey = info['pkey']
if 'password' in info:
self.__pass = info['password']
if 'pkey_passwd' in info:
self.__key_passwd = info['pkey_passwd']
# print(self.__host, self.__pass, self.__key_passwd)
try:
result = self.connect(sid)
# print(result)
except Exception as ex:
if str(ex).find("NoneType") == -1:
raise ex
return result
def send(self):
pass
def close(self):
try:
if self.__ssh:
self.__ssh.close()
if self.__tp: # 关闭宿主服务
self.__tp.close()
if self.__ps:
self.__ps.close()
except:
pass
def resize(self, sid, data):
try:
self.__ssh_list[sid].resize_pty(
width=data['cols'], height=data['rows'])
return True
except:
return False
def wsSend(self, recv):
try:
t = recv.decode("utf-8")
return emit('server_response', {'data': t})
except Exception as e:
return emit('server_response', {'data': recv})
def wsSendConnect(self):
return emit('connect', {'data': 'ok'})
def wsSendReConnect(self):
return emit('reconnect', {'data': 'ok'})
def heartbeat(self):
# limit_cos = 10
while True:
time.sleep(3)
cur_time = time.time()
for x in list(self.__ssh_list.keys()):
ssh_last_time = self.__ssh_last_request_time[x]
sid_off_cos = cur_time - ssh_last_time
# print("heartbeat off cos :", x, sid_off_cos)
if sid_off_cos > 3:
cur_ssh = self.__ssh_list[x]
if not cur_ssh:
del(self.__ssh_list[x])
del(self.__ssh_last_request_time[x])
continue
if cur_ssh.exit_status_ready():
del(self.__ssh_list[x])
del(self.__ssh_last_request_time[x])
continue
cur_ssh.send("exit\r\n")
del(self.__ssh_list[x])
del(self.__ssh_last_request_time[x])
def run(self, sid, info):
self.__sid = sid
if not self.__sid:
return self.wsSend('WebSocketIO无效')
self.__ssh_last_request_time[sid] = time.time()
if not sid in self.__ssh_list:
if type(info) == dict and 'host' in info:
result = self.setAttr(sid, info)
if result['status']:
return self.wsSendConnect()
else:
return self.wsSend(result['msg'])
else:
return self.wsSendReConnect()
result = self.returnMsg(False, '')
if sid in self.__ssh_list:
if 'resize' in info:
self.resize(sid, info)
result = self.returnMsg(True, '已连接')
if result['status']:
if type(info) == str:
time.sleep(0.1)
cur_ssh = self.__ssh_list[sid]
if cur_ssh.exit_status_ready():
self.wsSend("logout\r\n")
del(self.__ssh_list[sid])
return
cur_ssh.send(info)
try:
time.sleep(0.005)
recv = cur_ssh.recv(8192)
return self.wsSend(recv)
except Exception as ex:
return self.wsSend('')
else:
return self.wsSend(result['msg'])
+6 -1
View File
@@ -43,7 +43,12 @@ mw_start(){
mw_start_debug(){
python3 task.py >> $DIR/logs/task.log 2>&1 &
gunicorn -b :7200 -k gevent -w 1 app:app
port=7200
if [ -f /www/server/mdserver-web/data/port.pl ];then
port=$(cat /www/server/mdserver-web/data/port.pl)
fi
# gunicorn -b :${port} -k gevent -w 1 app:app
gunicorn -b :${port} -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
}
mw_start_debug2(){
+5
View File
@@ -4,6 +4,11 @@
"type":0,
"ps":""
},
{
"title":"已安装",
"type":-1,
"ps":""
},
{
"title":"运行环境",
"type":1,
+1 -1
View File
@@ -11,7 +11,7 @@
"checks":"server/backup_ftp",
"path": "server/backup_ftp",
"author":"midoks",
"home":"",
"home":"https://github.com/midoks/mdserver-web",
"date":"2022-10-23",
"pid": "4"
}
+3 -3
View File
@@ -10,8 +10,8 @@ serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=0.0.19
# bash install.sh install 0.0.16
## cd /www/server/mdserver-web/plugins/imail && bash install.sh install 0.0.16
# bash install.sh install 0.0.19
## cd /www/server/mdserver-web/plugins/imail && bash install.sh install 0.0.19
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
@@ -24,7 +24,7 @@ get_arch() {
TMP_ARCH=`arch`
if [ "$TMP_ARCH" == "x86_64" ];then
ARCH="amd64"
else if [ "$TMP_ARCH" == "aarch64" ];then
elif [ "$TMP_ARCH" == "aarch64" ];then
ARCH="arm64"
else
echo $ARCH
+1 -1
View File
@@ -797,7 +797,7 @@ function openPhpmyadmin(name,username,password){
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_cfg'});
var rdata = $.parseJSON(data.data);
if (rdata.choose != 'mariadb'){
layer.msg('当前为['+rdata.choose+']模式,若要使用请切换模式.',{icon:2,shade: [0.3, '#000']});
layer.msg('当前为['+rdata.choose+']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
return;
}
var phpmyadmin_cfg = rdata;
+2 -2
View File
@@ -104,14 +104,14 @@ rm -r /var/lib/mongodb
Install_Linux_Debian()
{
##################### debian start #####################
if [ "$SYS_VERSION_ID" -ge "11" ]; then
if [ "$SYS_VERSION_ID" -eq "11" ] && [ "$VERSION" -eq "4.4" ]; then
echo "Not yet supported"
exit 1
fi
if [ -f /usr/lib/systemd/system/mongod.service ];then
echo 'alreay exist!'
echo 'alreay install exist!'
exit 0
fi
+5 -4
View File
@@ -411,6 +411,7 @@ def my8cmd(version, method):
initDreplace(version)
# mysql 8.0 and 5.7
try:
isInited = True
if version == '5.7':
isInited = initMysql57Data()
elif version == '8.0':
@@ -483,7 +484,7 @@ def getMyDbPos():
return tmp.groups()[0].strip()
def setMyDbPos():
def setMyDbPos(version=''):
args = getArgs()
data = checkArgs(args, ['datadir'])
if not data[0]:
@@ -498,7 +499,7 @@ def setMyDbPos():
mw.execShell('mkdir -p ' + t_datadir)
# mw.execShell('/etc/init.d/mysqld stop')
stop()
stop(version)
mw.execShell('cp -rf ' + s_datadir + '/* ' + t_datadir + '/')
mw.execShell('chown -R mysql mysql ' + t_datadir)
mw.execShell('chmod -R 755 ' + t_datadir)
@@ -512,7 +513,7 @@ def setMyDbPos():
mycnf = mycnf.replace(s_datadir, t_datadir)
mw.writeFile(myfile, mycnf)
start()
restart(version)
result = mw.execShell(
'ps aux|grep mysqld| grep -v grep|grep -v python')
@@ -2733,7 +2734,7 @@ if __name__ == "__main__":
elif func == 'my_db_pos':
print(getMyDbPos())
elif func == 'set_db_pos':
print(setMyDbPos())
print(setMyDbPos(version))
elif func == 'my_port':
print(getMyPort())
elif func == 'set_my_port':
+1 -1
View File
@@ -819,7 +819,7 @@ function openPhpmyadmin(name,username,password){
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_cfg'});
var rdata = $.parseJSON(data.data);
if (rdata.choose != 'mysql-apt'){
layer.msg('当前为['+rdata.choose+']模式,若要使用请切换模式.',{icon:2,shade: [0.3, '#000']});
layer.msg('当前为['+rdata.choose+']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
return;
}
+7 -6
View File
@@ -397,6 +397,7 @@ def my8cmd(version, method):
initDreplace(version)
# mysql 8.0 and 5.7
try:
isInited = True
if version == '5.7':
isInited = initMysql57Data()
elif version == '8.0':
@@ -469,7 +470,7 @@ def getMyDbPos():
return tmp.groups()[0].strip()
def setMyDbPos():
def setMyDbPos(version=''):
args = getArgs()
data = checkArgs(args, ['datadir'])
if not data[0]:
@@ -484,7 +485,7 @@ def setMyDbPos():
mw.execShell('mkdir -p ' + t_datadir)
# mw.execShell('/etc/init.d/mysqld stop')
stop()
stop(version)
mw.execShell('cp -rf ' + s_datadir + '/* ' + t_datadir + '/')
mw.execShell('chown -R mysql mysql ' + t_datadir)
mw.execShell('chmod -R 755 ' + t_datadir)
@@ -498,17 +499,17 @@ def setMyDbPos():
mycnf = mycnf.replace(s_datadir, t_datadir)
mw.writeFile(myfile, mycnf)
start()
restart(version)
result = mw.execShell(
'ps aux|grep mysqld| grep -v grep|grep -v python')
'ps aux|grep "mysql-apt/bin/usr/sbin/mysqld"| grep -v grep|grep -v python')
if len(result[0]) > 10:
mw.writeFile('data/datadir.pl', t_datadir)
return mw.returnJson(True, '存储目录迁移成功!')
else:
mw.execShell('pkill -9 mysqld')
mw.writeFile(myfile, mw.readFile(path + '/etc/my_backup.cnf'))
start()
start(version)
return mw.returnJson(False, '文件迁移失败!')
@@ -2687,7 +2688,7 @@ if __name__ == "__main__":
elif func == 'my_db_pos':
print(getMyDbPos())
elif func == 'set_db_pos':
print(setMyDbPos())
print(setMyDbPos(version))
elif func == 'my_port':
print(getMyPort())
elif func == 'set_my_port':
+1 -1
View File
@@ -819,7 +819,7 @@ function openPhpmyadmin(name,username,password){
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_cfg'});
var rdata = $.parseJSON(data.data);
if (rdata.choose != 'mysql-yum'){
layer.msg('当前为['+rdata.choose+']模式,若要使用请切换模式.',{icon:2,shade: [0.3, '#000']});
layer.msg('当前为['+rdata.choose+']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
return;
}
+7 -7
View File
@@ -488,14 +488,14 @@ def initMysql8Pwd():
# 删除冗余账户
hostname = mw.execShell('hostname')[0].strip()
if hostname != 'localhost':
drop_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'\'@\'' + hostname + '\'";'
mw.execShell(drop_hostname)
drop_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'\'@\'' + hostname + '\'";'
mw.execShell(drop_hostname)
drop_root_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'root\'@\'' + hostname + '\'";'
mw.execShell(drop_root_hostname)
drop_root_hostname = serverdir + '/bin/mysql --defaults-file=' + \
myconf + ' -uroot -p' + pwd + ' -e "drop user \'root\'@\'' + hostname + '\'";'
mw.execShell(drop_root_hostname)
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
+1 -1
View File
@@ -819,7 +819,7 @@ function openPhpmyadmin(name,username,password){
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_cfg'});
var rdata = $.parseJSON(data.data);
if (rdata.choose != 'mysql'){
layer.msg('当前为['+rdata.choose+']模式,若要使用请切换模式.',{icon:2,shade: [0.3, '#000']});
layer.msg('当前为['+rdata.choose+']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
return;
}
+1 -8
View File
@@ -1,10 +1,3 @@
lua_shared_dict waf_limit 30m;
lua_shared_dict waf_drop_ip 10m;
lua_shared_dict waf_drop_sum 10m;
lua_package_path "{$WAF_PATH}/html/?.lua;{$WAF_PATH}/conf/?.lua;{$WAF_PATH}/lua/?.lua;{$ROOT_PATH}/openresty/lualib/?.lua;;";
lua_package_cpath "{$WAF_PATH}/conf/?.so;{$ROOT_PATH}/openresty/lualib/?.so;;";
init_worker_by_lua_file {$WAF_PATH}/lua/init_worker.lua;
access_by_lua_file {$WAF_PATH}/lua/init.lua;
# init_by_lua_file {$WAF_PATH}/lua/init.lua;
lua_shared_dict waf_drop_sum 10m;
+104 -37
View File
@@ -6,6 +6,7 @@ import os
import time
import subprocess
import json
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
@@ -228,17 +229,8 @@ def initTotalInfo():
mw.writeFile(path_total, cjson)
def status():
path = getConf()
if not os.path.exists(path):
return 'stop'
conf = mw.readFile(path)
if conf.find("#include luawaf.conf;") != -1:
return 'stop'
if conf.find("luawaf.conf;") == -1:
return 'stop'
return 'start'
def dstWafConf():
return mw.getServerDir() + "/web_conf/nginx/vhost/opwaf.conf"
def contentReplace(content):
@@ -328,7 +320,8 @@ def autoMakeConfig():
def restartWeb():
autoMakeConfig()
mw.restartWeb()
mw.opWeb('stop')
mw.opWeb('start')
def initDreplace():
@@ -370,11 +363,12 @@ def initDreplace():
content = contentReplace(content)
mw.writeFile(init_worker, content)
waf_conf = mw.getServerDir() + "/openresty/nginx/conf/luawaf.conf"
waf_tpl = getPluginDir() + "/conf/luawaf.conf"
content = mw.readFile(waf_tpl)
content = contentReplace(content)
mw.writeFile(waf_conf, content)
waf_conf = dstWafConf()
if not os.path.exists(waf_conf):
waf_tpl = getPluginDir() + "/conf/luawaf.conf"
content = mw.readFile(waf_tpl)
content = contentReplace(content)
mw.writeFile(waf_conf, content)
initDomainInfo()
initSiteInfo()
@@ -388,37 +382,61 @@ def initDreplace():
mw.execShell("chown -R www:www " + path)
def status():
path = getConf()
if not os.path.exists(path):
return 'stop'
waf_conf = dstWafConf()
if not os.path.exists(waf_conf):
return 'stop'
return 'start'
def start():
initDreplace()
path = getConf()
path = mw.getServerDir() + '/web_conf/nginx/lua/lua.conf'
init_worker_lua = getServerDir() + '/waf/lua/init_worker.lua'
init_lua = getServerDir() + '/waf/lua/init.lua'
conf = mw.readFile(path)
conf = conf.replace('#include luawaf.conf;', "include luawaf.conf;")
conf = re.sub('init_worker_by_lua_file (.*);',
"init_worker_by_lua_file " + init_worker_lua + ";", conf)
conf = re.sub('access_by_lua_file (.*);',
"access_by_lua_file " + init_lua + ";", conf)
mw.writeFile(path, conf)
import tool_task
tool_task.createBgTask()
mw.restartWeb()
restartWeb()
return 'ok'
def stop():
path = getConf()
conf = mw.readFile(path)
conf = conf.replace('include luawaf.conf;', "#include luawaf.conf;")
path = mw.getServerDir() + '/web_conf/nginx/lua/lua.conf'
empty_lua = mw.getServerDir() + '/web_conf/nginx/lua/empty.lua'
conf = mw.readFile(path)
conf = re.sub('init_worker_by_lua_file (.*);',
"init_worker_by_lua_file " + empty_lua + ";", conf)
conf = re.sub('access_by_lua_file (.*);',
"access_by_lua_file " + empty_lua + ";", conf)
mw.writeFile(path, conf)
wafconf = dstWafConf()
if os.path.exists(wafconf):
os.remove(wafconf)
import tool_task
tool_task.removeBgTask()
mw.restartWeb()
restartWeb()
return 'ok'
def restart():
mw.restartWeb()
restartWeb()
return 'ok'
@@ -428,6 +446,18 @@ def reload():
path = getServerDir()
path_tpl = getPluginDir()
config = path + "/waf/lua/common.lua"
config_tpl = path_tpl + "/waf/lua/common.lua"
content = mw.readFile(config_tpl)
content = contentReplace(content)
mw.writeFile(config, content)
config = path + "/waf/lua/init_worker.lua"
config_tpl = path_tpl + "/waf/lua/init_worker.lua"
content = mw.readFile(config_tpl)
content = contentReplace(content)
mw.writeFile(config, content)
config = path + "/waf/lua/init.lua"
config_tpl = path_tpl + "/waf/lua/init.lua"
content = mw.readFile(config_tpl)
@@ -438,6 +468,8 @@ def reload():
mw.execShell('rm -rf ' + errlog)
start()
restartWeb()
return 'ok'
@@ -1022,24 +1054,41 @@ def removeSiteCdnHeader():
def outputData():
args = getArgs()
data = checkArgs(args, ['s_Name'])
data = checkArgs(args, ['sname'])
if not data[0]:
return data[1]
path = getRuleJsonPath(args['s_Name'])
path = getRuleJsonPath(args['sname'])
content = mw.readFile(path)
return mw.returnJson(True, 'ok', content)
def importData():
args = getArgs()
data = checkArgs(args, ['s_Name', 'pdata'])
data = checkArgs(args, ['sname', 'pdata'])
if not data[0]:
return data[1]
path = getRuleJsonPath(args['s_Name'])
mw.writeFile(path, args['pdata'])
restartWeb()
path = getRuleJsonPath(args['sname'])
source_data = mw.readFile(path)
source_data = json.loads(source_data)
save_data = []
save_data.append(source_data[0])
pdata = args['pdata'].strip()
try:
pdata = json.loads(pdata)
mw.writeFile(path, json.dumps(pdata))
except Exception as e:
pdata = pdata.split("\\n")
for x in pdata:
pval = x.strip()
if pval != "":
vv = json.loads(pval)
save_data.append(vv[0])
mw.writeFile(path, json.dumps(save_data))
# restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -1167,6 +1216,28 @@ def getWafConf():
return mw.readFile(conf)
def cleanDropIp():
url = "http://127.0.0.1/clean_waf_drop_ip"
data = mw.httpGet(url)
return mw.returnJson(True, 'ok!', data)
def testRun():
# args = getArgs()
# data = checkArgs(args, ['siteName'])
# if not data[0]:
# return data[1]
conf_json = getServerDir() + "/waf/default.json"
data = mw.readFile(conf_json)
pdata = json.loads(data)
default_site = pdata['default']
url = "http://" + default_site + '/?t=../etc/passwd'
returnData = mw.httpGet(url, 10)
return mw.returnJson(True, '测试运行成功!', returnData)
def installPreInspection():
check_op = mw.getServerDir() + "/openresty"
if not os.path.exists(check_op):
@@ -1174,12 +1245,6 @@ def installPreInspection():
return 'ok'
def cleanDropIp():
url = "http://127.0.0.1/clean_waf_drop_ip"
data = mw.httpGet(url)
return mw.returnJson(True, 'ok!', data)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
@@ -1268,5 +1333,7 @@ if __name__ == "__main__":
print(getWafSite())
elif func == 'clean_drop_ip':
print(cleanDropIp())
elif func == 'test_run':
print(testRun())
else:
print('error')
+1 -1
View File
@@ -12,5 +12,5 @@
"home":"https://github.com/loveshell/ngx_lua_waf",
"date":"2019-04-21",
"pid": "1",
"versions": ["0.2.3"]
"versions": ["0.2.4"]
}
+39 -21
View File
@@ -568,14 +568,14 @@ function outputLayer(rdata, name, type) {
'<div class="ml0" style="position:relative;" id="focus_tips">' +
'<textarea class="bt-input-text mr20 config" name="config" style="width: 300px; height: 250px; line-height: 22px; display: none;" id="lead_data">' + (rdata != '' ? JSON.stringify(rdata) : '') + '</textarea>' +
'<div class="placeholder c9" style="top: 15px; left: 15px; display:' + (rdata == "" ? "block;" : "none;") + '">导入格式如下:' +
(name == 'ip_white' || name == 'ip_black' ? "[[[127, 0, 0, 1],[127, 0, 0, 255]]]" : "[\"^/test\",\"^/web\"]") +
(name == 'ip_white' || name == 'ip_black' ? "[[[127, 0, 0, 1],[127, 0, 0, 255]],[[192, 0, 0, 1],[192, 0, 0, 255]]]" : "[\"^/test\",\"^/web\"]") +
'</div>' +
'</div>' +
'</div>' +
'<div class="line "><div class="ml0">' +
(type ? '<button name="btn_save_to" class="btn btn-success btn-sm mr5 btn_save_to" >导出配置</button>' : '<button name="btn_save" class="btn btn-success btn-sm mr5 btn_save">保存</button>') +
'</div></div>' +
'</div>'
'</div>',
});
var lead_error = CodeMirror.fromTextArea(document.getElementById("lead_data"), {
mode: 'html',
@@ -585,7 +585,10 @@ function outputLayer(rdata, name, type) {
});
setTimeout(function () {
$('.btn_save').on('click', function () {
importData(name, lead_error.getValue());
importData(name, lead_error.getValue(), function(){
layer.close(window.Load_layer);
ipWhiteLoadList();
});
})
$('.btn_save_to').on('click', function () {
funDownload(lead_error.getValue(), name + '.json');
@@ -601,7 +604,7 @@ function outputLayer(rdata, name, type) {
function outputData(name, callback) {
var loadT = layer.msg('正在导出数据..', { icon: 16, time: 0 });
owPost('output_data', { s_Name: name } , function(data){
owPost('output_data', { sname: name } , function(data){
var tmp = $.parseJSON(data.data);
var rdata = $.parseJSON(tmp.data);
if (callback) callback(rdata,res);
@@ -611,7 +614,7 @@ function outputData(name, callback) {
//导入数据
function importData(name, pdata, callback) {
owPost('import_data', { s_Name: name, pdata: pdata } , function(data){
owPost('import_data', { sname: name, pdata: pdata } , function(data){
var rdata = $.parseJSON(data.data);
if (callback) callback();
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
@@ -622,6 +625,22 @@ function fileInput(name) {
outputLayer('', name, false);
}
function ipWhiteLoadList(){
getRuleByName('ip_white', function(data){
var tmp = $.parseJSON(data.data);
var rdata = $.parseJSON(tmp.data);
var tbody = ''
for (var i = 0; i < rdata.length; i++) {
tbody += '<tr>\
<td>'+ rdata[i][0].join('.') + '</td>\
<td>'+ rdata[i][1].join('.') + '</td>\
<td class="text-right"><a class="btlink" onclick="removeIpWhite('+ i + ')">删除</a></td>\
</tr>'
}
$("#ip_white_con").html(tbody);
});
}
//IP白名单
function ipWhite(type) {
if (type == undefined) {
@@ -675,20 +694,7 @@ function ipWhite(type) {
});
tableFixed("ipWhite");
}
getRuleByName('ip_white', function(data){
var tmp = $.parseJSON(data.data);
var rdata = $.parseJSON(tmp.data);
var tbody = ''
for (var i = 0; i < rdata.length; i++) {
tbody += '<tr>\
<td>'+ rdata[i][0].join('.') + '</td>\
<td>'+ rdata[i][1].join('.') + '</td>\
<td class="text-right"><a class="btlink" onclick="removeIpWhite('+ i + ')">删除</a></td>\
</tr>'
}
$("#ip_white_con").html(tbody);
});
ipWhiteLoadList();
}
//IP白名单
@@ -1712,9 +1718,12 @@ function wafLogs(){
<button data-name="l7" type="button" class="btn btn-default">近7天</button>\
<button data-name="l30" type="button" class="btn btn-default">近30天</button>\
</div>\
<span class="last-span"><input data-name="" type="text" id="time_choose" lay-key="1000001_'+randstr+'" class="form-control btn-group-sm" autocomplete="off" placeholder="自定义时间" style="display: inline-block;font-size: 12px;padding: 0 10px;height:30px;width: 200px;"></span>\
<span class="last-span"><input data-name="" type="text" id="time_choose" lay-key="1000001_'+randstr+'" class="form-control btn-group-sm" autocomplete="off" placeholder="自定义时间" style="display: inline-block;font-size: 12px;padding: 0 10px;height:30px;width: 155px;"></span>\
</div>\
<div style="float:right;">\
<button id="UncoverAll" class="btn btn-success btn-sm" style="padding-left: 5px;padding-right: 5px;">解封所有</button>\
<button id="testRun" class="btn btn-default btn-sm" style="padding-left: 5px;padding-right: 5px;">测试</button>\
</div>\
<div style="float:right;"><button id="UncoverAll" class="btn btn-success btn-sm">解封所有</button></div>\
</div>\
<div class="divtable mtb10" id="ws_table"></div>\
</div>';
@@ -1733,6 +1742,15 @@ function wafLogs(){
});
});
//测试demo
$("#testRun").click(function(){
owPost('test_run',{},function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg, function(){
wafLogRequest(1);
},{icon:1,shade: [0.3, '#000']},2000);
});
});
//日期范围
laydate.render({
+7 -6
View File
@@ -309,12 +309,12 @@ def test_Upload():
def test_start():
# test_OK()
# test_Dir()
test_Dir()
# test_UA()
test_Header()
# test_Header()
# test_UA_for(1000)
test_POST()
test_scan()
# test_POST()
# test_scan()
# test_CC()
# test_url_ext()
# test_cdn()
@@ -322,6 +322,7 @@ def test_start():
if __name__ == "__main__":
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf && sh install.sh uninstall 0.2.2 && sh install.sh install 0.2.2')
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/ && python3 plugins/openresty/index.py stop && python3 plugins/openresty/index.py start')
# os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf && sh install.sh uninstall 0.2.2 && sh install.sh install 0.2.2')
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/ && python3 /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf/index.py reload')
# os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/ && python3 plugins/openresty/index.py stop && python3 plugins/openresty/index.py start')
test_start()
+14 -4
View File
@@ -1,3 +1,14 @@
local waf_root = "{$WAF_ROOT}"
local waf_cpath = waf_root.."/waf/lua/?.lua;"..waf_root.."/waf/conf/?.lua;"..waf_root.."/waf/html/?.lua;"
local waf_sopath = waf_root.."/waf/conf/?.so;"
if not package.path:find(waf_cpath) then
package.path = waf_cpath .. package.path
end
if not package.cpath:find(waf_sopath) then
package.cpath = waf_sopath .. package.cpath
end
local setmetatable = setmetatable
local _M = { _VERSION = '0.02' }
@@ -9,7 +20,6 @@ local sqlite3 = require "lsqlite3"
local ngx_match = ngx.re.find
local debug_mode = false
local waf_root = "{$WAF_ROOT}"
local cpath = waf_root.."/waf/"
local log_dir = waf_root.."/logs/"
local rpath = cpath.."/rule/"
@@ -62,12 +72,12 @@ end
-- 后台任务
function _M.cron(self)
local timer_every_get_data = function (premature)
self.clean_log()
local timer_every_get_data = function(premature)
self:clean_log()
end
ngx.timer.every(10, timer_every_get_data)
local timer_every_import_data = function (premature)
local timer_every_import_data = function(premature)
local llen, _ = ngx.shared.waf_limit:llen('waf_limit_logs')
if llen == 0 then
+15 -5
View File
@@ -1,3 +1,14 @@
local waf_root = "{$WAF_ROOT}"
local waf_cpath = waf_root.."/waf/lua/?.lua;"..waf_root.."/waf/conf/?.lua;"..waf_root.."/waf/html/?.lua;"
local waf_sopath = waf_root.."/waf/conf/?.so;"
if not package.path:find(waf_cpath) then
package.path = waf_cpath .. package.path
end
if not package.cpath:find(waf_sopath) then
package.cpath = waf_sopath .. package.cpath
end
local json = require "cjson"
local ngx_match = ngx.re.find
@@ -11,11 +22,11 @@ local config = require "waf_config"
local site_config = require "waf_site"
local config_domains = require "waf_domains"
-- C:D("config:"..C:to_json(config))
C:setConfData(config, site_config)
C:setDebug(true)
-- C:D("config:"..C:to_json(config))
local get_html = require "html_get"
local post_html = require "html_post"
@@ -246,7 +257,8 @@ local function waf_drop_ip()
end
local function waf_cc()
if not config['cc']['open'] or not C:is_site_config('cc') then return false end
if not config['cc']['open'] then return false end
if not C:is_site_config('cc') then return false end
local ip = params['ip']
@@ -521,7 +533,6 @@ end
function waf()
min_route()
-- white ip
if waf_ip_white() then return true end
@@ -550,9 +561,8 @@ function waf()
-- 扫描软件禁止
if waf_scan_black() then return true end
if waf_post() then return true end
if site_config[server_name] and site_config[server_name]['open'] then
if X_Forwarded() then return true end
if post_X_Forwarded() then return true end
+11 -4
View File
@@ -1,13 +1,20 @@
local waf_root = "{$WAF_ROOT}"
local waf_cpath = waf_root.."/waf/lua/?.lua;"..waf_root.."/waf/conf/?.lua;"..waf_root.."/waf/html/?.lua;"
local waf_sopath = waf_root.."/waf/conf/?.so;"
if not package.path:find(waf_cpath) then
package.path = waf_cpath .. package.path
end
if not package.cpath:find(waf_sopath) then
package.cpath = waf_sopath .. package.cpath
end
local json = require "cjson"
local waf_root = "{$WAF_ROOT}"
local cpath = waf_root.."/waf/"
local __C = require "common"
local C = __C:getInstance()
local function timer_stats_total_log(premature)
C:timer_stats_total()
end
+10
View File
@@ -0,0 +1,10 @@
lua_package_path "{$SERVER_PATH}/web_conf/nginx/lua/?.lua;{$SERVER_PATH}/openresty/lualib/?.lua;;";
lua_package_cpath "{$SERVER_PATH}/web_conf/nginx/lua/?.so;{$SERVER_PATH}/openresty/lualib/?.so;;";
lua_code_cache on;
#waf
init_worker_by_lua_file {$SERVER_PATH}/web_conf/nginx/lua/empty.lua;
#waf && webstats need;
access_by_lua_file {$SERVER_PATH}/web_conf/nginx/lua/empty.lua;
+2 -1
View File
@@ -16,7 +16,7 @@ http
{
include mime.types;
#include luawaf.conf;
include {$SERVER_PATH}/web_conf/nginx/lua/lua.conf;
#include proxy.conf;
default_type application/octet-stream;
@@ -28,6 +28,7 @@ http
server_names_hash_bucket_size 512;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_body_buffer_size 50m;
client_max_body_size 50m;
sendfile on;
+24
View File
@@ -131,10 +131,34 @@ def confReplace():
content = content.replace('{$OS_USER}', user)
content = content.replace('{$OS_USER_GROUP}', user_group)
# ng_conf_md5 = ''
# ng_conf_md5_file = getServerDir() + '/nginx_conf.md5'
# if not os.path.exists(ng_conf_md5_file):
# ng_conf_md5 = mw.md5(content)
# mw.writeFile(ng_conf_md5_file, ng_conf_md5)
# else:
# ng_conf_md5 = mw.writeFile(ng_conf_md5_file).strip()
# 主配置文件
nconf = getServerDir() + '/nginx/conf/nginx.conf'
mw.writeFile(nconf, content)
# lua配置
lua_conf_dir = mw.getServerDir() + '/web_conf/nginx/lua'
if not os.path.exists(lua_conf_dir):
mw.execShell('mkdir -p ' + lua_conf_dir)
lua_conf = lua_conf_dir + '/lua.conf'
if not os.path.exists(lua_conf):
lua_conf_tpl = getPluginDir() + '/conf/lua.conf'
lua_content = mw.readFile(lua_conf_tpl)
lua_content = lua_content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(lua_conf, lua_content)
empty_lua = lua_conf_dir + '/empty.lua'
if not os.path.exists(empty_lua):
mw.writeFile(empty_lua, '')
# 静态配置
php_conf = mw.getServerDir() + '/web_conf/php/conf'
if not os.path.exists(php_conf):
+16 -9
View File
@@ -49,15 +49,20 @@ if [ "$OSNAME" == "ubuntu" ];then
fi
# apt install $(grep-aptavail -S PHP-defaults -s Package -n)
if [ ! -f /etc/apt/sources.list.d/php.list ] && [ "$OSNAME" == "debian" ];then
# install php source
apt update -y
apt -y install apt-transport-https lsb-release ca-certificates curl
curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
apt update -y
# install php source
apt update -y
apt -y install apt-transport-https lsb-release ca-certificates curl
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
if [ ! -z "$cn" ];then
curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://mirror.sjtu.edu.cn/sury/php/apt.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://mirror.sjtu.edu.cn/sury/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
else
curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
fi
apt update -y
fi
@@ -85,14 +90,16 @@ if [ "${action}" == "install" ] && [ -d ${serverPath}/php-apt/${type} ];then
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install xml
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install mcrypt
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install mysqlnd
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install mysql
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install gettext
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install redis
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install memcached
cd ${rootPath}/plugins/php-apt/versions && bash common.sh ${type:0:1}.${type:1:2} install mbstring
echo "install PHP-APT[${type}] extend end"
if [ ! -f /usr/local/bin/composer ];then
cd /tmp
curl -sS https://getcomposer.org/installer | php
curl -sS https://getcomposer.org/installer | /usr/bin/php${type:0:1}.${type:1:2}
mv composer.phar /usr/local/bin/composer
fi
fi
+1 -2
View File
@@ -57,5 +57,4 @@ fi
echo "apt install -y php${version}-${extName}"
echo "apt remove -y php${version}-${extName}"
systemctl restart php${version}-fpm
+18
View File
@@ -35,6 +35,24 @@
"shell": "mysqlnd.sh",
"check": "mysqlnd"
},
{
"name": "mysql",
"versions": [
"56",
"70",
"71",
"72",
"73",
"74",
"80",
"81",
"82"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
"shell": "mysql.sh",
"check": "mysql"
},
{
"name": "sqlite3",
"versions": [
+4 -1
View File
@@ -68,6 +68,8 @@ if [ "${action}" == "install" ] && [ -d ${serverPath}/php-yum/${type} ];then
# 安装通用扩展
echo "install PHP-YUM[${type}] extend start"
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install mysqlnd
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install mysql
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install gd
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install iconv
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install exif
@@ -77,11 +79,12 @@ if [ "${action}" == "install" ] && [ -d ${serverPath}/php-yum/${type} ];then
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install gettext
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install redis
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install memcached
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install mbstring
echo "install PHP-YUM[${type}] extend end"
if [ ! -f /usr/local/bin/composer ];then
cd /tmp
curl -sS https://getcomposer.org/installer | php
curl -sS https://getcomposer.org/installer | /opt/remi/php${type}/root/usr/bin/php
mv composer.phar /usr/local/bin/composer
fi
fi
+1 -1
View File
@@ -28,7 +28,7 @@ fi
Uninstall_php()
{
# $serverPath/php-ya/init.d/php${PHP_VER} stop
yum remove -y php74 php74-php-fpm php74-*
rm -rf $serverPath/php-yum/${PHP_VER}
echo "卸载php-${version}..." > $install_tmp
}
+1 -1
View File
@@ -28,7 +28,7 @@ fi
Uninstall_php()
{
# $serverPath/php-ya/init.d/php${PHP_VER} stop
yum remove -y php81 php81-php-fpm php81-*
rm -rf $serverPath/php-yum/${PHP_VER}
echo "卸载php-${version}..." > $install_tmp
}
+1 -1
View File
@@ -28,7 +28,7 @@ fi
Uninstall_php()
{
# $serverPath/php-yum/init.d/php${PHP_VER} stop
yum remove -y php82 php82-php-fpm php82-*
rm -rf $serverPath/php-yum/${PHP_VER}
echo "卸载php-${version}..." > $install_tmp
}
+7
View File
@@ -21,6 +21,7 @@ extName=$3
FILE=${curPath}/${version}/${extName}.sh
# yum install -y php81-php-yar
# yum install -y php74-php-pecl-mysql
if [ "$action" == 'install' ];then
@@ -30,6 +31,10 @@ if [ "$action" == 'install' ];then
else
yum install -y php${version}-php*-${extName}
fi
# if [ "${extName}" == "mysql" ];then
# yum install -y php74-php-pecl-mysql
# fi
fi
@@ -46,5 +51,7 @@ fi
echo "yum install -y php${version}-php-${extName}"
echo "yum remove -y php${version}-php-${extName}"
bash ${rootPath}/plugins/php-yum/versions/lib.sh $version restart
+2 -2
View File
@@ -11,9 +11,9 @@ serverPath=$(dirname "$rootPath")
version=$1
action=$2
if [ -f /lib/systemd/system/php${version}.service ];then
if [ -f /lib/systemd/system/php${version}-php-fpm.service ];then
systemctl ${action} php${version}
elif [[ -f /usr/lib/systemd/system/php${version}.service ]]; then
elif [[ -f /usr/lib/systemd/system/php${version}-php-fpm.service ]]; then
systemctl ${action} php${version}
else
$serverPath/php/init.d/php${version} ${action}
+13
View File
@@ -25,6 +25,19 @@
"shell": "mysqlnd.sh",
"check": "mysqlnd"
},
{
"name": "mysql",
"versions": [
"74",
"80",
"81",
"82"
],
"type": "数据库",
"msg": "用于使用MySQL数据库的模块!",
"shell": "mysql.sh",
"check": "mysql"
},
{
"name": "oci8",
"versions": [
+1 -1
View File
@@ -82,7 +82,7 @@ if [ "${action}" == "install" ] && [ -d ${serverPath}/php/${type} ];then
if [ ! -f /usr/local/bin/composer ];then
cd /tmp
curl -sS https://getcomposer.org/installer | php
curl -sS https://getcomposer.org/installer | /www/server/php/${type}/bin/php
mv composer.phar /usr/local/bin/composer
fi
fi
+6 -1
View File
@@ -80,7 +80,12 @@ Install_lib()
fi
cd $php_lib/sg11
# echo "mv $php_lib/sg11/${DEFAULT_OSNAME}/ixed.${SG_VER}.lin $extFile"
cp -rf $php_lib/sg11/${DEFAULT_OSNAME}/ixed.${SG_VER}.${SUFFIX_NAME} $extFile
if [ -f $php_lib/sg11/${DEFAULT_OSNAME}/ixed.${SG_VER}.${SUFFIX_NAME} ];then
cp -rf $php_lib/sg11/${DEFAULT_OSNAME}/ixed.${SG_VER}.${SUFFIX_NAME} $extFile
else
echo 'Not supported temporarily'
exit
fi
if [ "$OSNAME" == 'macos' ];then
xattr -c * $extFile
+1 -1
View File
@@ -85,7 +85,7 @@ def getPhpVer(expect=55):
v = site_api.site_api().getPhpVersion()
is_find = False
for i in range(len(v)):
t = int(v[i]['version'])
t = str(v[i]['version'])
if (t == expect):
is_find = True
return str(t)
+1
View File
@@ -13,6 +13,7 @@
</div>
<script type="text/javascript">
resetPluginWinHeight(480);
$.getScript( "/plugins/file?name=swap&f=js/swap.js", function(){
pluginService('swap');
});
+12 -6
View File
@@ -122,7 +122,7 @@ def getLog():
logPath = args['path']
content = mw.getLastLine(logPath, 100)
content = mw.getLastLine(logPath, 16)
return mw.returnJson(True, 'ok', content)
@@ -132,11 +132,16 @@ def runShellArgs(args):
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))
param = args['params']
if param == '':
param = 'no-parameters'
param = re.sub("\"", '', param)
cmd = "bash {} {} >> {}.log 2>&1 &".format(
shellFile, param, shellFile)
# print(cmd)
os.system(cmd)
data[i]['count'] += 1
data[i]['uptime'] = int(time.time())
mw.writeFile(getCfgFilePath(), json.dumps(data))
@@ -150,6 +155,7 @@ def runShell():
if not check_arg[0]:
return check_arg[1]
args['params'] = 'panel-test'
return runShellArgs(args)
+1 -1
View File
@@ -21,7 +21,7 @@ Install_App()
Uninstall_App()
{
rm -rf $serverPath/redis
rm -rf $serverPath/webhook
echo "Uninstall_App" > $install_tmp
}
+67 -25
View File
@@ -26,6 +26,32 @@ function whPost(method, args,callback){
},'json');
}
function whPostNoMessage(method, args,callback){
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) {;
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 });
@@ -153,42 +179,60 @@ function showWebHookCode(url,code){
<div class="line help">\
<b>WebHook使用方法:</b><br>\
GET/POST:<br>\
'+window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '')+'/hook?access_key='+code+'&amp;param=aaa<br>\
'+window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '')+'/hook?access_key='+code+'&amp;params=aaa<br>\
@param access_key string HOOK密钥<br>\
@param param string 自定义参数(在hook脚本中使用$1接收)<br>\
@param params string 自定义参数(在hook脚本中使用$1接收)| 多个参数 "1 2" -> $1为1, $2为2<br>\
</div>\
</div>'
})
}
//查看日志
function getLogs(path){
whPost('get_log', {"path":path}, function(rdata){
function getLogsTimer(path,success,error){
whPostNoMessage('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:'<div class="bt-logs" style="font-size:0;">\
<textarea class="bt-input-text mr20 site_logs pd10" name="site_logs" style="width:100%;line-height:22px;white-space: pre-line;font-size:12px;height:358px;border: none;" readonly="readonly">'+ (rdata.data || '当前没有日志.') +'</textarea>\
</div>',
success:function(){
$('[name="site_logs"]').scrollTop($('[name="site_logs"]')[0].scrollHeight)
if (typeof(error) == 'function'){
error();
}
});
return;
}
$('[name="site_logs"]').text(rdata.data);
if (typeof(success) == 'function'){
success();
}
});
}
//查看日志
function getLogs(path){
logs_web = layer.open({
type:1,
title:'任务执行日志',
area: ['600px','400px'],
shadeClose:false,
closeBtn:2,
content:'<div class="bt-logs" style="font-size:0;">\
<textarea class="bt-input-text mr20 site_logs pd10" name="site_logs" style="width:100%;line-height:22px;white-space: pre-line;font-size:12px;height:358px;border: none;" readonly="readonly">正在获取中...</textarea>\
</div>',
success:function(){
$('[name="site_logs"]').scrollTop($('[name="site_logs"]')[0].scrollHeight);
logs_timer = setInterval(function(){
getLogsTimer(path,function(){
},function(){
layer.msg(rdata.msg,{icon:2});
layer.close(logs_web);
});
},1000);
},
cancel:function(){
clearInterval(logs_timer);
}
});
}
//运行
function runHook(key){
whPost('run_shell', {"access_key":key}, function(rdata){
@@ -220,5 +264,3 @@ function deleteHook(key, title){
});
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

-2
View File
@@ -1,7 +1,5 @@
<script type="text/javascript">
resetPluginWinWidth(480);
// $.getScript( "/plugins/file?name=webssh&f=js/webssh.js", function() {
//});
if ($(".term-box #term").text() != 'W') {
layer.closeAll();
webShell();
+197 -4
View File
@@ -11,10 +11,203 @@ sys.path.append(os.getcwd() + "/class/core")
import mw
def status():
return 'start'
class App():
__cmd_file = 'cmd.json'
__cmd_path = ''
__host_dir = ''
def __init__(self):
self.__cmd_path = self.getServerDir() + '/' + self.__cmd_file
if not os.path.exists(self.__cmd_path):
mw.writeFile(self.__cmd_path, '[]')
self.__host_dir = self.getServerDir() + '/host'
if not os.path.exists(self.__host_dir):
os.makedirs(self.__host_dir)
def getPluginName(self):
return 'webssh'
def getPluginDir(self):
return mw.getPluginDir() + '/' + self.getPluginName()
def getServerDir(self):
return mw.getServerDir() + '/' + self.getPluginName()
def getArgs(self):
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(self, 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 status(self):
return 'start'
def saveCmd(self, t):
data_tmp = json.loads(mw.readFile(self.__cmd_path))
is_has = False
for x in range(0, len(data_tmp) - 1):
if data_tmp[x]['title'] == t['title']:
is_has = True
data_tmp[x]['cmd'] = t['cmd']
if not is_has:
data_tmp.append(t)
mw.writeFile(self.__cmd_path, json.dumps(data_tmp))
def add_cmd(self):
args = self.getArgs()
check = self.checkArgs(args, ['title', 'cmd'])
if not check[0]:
return check[1]
title = args['title'].strip()
cmd = args['cmd']
t = {
'title': title,
'cmd': cmd
}
self.saveCmd(t)
return mw.returnJson(True, '添加成功!')
def del_cmd(self):
args = self.getArgs()
check = self.checkArgs(args, ['title'])
if not check[0]:
return check[1]
title = args['title'].strip()
data_tmp = json.loads(mw.readFile(self.__cmd_path))
for x in range(0, len(data_tmp)):
if data_tmp[x]['title'] == title:
del(data_tmp[x])
mw.writeFile(self.__cmd_path, json.dumps(data_tmp))
return mw.returnJson(True, '删除成功')
return mw.returnJson(False, '删除无效')
def get_cmd_list(self):
alist = json.loads(mw.readFile(self.__cmd_path))
return mw.returnJson(True, 'ok', alist)
def getSshInfo(self, file):
rdata = mw.readFile(file)
destr = mw.deCrypt('mdserver-web', rdata)
return json.loads(destr)
def get_server_by_host(self):
args = self.getArgs()
check = self.checkArgs(args, ['host'])
if not check[0]:
return check[1]
info_file = self.__host_dir + '/' + args['host'] + '/info.json'
if os.path.exists(info_file):
try:
info_tmp = self.getSshInfo(info_file)
host_info = {}
host_info['host'] = args['host']
host_info['port'] = info_tmp['port']
host_info['ps'] = info_tmp['ps']
host_info['type'] = info_tmp['type']
if 'password' in info_tmp:
host_info['password'] = info_tmp['password']
if 'pkey' in info_tmp:
host_info['pkey'] = info_tmp['pkey']
if 'pkey_passwd' in info_tmp:
host_info['pkey_passwd'] = info_tmp['pkey_passwd']
except Exception as e:
return mw.returnJson(False, '错误:' + str(e))
return mw.returnJson(True, 'ok!', host_info)
return mw.returnJson(False, '不存在此配置')
def get_server_list(self):
host_list = []
for name in os.listdir(self.__host_dir):
info_file = self.__host_dir + '/' + name + '/info.json'
if not os.path.exists(info_file):
continue
try:
info_tmp = self.getSshInfo(info_file)
host_info = {}
host_info['host'] = name
host_info['port'] = info_tmp['port']
host_info['ps'] = info_tmp['ps']
# host_info['sort'] = int(info_tmp['sort'])
except Exception as e:
print(e)
# if os.path.exists(info_file):
# os.remove(info_file)
# continue
host_list.append(host_info)
host_list = sorted(host_list, key=lambda x: x['host'], reverse=False)
return mw.returnJson(True, 'ok!', host_list)
def del_server(self):
args = self.getArgs()
check = self.checkArgs(args, ['host'])
if not check[0]:
return check[1]
host = args['host']
info_file = self.__host_dir + '/' + host
mw.execShell('rm -rf {}'.format(info_file))
return mw.returnJson(True, '删除成功!')
def add_server(self):
args = self.getArgs()
check = self.checkArgs(
args, ['host', 'port', 'type', 'username', 'ps'])
if not check[0]:
return check[1]
host = args['host']
info = {
'port': args['port'],
'username': args['username'],
'ps': args['ps'],
'type': args['type'],
}
if args['type'] == '0':
info['password'] = args['password']
else:
info['pkey'] = args['pkey']
info['pkey_passwd'] = args['pkey_passwd']
dst_host_dir = self.__host_dir + '/' + host
if not os.path.exists(dst_host_dir):
os.makedirs(dst_host_dir)
enstr = mw.enCrypt('mdserver-web', json.dumps(info))
mw.writeFile(dst_host_dir + '/info.json', enstr)
return mw.returnJson(True, '添加成功!')
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
classApp = App()
try:
data = eval("classApp." + func + "()")
print(data)
except Exception as e:
print(mw.getTracebackInfo())
+13 -1
View File
@@ -1,11 +1,23 @@
{
"hook":[
{
"tag":"menu",
"menu": {
"title":"终端管理",
"name":"webssh",
"path":"menu/index.html",
"css_path":"menu/index.css",
"js_path":"js/webssh.js"
}
}
],
"id":3,
"title":"SSH终端",
"tip":"lib",
"name":"webssh",
"type":"扩展",
"ps":"完整功能的SSH客户端,仅用于连接本服务器",
"versions":"1.0",
"versions":"2.0",
"shell":"install.sh",
"checks":"server/webssh",
"path": "server/webssh",
+2 -1
View File
@@ -11,12 +11,13 @@ serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
Install_webssh()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/webssh
echo '1.0' > $serverPath/webssh/version.pl
echo "${VERSION}" > $serverPath/webssh/version.pl
echo '安装完成' > $install_tmp
}
+580 -159
View File
@@ -1,179 +1,600 @@
function web_shell2() {
var termCols = 83;
var termRows = 21;
var sendTotal = 0;
if(!socket)socket = io.connect();
var term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true});
term.open();
term.setOption('cursorBlink', true);
term.setOption('fontSize', 14);
gterm = term
//全局
var host_ssh_list = [];
socket.on('server_response', function (data) {
term.write(data.data);
if (data.data == '\r\n登出\r\n' ||
data.data == '登出\r\n' ||
data.data == '\r\nlogout\r\n' ||
data.data == 'logout\r\n') {
setTimeout(function () {
layer.closeAll();
term.destroy();
clearInterval(interval);
}, 500);
}
});
if (socket) {
socket.emit('connect_event', '');
interval = setInterval(function () {
socket.emit('connect_event', '');
}, 1000);
//刷新页面
$(window).unload(function(){
for (i in host_ssh_list) {
host_ssh_list[i].close();
}
term.on('data', function (data) {
socket.emit('webssh', data);
return false;
});
function appPost(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'webssh', func:method, args:_args}, 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');
}
function appAsyncPost(method,args){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
return syncPost('/plugins/run', {name:'webssh', func:method, args:_args});
}
function appPostCallbak(method, args, callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'webssh';
req_data['func'] = method;
args['version'] = '1.0';
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');
}
$(document).ready(function(){
var tag = $.getUrlParam('tag');
if(tag == 'webssh'){
webShell_Load();
}
});
function webShell_Resize(){
var cur_ssh = $('.term_item_tab .list .active');
if (cur_ssh.length > 0){
var data = $(cur_ssh).data();
var item = host_ssh_list[data.id];
item.term.fit();
item.resize({ cols: item.term.cols, rows: item.term.rows});
item.term.focus();
}
}
function webShell_Load(){
changeDivH();
$(window).resize(function(){
changeDivH();
webShell_Resize();
});
$('.term_content_tab .term-tool-button').click(function(){
if ($(this).hasClass('tool-show')){
$('#term_box_view').css('margin-right',300);
$('.term_tootls').css('display',"block");
$(this).removeClass('tool-show').addClass('tool-hide');
$(this).find('span').removeClass('glyphicon-menu-left').addClass('glyphicon-menu-right');
} else {
$('#term_box_view').css('margin-right',0);
$('.term_tootls').css('display',"none");
$(this).removeClass('tool-hide').addClass('tool-show');
$(this).find('span').removeClass('glyphicon-menu-right').addClass('glyphicon-menu-left');
}
webShell_Resize();
});
var term_box = layer.open({
type: 1,
title: "本地终端",
area: ['685px','435px'],
closeBtn: 2,
shadeClose: false,
content: '<div class="term-box"><div id="term"></div></div>\
<div class="shell-text-input">\
<textarea type="text" class="bt-input-text-shell" placeholder="请将命令粘贴到此处.." value="" name="ssh_copy" />\
<div class="shell-btn-group">\
<button class="shellbutton btn btn-success btn-sm pull-right shell_btn_1">发送(Ctrl+Enter)</button>\
<button class="shellbutton btn btn-default btn-sm pull-right shell_btn_close">关闭</button>\
</div>\
</div>',
cancel: function () {
term.destroy();
clearInterval(interval);
$('.full_exit_screen').click(function(ele){
if($(this).hasClass('glyphicon-resize-full')){
requestFullScreen($('#term_box_view')[0]);
$(this).removeClass('glyphicon-resize-full').addClass('glyphicon-resize-small');
} else{
exitFull();
$(this).removeClass('glyphicon-resize-small').addClass('glyphicon-resize-full');
}
});
$(".shell_btn_close").click(function(){
layer.close(term_box);
term.destroy();
clearInterval(interval);
})
setTimeout(function () {
$('.terminal').detach().appendTo('#term');
$("#term").show();
socket.emit('webssh', "\n");
term.focus();
// 鼠标右键事件
var can = $("#term");
can.contextmenu(function (e) {
var winWidth = can.width();
var winHeight = can.height();
var mouseX = e.pageX;
var mouseY = e.pageY;
var menuWidth = $(".contextmenu").width();
var menuHeight = $(".contextmenu").height();
var minEdgeMargin = 10;
if (mouseX + menuWidth + minEdgeMargin >= winWidth &&
mouseY + menuHeight + minEdgeMargin >= winHeight) {
menuLeft = mouseX - menuWidth - minEdgeMargin + "px";
menuTop = mouseY - menuHeight - minEdgeMargin + "px";
$('.addServer').click(function(){
webShell_addServer();
});
$('.tootls_host_btn').click(function(){
webShell_addServer();
});
$('.tootls_commonly_btn').click(function(){
webShell_cmd();
});
// 切换服务器终端视图
$('.term_item_tab .list').on('click', 'span.item', function (ev) {
var index = $(this).index();
var data = $(this).data();
if ($(this).hasClass('addServer')) {
} else if ($(this).hasClass('tab_tootls')) {
} else {
$(this).addClass('active').siblings().removeClass('active');
$('.term_content_tab .term_item:eq(' + index + ')').addClass('active').siblings().removeClass('active');
webShell_Resize();
}
});
$('.term_item_tab').on('click', '.icon-trem-close', function () {
var id = $(this).parent().data('id');
webShell_removeTermView(id);
})
//服务器列表和常用命令
webShell_getHostList();
//服务器列表和命令切换
$('.term_tootls .tab-nav span').click(function(){
var list_type = $(this).attr('data-type');
if (!$(this).hasClass('on')){
$('.term_tootls .tab-nav span').removeClass('on');
$(this).addClass('on');
$('.term_tootls .tab-con .tab-block').removeClass('on')
if (list_type == 'host'){
$('.term_tootls .tab-con .tab-block').eq(0).addClass('on');
webShell_getHostList();
}
else if (mouseX + menuWidth + minEdgeMargin >= winWidth) {
menuLeft = mouseX - menuWidth - minEdgeMargin + "px";
menuTop = mouseY + minEdgeMargin + "px";
if (list_type == 'shell'){
$('.term_tootls .tab-con .tab-block').eq(1).addClass('on');
webShell_getCmdList();
}
else if (mouseY + menuHeight + minEdgeMargin >= winHeight) {
menuLeft = mouseX + minEdgeMargin + "px";
menuTop = mouseY - menuHeight - minEdgeMargin + "px";
}
});
webShell_Menu();
}
function changeDivH(){
var l = $(window).height();
$('#term_box_view').parent().css('height',l-80);
$('#xterm-viewport').css('height',l-80);
$('.tootls_host_list').css('display','block').css('height',l-192);
$('.tootls_commonly_list').css('display','block').css('height',l-192);
}
// 窗口状态改变
function fullScreenChange(el, callback) {
el.addEventListener("fullscreenchange", function () {
callback && callback(document.fullscreen);
});
el.addEventListener("webkitfullscreenchange", function () {
callback && callback(document.webkitIsFullScreen);
});
el.addEventListener("mozfullscreenchange", function () {
callback && callback(document.mozFullScreen);
});
el.addEventListener("msfullscreenchange", function () {
callback && callback(document.msFullscreenElement);
});
}
// 全屏
function requestFullScreen(element) {
var requestMethod = element.requestFullScreen || //W3C
element.webkitRequestFullScreen || //Chrome等
element.mozRequestFullScreen || //FireFox
element.msRequestFullScreen; //IE11
if (requestMethod) {
requestMethod.call(element);
}else if (typeof window.ActiveXObject !== "undefined") {//for Internet Explorer
var wscript = new ActiveXObject("WScript.Shell");
if (wscript !== null) {
wscript.SendKeys("{F11}");
}
}
}
//退出全屏
function exitFull() {
var exitMethod = document.exitFullscreen || //W3C
document.mozCancelFullScreen || //Chrome等
document.webkitExitFullscreen || //FireFox
document.webkitExitFullscreen; //IE11
if (exitMethod) {
exitMethod.call(document);
}else if (typeof window.ActiveXObject !== "undefined") {//for Internet Explorer
var wscript = new ActiveXObject("WScript.Shell");
if (wscript !== null) {
wscript.SendKeys("{F11}");
}
}
}
function webShell_getCmdList(){
appPost('get_cmd_list', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var alist = rdata.data;
var tli = '';
for (var i = 0; i < alist.length; i++) {
tli+='<li class="data-cmd-list" data-index="'+i+'" data-clipboard-text="'+alist[i]['cmd']+'">\
<i></i>\
<span class="span_title">'+alist[i]['title']+'</span>\
<span class="tootls">\
<span class="glyphicon glyphicon-edit" aria-hidden="true" title="编辑常用命令信息"></span>\
<span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除常用命令信息"></span>\
</span>\
</li>';
}
$('.tootls_commonly_list').html(tli);
$('.data-cmd-list .glyphicon-edit').click(function(){
var index = $(this).parent().parent().attr('data-index');
var t = alist[index];
webShell_cmd(t['title'],t['cmd']);
});
$('.data-cmd-list .glyphicon-trash').click(function(){
var index = $(this).parent().parent().attr('data-index');
var t = alist[index];
appPost('del_cmd', {title:t['title']}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
webShell_getCmdList();
},{ icon: rdata.status ? 1 : 2 });
});
});
$('.data-cmd-list .span_title').click(function(e){
copyText($(this).parent().attr('data-clipboard-text'));
e.preventDefault();
});
});
}
var n;
function Terms_WebSocketIO_Create(ip, random){
n = new Terms_WebSocketIO('#'+random, { ssh_info: { host: ip, ps: "22", id: random } });
n.registerCloseCallBack(function(){
webShell_removeTermView(random);
layer.msg('已经关闭【'+ip+'】', { icon: 1, time: 3000 });
});
n.registerConnectedCallBack(function(){
var that = this;
$('.term_item_tab .item').each(function(){
var id = $(this).data('id');
if (id == that.id){
$(this).find('.icon').removeClass('icon-warning').addClass('icon-sucess');
}
else {
menuLeft = mouseX + minEdgeMargin + "px";
menuTop = mouseY + minEdgeMargin + "px";
});
webShell_Resize();
});
n.registerExitCallBack(function(){
var that = this;
$('.term_item_tab .item').each(function(){
var id = $(this).data('id');
if (id == that.id){
$(this).find('.icon').removeClass('icon-sucess').addClass('icon-warning');
}
});
});
return n;
}
function webShell_Menu(){
var random = 'localhost';
// host_ssh_list[random] = new Terms_WebSocketIO('#'+random, { ssh_info: { host: "38.6.224.67", ps: "22", id: random } });
host_ssh_list[random] = Terms_WebSocketIO_Create('127.0.0.1',random);
}
function webShell_openTermView(info) {
if (typeof info === "undefined") {
info = { host: '127.0.0.1', ps: '本地服务器' }
}
var random = getRandomString(9);
var tab_content = $('.term_content_tab');
var item_list = $('.term_item_tab .list');
tab_content.find('.term_item').removeClass('active').siblings().removeClass('active');
tab_content.append('<div class="term_item active" id="' + random + '" data-host="' + info.host + '"></div>');
item_list.find('.item').removeClass('active');
if (info.ps == ''){
info.ps = info.host;
}
item_list.append('<span class="active item ' + (info.host == '127.0.0.1' ? 'localhost_item' : '') + '" data-host="' + info.host + '" data-id="' + random + '"><i class="icon icon-sucess"></i><div class="content"><span>' + info.ps + '</span></div><span class="icon-trem-close"></span></span>');
host_ssh_list[random] = Terms_WebSocketIO_Create(info.host, random);
}
function webShell_removeTermView(id){
var item = $('[data-id="' + id + '"]');
var next = item.next();
var prev = item.prev();
$('#' + id).remove();
item.remove();
try {
host_ssh_list[id].close();
} catch (error) {
console.log(error);
}
delete host_ssh_list[id];
if (item.hasClass('active')) {
if (next.length > 0) {
next.click();
} else {
prev.click();
}
}
}
function webShell_getHostList(info){
appPost('get_server_list', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var alist = rdata.data;
var tli = '';
for (var i = 0; i < alist.length; i++) {
tli+='<li class="data-host-list" data-index="'+i+'" data-host="'+alist[i]['host']+'">\
<i></i>\
<span class="host">'+alist[i]['host']+'</span>\
<span class="tootls">\
<span class="glyphicon glyphicon-edit" aria-hidden="true" title="编辑常用命令信息"></span>\
<span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除常用命令信息"></span>\
</span>\
</li>';
}
$('.tootls_host_list').html(tli);
$('.data-host-list .glyphicon-edit').click(function(e){
var index = $(this).parent().parent().attr('data-index');
var info = alist[index];
webShell_addServer(info);
});
$('.data-host-list .glyphicon-trash').click(function(e){
var index = $(this).parent().parent().attr('data-index');
var t = alist[index];
appPost('del_server', {host:t['host']}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
webShell_getHostList();
},{ icon: rdata.status ? 1 : 2 });
});
});
$('.tootls_host_list .host').on('click', function (e) {
var _this = $(this).parent();
var index = $(_this).index();
var host = $(_this).data('host');
$(_this).find('i').addClass('active');
if ($('.item[data-host="' + host + '"]').length > 0) {
layer.msg('已经打开!', { icon: 0, time: 3000 });
} else {
webShell_openTermView(alist[index]);
}
e.preventDefault();
});
});
}
function webShell_addServer(info=[]){
layer.open({
type: 1,
title: '添加主机信息',
area: '500px',
btn:["确定","取消"],
content:'<div class="bt-form pd20 c6">\
<div class="line input_group">\
<span class="tname">服务器IP</span>\
<div class="info-r">\
<input type="text" name="host" class="bt-input-text mr5" style="width:240px" value="127.0.0.1" placeholder="输入服务器IP" val="" autocomplete="off" />\
<input type="text" name="port" class="bt-input-text mr5" style="width:60px" placeholder="端口" value="22" autocomplete="off"/>\
</div>\
</div>\
<div class="line">\
<span class="tname">SSH账号</span>\
<div class="info-r">\
<input type="text" name="username" class="bt-input-text mr5" style="width:305px" placeholder="输入SSH账号" value="root" autocomplete="off"/>\
</div>\
</div>\
<div class="line">\
<span class="tname">验证方式</span>\
<div class="info-r">\
<div class="btn-group">\
<button type="button" tabindex="-1" class="btn btn-sm auth_type_checkbox btn-default btn-success" data-ctype="0">密码验证</button>\
<button type="button" tabindex="-1" class="btn btn-sm auth_type_checkbox btn-default" data-ctype="1">私钥验证\
</button>\
</div>\
</div>\
</div>\
<div class="line c_password_view show">\
<span class="tname">密码</span>\
<div class="info-r">\
<input type="text" name="password" class="bt-input-text mr5" placeholder="请输入SSH密码" style="width:305px;" value="" autocomplete="off"/>\
</div>\
</div>\
<div class="line c_pkey_view hide">\
<span class="tname">私钥</span>\
<div class="info-r">\
<textarea rows="4" name="pkey" class="bt-input-text mr5" placeholder="请输入SSH私钥" style="width:305px;height: 80px;line-height: 18px;padding-top:10px;"></textarea>\
</div>\
</div>\
<div class="line key_pwd_line hide" style="display:none;">\
<span class="tname">私钥密码</span>\
<div class="info-r">\
<input type="text" name="pkey_passwd" class="bt-input-text mr5" placeholder="请输入私钥密码" style="width:305px;" value="" autocomplete="off"/>\
</div>\
</div>\
<div class="line ssh_ps_tips">\
<span class="tname">备注</span>\
<div class="info-r">\
<input type="text" name="ps" class="bt-input-text mr5" placeholder="请输入备注,可为空" style="width:305px;" value="" autocomplete="off"/>\
</div>\
</div>\
</div>',
success:function(){
if (typeof(info['host'])!='undefined'){
$('input[name="host"]').val(info['host']);
appPost('get_server_by_host',{host:info['host']},function(rdata){
var rdata = $.parseJSON(rdata.data);
var jdata = rdata.data;
if (jdata['type'] == 0){
$('input[name="password"]').val(jdata['password']);
} else{
$('textarea[name="pkey"]').val(jdata['pkey']);
// $('input[name="pkey_passwd"]').val(jdata['pkey_passwd']);
}
$('input[name="ps"]').val(jdata['ps']);
$('.auth_type_checkbox').each(function(){
if ($(this).data('ctype') == jdata['type']){
$(this).addClass('btn-success');
} else {
$(this).removeClass('btn-success');
}
});
if (jdata['type'] == 0){
$('.c_password_view').removeClass('show').addClass('show');
$('.c_pkey_view').removeClass('show').addClass('hide');
// $('.key_pwd_line').removeClass('show').addClass('hide');
}else{
$('.c_password_view').removeClass('show').addClass('hide');
$('.c_pkey_view').removeClass('show').addClass('show');
// $('.key_pwd_line').removeClass('show').addClass('show');
}
});
}
$('.auth_type_checkbox').click(function(){
var ctype = $(this).attr('data-ctype');
$('.auth_type_checkbox').removeClass('btn-success');
$(this).addClass('btn-success');
if (ctype == 0){
$('.c_password_view').removeClass('show').addClass('show');
$('.c_pkey_view').removeClass('show').addClass('hide');
// $('.key_pwd_line').removeClass('show').addClass('hide');
}else{
$('.c_password_view').removeClass('show').addClass('hide');
$('.c_pkey_view').removeClass('show').addClass('show');
// $('.key_pwd_line').removeClass('show').addClass('show');
}
});
},
yes:function(l,layeror){
var host = $('input[name="host"]').val();
var port = $('input[name="port"]').val();
var username = $('input[name="username"]').val();
var password = '';
var pkey = '';
var pkey_passwd = '';
var type = $('.btn-group .btn-success').attr('data-ctype');
if (type == "0"){
password = $('input[name="password"]').val();
} else{
pkey = $('textarea[name="pkey"]').val();
pkey_passwd = $('input[name="pkey_passwd"]').val();
}
var ps = $('input[name="ps"]').val();
var req_data = {
type:type,
host:host,
port:port,
username:username,
password:password,
pkey:pkey,
pkey_passwd:pkey_passwd,
ps:ps,
};
var selectText = term.getSelection()
var style_str = '';
var paste_str = '';
if (!selectText) {
if (!getCookie('shell_copy_body')) {
paste_str = 'style="color: #bbb;" disable';
}
style_str = 'style="color: #bbb;" disable';
} else {
setCookie('ssh_selection', selectText);
}
console.log(req_data);
appPost('add_server',req_data,function(rdata){
layer.close(l);
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
webShell_getHostList();
},{ icon: rdata.status ? 1 : 2 });
});
},
});
}
var menudiv = '<ul class="contextmenu">\
<li><a class="shell_copy_btn menu_ssh" data-clipboard-text="'+ selectText + '" ' + style_str + '>复制到剪切板</a></li>\
<li><a onclick="shell_paste_text()" '+ paste_str+'>粘贴选中项</a></li>\
<li><a onclick="shell_to_baidu()" ' + style_str + '>百度搜索</a></li>\
</ul>';
$("body").append(menudiv);
$(".contextmenu").css({
"left": menuLeft,
"top": menuTop
function webShell_cmd(title='', cmd=''){
layer.open({
type: 1,
title: '添加常用命令信息',
area: '500px',
btn:["确定","取消"],
content:'<div class="bt-form pd20 c6">\
<div class="line">\
<span class="tname">命令名称</span>\
<div class="info-r">\
<input type="text" name="title" class="bt-input-text mr5" style="width:305px" placeholder="请输入常用命令描述,必填项" value="'+title+'" autocomplete="off"/>\
</div>\
</div>\
<div class="line">\
<span class="tname">命令内容</span>\
<div class="info-r">\
<textarea rows="4" name="cmd" class="bt-input-text mr5" placeholder="请输入常用命令信息,必填项" style="width:305px;height: 150px;line-height: 18px;padding-top:10px;">'+cmd+'</textarea>\
</div>\
</div>\
</div>',
success:function(){
},
yes:function(l,layer_id){
var title = $('input[name="title"]').val();
var cmd = $('textarea[name="cmd"]').val();
appPost('add_cmd', {title:title,cmd:cmd}, function(rdata){
layer.close(l);
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg, function(){
webShell_getCmdList();
},{ icon: rdata.status ? 1 : 2 });
});
return false;
});
can.click(function () {
remove_ssh_menu();
});
clipboard = new ClipboardJS('.shell_copy_btn');
clipboard.on('success', function (e) {
layer.msg('复制成功!');
setCookie('shell_copy_body', e.text)
remove_ssh_menu();
term.focus();
});
clipboard.on('error', function (e) {
layer.msg('复制失败,浏览器不兼容!');
setCookie('shell_copy_body', e.text)
remove_ssh_menu();
term.focus();
});
$(".shellbutton").click(function () {
var tobj = $("textarea[name='ssh_copy']");
var ptext = tobj.val();
tobj.val('');
if ($(this).text().indexOf('Alt') != -1) {
ptext +="\n";
}
socket.emit('webssh', ptext);
term.focus();
})
$("textarea[name='ssh_copy']").keydown(function (e) {
if (e.ctrlKey && e.keyCode == 13) {
$(".shell_btn_1").click();
} else if (e.altKey && e.keyCode == 13) {
$(".shell_btn_1").click();
}
});
}, 100);
}
});
}
function shell_to_baidu() {
var selectText = getCookie('ssh_selection');
remove_ssh_menu();
window.open('https://www.baidu.com/s?wd=' + selectText)
gterm.focus();
}
function shell_paste_text(){
socket.emit('webssh', getCookie('ssh_selection'));
remove_ssh_menu();
gterm.focus();
}
function remove_ssh_menu() {
$(".contextmenu").remove();
}
+593
View File
@@ -0,0 +1,593 @@
/* menu start */
.menu .menu_plugin_webssh {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMBJREFUeNpiYKAQMM6cOVMASBuQozk9Pf0AC5AuAOJ6cgwAWt7IhMQvRKIfAPEEYgxhQWL3o9EFpBgwAeifQhKdD7YI5oWPUMEEmAQR4COyATBwAIgdgIacB2IFYkxhQouWB0BsCA3E86QGIsxvDSBXgGIDSxr5ALTgAk4XADWAQt4fiB2BChcAaQVoGoHheLwuAGqagBz/UNsciQ4DEgE/zAUfQM4DOt+eRANAYTMRZADIrxfIdMUFSnMzA0CAAQD0hjqnYxWD2gAAAABJRU5ErkJggg==");
}
.menu .current .menu_plugin_webssh:hover {
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQXAJ6ipUFITySRPIiMkDFRQuXm5jJKQy1kQCGeOzBXQSl3PiWLPVhfZSxrQCpxP9na2yeEPTREQ8LExmRqb5OXm/Hx8TU9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjMyQjYwMTU3OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjMyQjYwMTU4OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MzJCNjAxNTU5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzJCNjAxNTY5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX08/Lx8O/u7ezr6uno5+bl5OPi4eDf3t3c29rZ2NfW1dTT0tHQz87NzMvKycjHxsXEw8LBwL++vby7urm4t7a1tLOysbCvrq2sq6qpqKempaSjoqGgn56dnJuamZiXlpWUk5KRkI+OjYyLiomIh4aFhIOCgYB/fn18e3p5eHd2dXRzcnFwb25tbGtqaWhnZmVkY2JhYF9eXVxbWllYV1ZVVFNSUVBPTk1MS0pJSEdGRURDQkFAPz49PDs6OTg3NjU0MzIxMC8uLSwrKikoJyYlJCMiISAfHh0cGxoZGBcWFRQTEhEQDw4NDAsKCQgHBgUEAwIBAAAh+QQFMgAXACwAAAAAEAAQAAAFU6AljmRpBVOqrqtFVXAsy9Q7VMMDzHHN/5UawGQC1CiWg4IoOiINAoGB6BxBENSjyIE4oFKMprYhIFgYkvTQpWWOqm6RcVBI2+/2AuXL6k8CcSYhACH5BAUyABcALAcACQAFAAIAAAUIYJSMBLGcSggAIfkEBTIAFwAsBwAJAAUAAgAABQhgMI0MI51ACAAh+QQFMgAXACwHAAkABQACAAAFCGCUjASxnEoIADs=");
}
/* menu end */
.xterm{
position: inherit;
}
.tab-nav {
border-bottom: #cacad9 1px solid;
}
.tab-nav span {
background-color: #f0f0f1;
height: 32px;
line-height: 32px;
padding: 0 15px;
border: #cacad9 1px solid;
color: #444;
display: inline-block;
margin: 0 -1px -1px 0;
cursor: pointer;
position: relative;
}
.tab-nav .on {
background: #fff;
border-bottom: #fff 1px solid;
color: #444
}
.tab-con {
padding: 10px;
position: relative;
}
.tab-con .tab-block {
display: none;
height: 100%;
width: 100%;
}
.tab-con .tab-block.on {
display: inline-block;
}
.tab-con ul.cmdlist {
list-style-type: decimal
}
ul.cmdlist {
list-style-type: decimal;
height: 505px;
overflow-y: auto;
}
.tab-con ul.cmdlist li {
position: relative;
list-style-type: decimal;
list-style-position: inside;
line-height: 40px;
border-bottom: #dbdbea 1px solid;
margin-top: 6px
}
.tab-con ul.cmdlist li .com-progress,
.tab-con ul.cmdlist li .state,
.opencmd {
float: right;
margin-left: 20px;
color: #535362
}
.tab-con ul.cmdlist li .line-progress {
position: absolute;
bottom: -1px;
left: 0;
height: 1px;
background-color: #20a53a
}
.tab-con ul.cmdlist li .cmd {
border: 0 none;
border-radius: 0;
display: block;
width: 570px;
height: 200px;
line-height: 22px;
padding: 0 10px;
background-color: #333;
color: #eee;
overflow: auto
}
.term_item_tab .list {
display: inline-block;
webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* display: flex; */
height: 38px;
overflow: hidden;
overflow-x: auto;
}
.term_item_tab .list>span {
height: 38px;
line-height: 38px;
text-align: left;
padding: 0 25px 0 22px;
display: inline-block;
vertical-align: middle;
border-right: 1px solid #e2e2e2;
cursor: pointer;
width: 150px;
position: relative;
flex-shrink: 0;
}
.icon-trem-close {
height: 18px;
width: 18px;
position: absolute;
top: 50%;
margin-top: -8.5px;
right: 8px;
display: none !important;
}
.icon-trem-close::after,
.icon-trem-close::before {
content: '';
height: 14px;
width: 2px;
display: inline-block;
background: #fb0000;
z-index: 999;
position: absolute;
position: absolute;
top: 1.5px;
left: 8px;
transform: rotate(-45deg);
}
.icon-trem-close::after {
transform: rotate(45deg);
}
.icon-trem-close::before {
transform: rotate(-45deg);
}
/*term_item_tab*/
.term_item_tab .list>span.active .icon-trem-close,
.term_item_tab .list>span:hover .icon-trem-close {
display: inline-block !important;
}
.term_item_tab {
background: #f1f1f1;
font-size: 0;
}
.term_item_tab .list>span i {
transition: all 50ms;
}
.term_item_tab .list>span .icon {
height: 9px;
width: 9px;
border-radius: 5px;
display: inline-block;
background: #fff;
position: absolute;
left: 8px;
top: 50%;
margin-top: -4.5px;
}
.term_item_tab .list>span .icon.icon-sucess {
background-color: #10952a;
}
.term_item_tab .list>span .icon.icon-info {
background-color: #fc6d26;
}
.term_item_tab .list>span .icon.icon-warning {
background-color: #ff5d2c;
}
.term_item_tab .list>span:hover {
background-color: #dadada;
}
.term_item_tab .list>span.active {
background-color: #424242;
}
.term_item_tab .list span.active span {
color: #fff;
}
.term_item_tab .list .content {
position: relative;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.term_item_tab .item .glyphicon {
vertical-align: top;
position: absolute;
right: 12px;
font-size: 15px;
height: 38px;
line-height: 38px;
color: #ff7070 !important;
display: none;
transition: all 500ms;
}
.term_item_tab .item .glyphicon:hover {
color: red;
}
.term_item_tab .list span span {
vertical-align: middle;
font-size: 13px;
font-weight: 500;
color: #666;
display: inline-block;
line-height: 37px;
}
.term_item_tab .glyphicon {
font-size: 15px;
margin-left: 8px;
vertical-align: middle;
transition: all 500ms;
cursor: pointer;
display: inline-block;
color: #ea7575;
}
.term_item_tab span.glyphicon {
color: #888;
}
.term_item_tab .glyphicon:hover {
color: red;
}
.term_item_tab .tab_tootls {
padding: 0;
float: right;
/* padding-right: 15px; */
/* display: inline-block; */
/* display: none; */
}
/* .term_item_tab .tab_tootls span{
margin-left: 0;
font-size: 12px;
display: block;
height: 19px;
color: #bbb;
/* vertical-align: bottom;
} */
.term_item_tab .tab_tootls .glyphicon-resize-full,
.term_item_tab .tab_tootls .glyphicon-resize-small {
height: 38px;
line-height: 38px;
width: 40px;
text-align: center;
margin: 0
}
.term_item_tab .addServer {
display: inline-block;
width: 40px;
text-align: center;
padding: 0;
height: 38px;
line-height: 38px;
vertical-align: top;
}
.term_item_tab .addServer span {
margin: 0;
color: #20a53a;
}
.term_item_tab>span:hover {
background-color: #ececec;
cursor: pointer;
}
.term_item_tab .addServer span:hover {
color: #4c4c4c;
}
.term_content_tab {
background-color: rgb(51, 51, 51);
position: absolute;
top: 38px;
left: 0;
right: 0;
bottom: 0;
padding: 10px 10px 10px 10px;
overflow: hidden;
}
.term_content_tab .term_item {
height: 100%;
width: 100%;
display: none;
}
.term_content_tab .term_item.active {
display: inline-block;
}
.term-tool-button {
position: absolute;
right: -7px;
top: 50%;
width: 28px;
height: 60px;
background-color: #565656;
border-top-left-radius: 30px;
border-bottom-left-radius: 30px;
cursor: pointer;
z-index: 999;
margin-top: -30px;
}
.term-tool-button span {
font-size: 12px;
position: relative;
left: 15%;
top: 35%;
font-size: 18px;
color: #FFFFFF;
cursor: pointer;
}
.term-tool-button:hover {
background-color: #D8D8D8;
}
.term_box {
height: 100%;
border-radius: 3px;
margin-right: 300px;
position: relative;
}
.term_tootls {
width: 290px;
position: absolute;
right: 15px;
top: 15px;
/* border: 1px solid #ececec; */
}
.term_tootls .tootls_tab {
display: inline-block;
/* border: 1px solid #20a53a; */
width: 100%;
position: relative;
}
.term_tootls .tootls_tab a {
display: inline-block;
width: 38px;
text-align: center;
height: 38px;
line-height: 38px;
position: absolute;
right: 0;
color: #ececec;
background-color: #c7c7c71a;
}
.term_tootls .tab-con {
/* position: absolute;*/
top: 10px;
left: 0;
right: 0;
bottom: 0;
padding: 0;
overflow: hidden;
}
.term_tootls .tootls_tab a:hover {
background-color: #8282824d;
}
.term_tootls .tootls_tab i {
font-style: normal;
font-size: 12px;
color: #ececec;
margin-left: 5px;
}
.main-content .safe {
position: relative;
}
.term_content_tab .xterm .xterm-viewport{
/* On OS X this is required in order for the scroll bar to appear fully opaque */
background-color: #000;
overflow-y: auto;
cursor: default;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
}
.term_content_tab .xterm .composition-view.active {
display: block;
}
.term_content_tab .xterm .xterm-viewport::-webkit-scrollbar {
width: 8px;
height: 5px;
border-radius: 4px;
}
.term_content_tab .xterm .xterm-viewport::-webkit-scrollbar-thumb {
border-radius: 0;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #666;
border-radius: 4px;
transition: all 1s;
}
.term_content_tab .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb {
background: #aaa;
}
.term_content_tab .xterm .xterm-viewport::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
border-radius: 0;
background: #222;
border-radius: 4px;
transition: all 1s;
}
.term_content_tab .xterm .xterm-viewport:hover::-webkit-scrollbar-track {
background-color: #444;
}
.tootls_host_list,
.tootls_commonly_list {
list-style: none;
border-top: none;
border: 1px solid #ececec;
overflow-y: auto;
}
.tootls_host_list,
.tootls_commonly_list {
overflow: auto;
overflow-x: hidden;
font-size: 12px;
bottom: 0;
right: 0;
left: 0;
margin-top: 10px;
}
.tootls_commonly_list li,
.tootls_host_list li {
display: inline-block;
height: 38px;
line-height: 38px;
color: #444;
border-bottom: 1px solid #ececec;
font-size: 13px;
cursor: pointer;
position: relative;
width: 100%;
}
.tootls_commonly_list li {
padding-left: 15px;
}
.tootls_commonly_list li:hover,
.tootls_host_list li:hover {
background-color: #eee;
}
.tootls_commonly_list li:hover .tootls,
.tootls_host_list li:hover .tootls {
display: inline-block;
}
.tootls_host_list li i {
display: inline-block;
height: 100%;
width: 38px;
background-size: 16px;
background: url('/plugins/file?name=webssh&f=img/ico-cmd.png') no-repeat center center;
}
.tootls_commonly_list li>span,
.tootls_host_list li>span {
vertical-align: top;
display: inline-block;
}
.tootls_commonly_list li:hover>span:nth-child(2),
.tootls_host_list li:hover>span:nth-child(2) {
width: 120px;
}
.tootls_commonly_list li>span:nth-child(2),
.tootls_host_list li>span:nth-child(2) {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
max-width: 190px;
}
/* .tootls_host_list li>span:nth-child(2){
margin-left: 35px;
} */
.tootls_commonly_list li>span:nth-child(2) {
max-width: 190px;
}
.tootls_commonly_list li span:nth-child(3),
.tootls_host_list li span:nth-child(3) {
padding-left: 10px;
}
.tootls_commonly_list li .tootls,
.tootls_host_list li .tootls {
width: 70px;
text-align: right;
padding-right: 10px;
display: none;
position: absolute;
right: 5px;
}
.tootls_commonly_list li .tootls {
width: 90px;
}
.tootls_commonly_list li .tootls span,
.tootls_host_list li .tootls span {
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
}
.tootls_commonly_list li .tootls span:nth-child(1),
.tootls_host_list li .tootls span:nth-child(1) {
color: #888;
font-size: 14px;
}
.tootls_commonly_list li .tootls span:nth-child(2),
.tootls_host_list li .tootls span:nth-child(2) {
color: #ea7575;
}
.tootls_commonly_list li .tootls span:nth-child(2):hover,
.tootls_host_list li .tootls span:nth-child(2):hover {
color: red;
}
+56
View File
@@ -0,0 +1,56 @@
<div class="main-content">
<div class="container-fluid">
<div class="safe bgw mtb15 pd15 radius4" style="height: 300px;">
<div class="term_box" id="term_box_view">
<div class="term_item_tab">
<div class="list">
<span class="item active" data-host="127.0.0.1" data-id="localhost">
<i class="icon-sucess icon"></i>
<div class="content">
<span>本地服务器</span>
</div>
<span class="icon-trem-close"></span>
</div>
<span class="addServer" title="添加服务器SSH信息">
<span class="glyphicon glyphicon-plus" aria-hidden="true" ></span>
</span>
<span class="tab_tootls">
<span class="glyphicon full_exit_screen glyphicon-resize-full" aria-hidden="true"></span>
<!-- <span>全屏显示</span> -->
</span>
</div>
<!-- 控制台 -->
<div class="term_content_tab">
<div class="term-tool-button tool-hide"><span class="glyphicon glyphicon-menu-right"></span></div>
<div class="term_item active" id="localhost" data-host="127.0.0.1"></div>
</div>
</div>
<div class="term_tootls">
<div class="tab-nav">
<span class="on" data-type="host">服务器列表</span>
<span data-type="shell">常用命令</span>
</div>
<div class="tab-con">
<div class="tab-block on">
<div>
<button class="btn btn-success btn-sm tootls_host_btn" type="button" data-type="host">添加服务器</button>
</div>
<ul class="tootls_host_list"></ul>
</div>
<div class="tab-block">
<div>
<button class="btn btn-success tootls_commonly_btn btn-sm" type="button" data-type="shell">添加命令</button>
</div>
<ul class="tootls_commonly_list"></ul>
</div>
</div>
</div>
</div>
</div>
</div>
+1
View File
@@ -1,2 +1,3 @@
lua_shared_dict mw_total 100m;
lua_need_request_body off;
include {$SERVER_APP}/lua/webstats_log.lua;
+1 -1
View File
@@ -194,7 +194,7 @@
<p onclick="wsOverview();">概览</p>
<p onclick="wsSitesList();">网站列表</p>
<p onclick="wsSpiderStat();">蜘蛛统计</p>
<p onclick="wsClientStat();">客服端统计</p>
<p onclick="wsClientStat();">客户端统计</p>
<p onclick="wsIpStat();">IP统计</p>
<p onclick="wsUriStat();">URI统计</p>
<p onclick="wsSitesErrorLog();">错误日志</p>
+68 -7
View File
@@ -5,6 +5,7 @@ import io
import os
import time
import json
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
@@ -81,6 +82,18 @@ def loadLuaFile(name):
lua_dir = getServerDir() + "/lua"
lua_dst = lua_dir + "/" + name
if not os.path.exists(lua_dst):
lua_tpl = getPluginDir() + '/lua/' + name
content = mw.readFile(lua_tpl)
content = content.replace('{$SERVER_APP}', getServerDir())
content = content.replace('{$ROOT_PATH}', mw.getServerDir())
mw.writeFile(lua_dst, content)
def loadLuaFileReload(name):
lua_dir = getServerDir() + "/lua"
lua_dst = lua_dir + "/" + name
lua_tpl = getPluginDir() + '/lua/' + name
content = mw.readFile(lua_tpl)
content = content.replace('{$SERVER_APP}', getServerDir())
@@ -221,6 +234,15 @@ def initDreplace():
content = content.replace('{$ROOT_PATH}', mw.getServerDir())
mw.writeFile(path, content)
# 已经安装的
al_config = getServerDir() + "/lua/config.json"
if os.path.exists(al_config):
tmp = json.loads(mw.readFile(al_config))
if tmp['global']['record_post_args'] or tmp['global']['record_get_403_args']:
openLuaNeedRequestBody()
else:
closeLuaNeedRequestBody()
lua_dir = getServerDir() + "/lua"
if not os.path.exists(lua_dir):
mw.execShell('mkdir -p ' + lua_dir)
@@ -244,6 +266,11 @@ def initDreplace():
return 'ok'
def luaRestart():
mw.opWeb("stop")
mw.opWeb("start")
def start():
initDreplace()
@@ -253,7 +280,8 @@ def start():
if not mw.isAppleSystem():
mw.execShell("chown -R www:www " + getServerDir())
mw.opWeb("reload")
# issues:326
luaRestart()
return 'ok'
@@ -265,22 +293,30 @@ def stop():
import tool_task
tool_task.removeBgTask()
mw.opWeb("restart")
luaRestart()
return 'ok'
def restart():
initDreplace()
mw.opWeb("reload")
luaRestart()
return 'ok'
def reload():
initDreplace()
file_list = [
'webstats_common.lua',
'webstats_log.lua',
]
for fl in file_list:
loadLuaFileReload(fl)
loadDebugLogFile()
mw.opWeb("restart")
luaRestart()
return 'ok'
@@ -291,6 +327,22 @@ def getGlobalConf():
return mw.returnJson(True, 'ok', content)
def openLuaNeedRequestBody():
conf = luaConf()
content = mw.readFile(conf)
content = re.sub("lua_need_request_body (.*);",
'lua_need_request_body on;', content)
mw.writeFile(conf, content)
def closeLuaNeedRequestBody():
conf = luaConf()
content = mw.readFile(conf)
content = re.sub("lua_need_request_body (.*);",
'lua_need_request_body off;', content)
mw.writeFile(conf, content)
def setGlobalConf():
args = getArgs()
@@ -298,14 +350,23 @@ def setGlobalConf():
content = mw.readFile(conf)
content = json.loads(content)
open_force_get_request_body = False
for v in ['record_post_args', 'record_get_403_args']:
data = checkArgs(args, [v])
if data[0]:
rval = False
if args[v] == "true":
rval = True
open_force_get_request_body = True
content['global'][v] = rval
# 开启强制获取日志配置
if open_force_get_request_body:
openLuaNeedRequestBody()
else:
closeLuaNeedRequestBody()
for v in ['ip_top_num', 'uri_top_num', 'save_day']:
data = checkArgs(args, [v])
if data[0]:
@@ -333,7 +394,7 @@ def setGlobalConf():
mw.writeFile(conf, json.dumps(content))
conf_lua = getServerDir() + "/lua/webstats_config.lua"
listToLuaFile(conf_lua, content)
mw.restartWeb()
luaRestart()
return mw.returnJson(True, '设置成功')
@@ -405,7 +466,7 @@ def setSiteConf():
for v in ['cdn_headers', 'exclude_extension', 'exclude_status', 'exclude_ip']:
data = checkArgs(args, [v])
if data[0]:
site_conf[v] = args[v].split("\\n")
site_conf[v] = args[v].strip().split("\\n")
data = checkArgs(args, ['exclude_url'])
if data[0]:
@@ -426,7 +487,7 @@ def setSiteConf():
mw.writeFile(conf, json.dumps(content))
conf_lua = getServerDir() + "/lua/webstats_config.lua"
listToLuaFile(conf_lua, content)
mw.restartWeb()
luaRestart()
return mw.returnJson(True, '设置成功')
+1 -1
View File
@@ -4,7 +4,7 @@
"name": "webstats",
"title": "网站统计",
"shell": "install.sh",
"versions":["0.2.2"],
"versions":["0.2.3"],
"tip": "soft",
"install_pre_inspection":true,
"checks": "server/webstats",
+7 -1
View File
@@ -14,6 +14,12 @@ install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
sys_os=`uname`
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
HTTP_PREFIX="https://"
if [ ! -z "$cn" ];then
HTTP_PREFIX="https://ghproxy.com/"
fi
if [ "$sys_os" == "Darwin" ];then
BAK='_bak'
else
@@ -97,7 +103,7 @@ Install_App()
# 缓存数据
GEO_VERSION=$(get_latest_release "P3TERX/GeoLite.mmdb")
if [ ! -f $serverPath/source/webstats/GeoLite2-City.mmdb ];then
wget --no-check-certificate -O $serverPath/source/webstats/GeoLite2-City.mmdb https://github.com/P3TERX/GeoLite.mmdb/releases/download/${GEO_VERSION}/GeoLite2-City.mmdb
wget --no-check-certificate -O $serverPath/source/webstats/GeoLite2-City.mmdb ${HTTP_PREFIX}github.com/P3TERX/GeoLite.mmdb/releases/download/${GEO_VERSION}/GeoLite2-City.mmdb
fi
if [ -f $serverPath/source/webstats/GeoLite2-City.mmdb ];then
+1 -3
View File
@@ -853,16 +853,14 @@ function wsSitesListRequest(page){
});
},
yes:function(){
var select = $('#webstats .tab-nav span');
var select_pos = 0;
$('#webstats .tab-nav span').each(function(i){
$('#site_conf .tab-nav span').each(function(i){
if ($(this).hasClass('on')){select_pos = i;}
});
var args = {"site":domain};
if ( [0,1,2,4].indexOf(select_pos)>-1 ){
var setting_cdn = $('textarea[name="setting-cdn"]').val();
// var list = setting_cdn.split('\n')
if ( select_pos == 0 ){
args['cdn_headers'] = setting_cdn;
} else if ( select_pos == 1 ){
+17 -6
View File
@@ -94,7 +94,7 @@ function _M.setInputSn(self, input_sn)
if config[input_sn] == nil then
auto_config = global_config
else
auto_config = config[site]
auto_config = config[input_sn]
for k, v in pairs(global_config) do
if auto_config[k] == nil then
auto_config[k] = v
@@ -202,19 +202,28 @@ function _M.get_http_origin(self)
local data = ""
local headers = ngx.req.get_headers()
if not headers then return data end
if method ~='GET' then
local req_method = ngx.req.get_method()
if req_method ~='GET' then
-- API disabled in the context of log_by_lua*
-- ngx.req.read_body()
data = ngx.req.get_body_data()
-- proxy_pass, fastcgi_pass, uwsgi_pass, and scgi_pass
data = ngx.var.request_body
if not data then
data = ngx.req.get_body_data()
end
if not data then
data = ngx.req.get_post_args(1000000)
end
if "string" == type(data) then
headers["payload"] = data
end
if "table" == type(data) then
headers = table.concat(headers, data)
-- headers = table.concat(headers, data)
headers["payload"] = table.concat(data, "&")
end
end
return json.encode(headers)
@@ -616,7 +625,8 @@ end
function _M._update_stat_pre(self, db, stat_table, key)
local update_stat_stmt = db:prepare(string.format("INSERT INTO %s(time) SELECT :time WHERE NOT EXISTS(SELECT time FROM %s WHERE time=:time);", stat_table, stat_table))
local local_sql = string.format("INSERT INTO %s(time) SELECT :time WHERE NOT EXISTS(SELECT time FROM %s WHERE time=:time);", stat_table, stat_table)
local update_stat_stmt = db:prepare(local_sql)
update_stat_stmt:bind_names{time=key}
update_stat_stmt:step()
update_stat_stmt:finalize()
@@ -632,7 +642,8 @@ end
function _M.update_stat(self, db, stat_table, key, columns)
-- 根据指定表名,更新统计数据
if not columns then return end
local stmt = db:prepare(string.format("INSERT INTO %s(time) SELECT :time WHERE NOT EXISTS(SELECT time FROM %s WHERE time=:time);", stat_table, stat_table))
local local_sql = string.format("INSERT INTO %s(time) SELECT :time WHERE NOT EXISTS(SELECT time FROM %s WHERE time=:time);", stat_table, stat_table)
local stmt = db:prepare(local_sql)
stmt:bind_names{time=key}
local res, err = stmt:step()
stmt:finalize()
+1 -1
View File
@@ -8,7 +8,7 @@ log_by_lua_block {
package.path = cpath .. "?.lua;" .. package.path
end
local ver = '0.2.2'
local ver = '0.2.3'
local debug_mode = true
local __C = require "webstats_common"
+1 -1
View File
@@ -95,7 +95,7 @@ def removeBgTask():
data = api.delete(cfg["task_id"])
if data[0]:
print(data[1])
# print(data[1])
cfg["task_id"] = -1
mw.writeFile(getTaskConf(), json.dumps(cfg))
return True
+2 -14
View File
@@ -1,18 +1,8 @@
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function xhPost(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(str2Obj(args));
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
@@ -31,12 +21,10 @@ function xhPost(method,args,callback){
},'json');
}
function xhAsyncPost(method,args){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(str2Obj(args));
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
+1
View File
@@ -19,6 +19,7 @@ configparser==5.2.0
python-engineio==4.3.2
python-socketio>=4.2.0
flask-socketio==5.2.0
flask_sockets==0.2.1
zmq==0.0.0
paramiko>=2.8.0
pymongo
+46 -125
View File
@@ -8,11 +8,11 @@ import shutil
import uuid
import json
import traceback
import socket
# reload(sys)
# sys.setdefaultencoding('utf-8')
import paramiko
from datetime import timedelta
from flask import Flask
@@ -27,6 +27,7 @@ from flask import render_template_string, abort
from flask_caching import Cache
from flask_session import Session
from whitenoise import WhiteNoise
sys.path.append(os.getcwd() + "/class/core")
@@ -67,6 +68,10 @@ app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'MW_:'
app.config['SESSION_COOKIE_NAME'] = "MW_VER_1"
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=31)
if mw.isAppleSystem():
app.config['DEBUG'] = True
# Session(app)
# 设置BasicAuth
@@ -75,7 +80,7 @@ app.config['BASIC_AUTH_OPEN'] = False
if os.path.exists(basic_auth_conf):
try:
ba_conf = json.loads(mw.readFile(basic_auth_conf))
print(ba_conf)
# print(ba_conf)
app.config['BASIC_AUTH_USERNAME'] = ba_conf['basic_user']
app.config['BASIC_AUTH_PASSWORD'] = ba_conf['basic_pwd']
app.config['BASIC_AUTH_OPEN'] = ba_conf['open']
@@ -88,6 +93,10 @@ from flask_socketio import SocketIO, emit, send
socketio = SocketIO()
socketio.init_app(app)
# sockets
from flask_sockets import Sockets
sockets = Sockets(app)
# from gevent.pywsgi import WSGIServer
# from geventwebsocket.handler import WebSocketHandler
# http_server = WSGIServer(('0.0.0.0', '7200'), app,
@@ -210,7 +219,8 @@ def publicObject(toObject, func, action=None, get=None):
return mw.getJson(data)
except Exception as e:
# API发生错误记录
print(traceback.print_exc())
if mw.isDebugMode():
print(traceback.print_exc())
data = {'msg': '访问异常:' + str(e) + '!', "status": False}
return mw.getJson(data)
@@ -232,7 +242,7 @@ def wellknow(val=None):
return ''
@app.route("/hook")
@app.route("/hook", methods=['POST', 'GET'])
def webhook():
# 仅针对webhook插件
input_args = {
@@ -240,6 +250,12 @@ def webhook():
'params': request.args.get('params', '').strip()
}
if request.method == 'POST':
input_args = {
'access_key': request.form.get('access_key', '').strip(),
'params': request.form.get('params', '').strip()
}
wh_install_path = mw.getServerDir() + '/webhook'
if not os.path.exists(wh_install_path):
return mw.returnJson(False, '请先安装WebHook插件!')
@@ -540,140 +556,45 @@ def index(reqClass=None, reqAction=None, reqData=None):
##################### ssh start ###########################
ssh = None
shell = None
shell_client = None
def create_rsa():
# mw.execShell("rm -f /root/.ssh/*")
if not os.path.exists('/root/.ssh/authorized_keys'):
mw.execShell('touch /root/.ssh/authorized_keys')
@socketio.on('webssh_websocketio')
def webssh_websocketio(data):
if not isLogined():
emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'})
return
if not os.path.exists('/root/.ssh/id_rsa.pub') and os.path.exists('/root/.ssh/id_rsa'):
mw.execShell(
'echo y | ssh-keygen -q -t rsa -P "" -f /root/.ssh/id_rsa')
else:
mw.execShell('ssh-keygen -q -t rsa -P "" -f /root/.ssh/id_rsa')
global shell_client
if not shell_client:
import ssh_terminal
shell_client = ssh_terminal.ssh_terminal()
mw.execShell('cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys')
mw.execShell('chmod 600 /root/.ssh/authorized_keys')
def clear_ssh():
# 服务器IP
ip = mw.getHostAddr()
sh = '''
#!/bin/bash
PLIST=`who | grep localhost | awk '{print $2}'`
for i in $PLIST
do
ps -t /dev/$i |grep -v TTY | awk '{print $1}' | xargs kill -9
done
#getHostAddr
PLIST=`who | grep "${ip}" | awk '{print $2}'`
for i in $PLIST
do
ps -t /dev/$i |grep -v TTY | awk '{print $1}' | xargs kill -9
done
'''
if not mw.isAppleSystem():
info = mw.execShell(sh)
print(info[0], info[1])
def connect_ssh():
# print 'connect_ssh ....'
# clear_ssh()
global shell, ssh
if not os.path.exists('/root/.ssh/id_rsa') or not os.path.exists('/root/.ssh/id_rsa.pub'):
create_rsa()
# 检查是否写入authorized_keys
data = mw.execShell("cat /root/.ssh/id_rsa.pub | awk '{print $3}'")
if data[0] != "":
ak_data = mw.execShell(
"cat /root/.ssh/authorized_keys | grep " + data[0])
if ak_data[0] == "":
mw.execShell(
'cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys')
mw.execShell('chmod 600 /root/.ssh/authorized_keys')
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(mw.getHostAddr(), mw.getSSHPort(), timeout=5)
except Exception as e:
ssh.connect('127.0.0.1', mw.getSSHPort())
except Exception as e:
ssh.connect('localhost', mw.getSSHPort())
except Exception as e:
return False
shell = ssh.invoke_shell(term='xterm', width=83, height=21)
shell.setblocking(0)
return True
shell_client.run(request.sid, data)
return
@socketio.on('webssh')
def webssh(msg):
# print('webssh ...')
global shell
if not isLogined():
emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'})
return None
global shell, ssh
ssh_success = True
if not shell:
ssh_success = connect_ssh()
if not shell:
emit('server_response', {'data': '连接SSH服务失败!\r\n'})
return
shell = mw.connectSsh()
if shell.exit_status_ready():
ssh_success = connect_ssh()
if not ssh_success:
emit('server_response', {'data': '连接SSH服务失败!\r\n'})
return
shell.send(msg)
try:
time.sleep(0.005)
recv = shell.recv(4096)
emit('server_response', {'data': recv.decode("utf-8")})
except Exception as ex:
pass
# print 'webssh:' + str(ex)
@socketio.on('connect_event')
def connected_msg(msg):
if not isLogined():
emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'})
return None
global shell, ssh
ssh_success = True
if not shell:
ssh_success = connect_ssh()
# print(ssh_success)
if not ssh_success:
emit('server_response', {'data': '连接SSH服务失败!\r\n'})
return
try:
recv = shell.recv(8192)
# print recv.decode("utf-8")
emit('server_response', {'data': recv.decode("utf-8")})
except Exception as e:
pass
# print 'connected_msg:' + str(e)
if not mw.isAppleSystem():
try:
import paramiko
ssh = paramiko.SSHClient()
# 启动尝试时连接
# connect_ssh()
except Exception as e:
print("本地终端无法使用")
shell = mw.connectSsh()
if shell:
shell.send(msg)
try:
time.sleep(0.005)
recv = shell.recv(4096)
emit('server_response', {'data': recv.decode("utf-8")})
except Exception as ex:
emit('server_response', {'data': str(ex)})
##################### ssh end ###########################
+1 -1
View File
@@ -506,7 +506,7 @@ function getFiles(Path) {
BarTools += ' <button onclick="javascript:backDir();" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left" title="返回上一级"></button>';
}
setCookie('open_dir_path',rdata.PATH);
BarTools += ' <button onclick="javascript:getFiles(\'' + rdata.PATH + '\');" class="btn btn-default btn-sm glyphicon glyphicon-refresh" title="返回上一级"></button>\
BarTools += ' <button onclick="javascript:getFiles(\'' + rdata.PATH + '\');" class="btn btn-default btn-sm glyphicon glyphicon-refresh" title="刷新"></button>\
<button onclick="webShell()" title="终端" type="button" class="btn btn-default btn-sm"><em class="ico-cmd"></em></button>';
var copyName = getCookie('copyFileName');
var cutName = getCookie('cutFileName');
+3
View File
@@ -123,6 +123,9 @@ function getSshInfo(){
}
$("#firewall_status").html(fStatus);
showAccept(1);
getLogs(1);
},'json');
}
+19 -12
View File
@@ -1525,11 +1525,16 @@ function webShell() {
}
});
$(window).unload(function(){
  term.destroy();
clearInterval(interval);
});
if (socket) {
socket.emit('connect_event', '');
socket.emit('webssh', '');
interval = setInterval(function () {
socket.emit('connect_event', '');
}, 1000);
socket.emit('webssh', '');
}, 500);
}
term.on('data', function (data) {
@@ -1540,7 +1545,7 @@ function webShell() {
var term_box = layer.open({
type: 1,
title: "本地终端",
area: ['685px','435px'],
area: ['685px','463px'],
closeBtn: 1,
shadeClose: false,
content: '<div class="term-box"><div id="term"></div></div>\
@@ -1551,18 +1556,22 @@ function webShell() {
<button class="shellbutton btn btn-default btn-sm pull-right shell_btn_close">关闭</button>\
</div>\
</div>',
success:function(){
$(".shell_btn_close").click(function(){
layer.close(term_box);
term.destroy();
clearInterval(interval);
});
},
cancel: function () {
term.destroy();
clearInterval(interval);
}
});
$(".shell_btn_close").click(function(){
layer.close(term_box);
term.destroy();
clearInterval(interval);
})
setTimeout(function () {
$('.terminal').detach().appendTo('#term');
$("#term").show();
socket.emit('webssh', "\n");
@@ -1649,16 +1658,14 @@ function webShell() {
}
socket.emit('webssh', ptext);
term.focus();
})
});
$("textarea[name='ssh_copy']").keydown(function (e) {
if (e.ctrlKey && e.keyCode == 13) {
$(".shell_btn_1").click();
} else if (e.altKey && e.keyCode == 13) {
$(".shell_btn_1").click();
}
});
}, 100);
}
+14 -3
View File
@@ -5,6 +5,12 @@ function resetPluginWinWidth(width){
$("div[id^='layui-layer'][class*='layui-layer-page']").width(width);
}
//重置插件弹出框宽度
function resetPluginWinHeight(height){
$("div[id^='layui-layer'][class*='layui-layer-page']").height(height);
$(".bt-form .bt-w-main").height(height-42);
}
//软件管理窗口
function softMain(name, title, version) {
@@ -137,11 +143,14 @@ function getSList(isdisplay) {
plugin_title = plugin.title + ' ' + plugin.setup_version;
}
icon_link = "/plugins/file?name="+plugin.name+"&f=ico.png";
if (plugin.icon != ''){
icon_link = "/plugins/file?name="+plugin.name+"&f="+plugin.icon;
}
sBody += '<tr>' +
'<td><span ' + titleClick +
'><img data-src="/plugins/file?name='+plugin.name+
'&f=ico.png" src="/static/img/loading.gif">' + plugin_title + '</span></td>' +
'<td><span ' + titleClick + '>'+
'<img data-src="'+icon_link+'" src="/static/img/loading.gif">' + plugin_title + '</span></td>' +
'<td>' + plugin.ps + '</td>' +
'<td>' + softPath + '</td>' +
'<td>' + state + '</td>' +
@@ -151,6 +160,8 @@ function getSList(isdisplay) {
}
sBody += pBody;
$("#softList").html(sBody);
$(".menu-sub span").click(function() {
setCookie('soft_type', $(this).attr('typeid'));
+9 -31
View File
@@ -3994,7 +3994,7 @@ html .menu .menu_exit:hover {
.menu-sub span {
display: inline-block;
font-size: 14px;
font-size: 13px;
height: 40px;
padding: 0 25px;
cursor: pointer
@@ -4399,7 +4399,8 @@ html .menu .menu_exit:hover {
font-size: 14px;
text-align:center;
}
.cloading{
.cloading {
background-image: url("data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=");
background-repeat: no-repeat;
background-position: center 45px;
@@ -4409,32 +4410,7 @@ html .menu .menu_exit:hover {
text-align: center;
font-size: 14px;
}
/*6.0终端样式*/
.term-box{
padding:0 10px 10px;
background-color:#333333;
}
.shell-text-input .bt-input-text-shell{
width:100%;
padding:10px 10px 0;
border:0 none;
height:60px;
overflow:auto;
resize:none;
}
.shell-text-input .bt-input-text-shell:focus,.shell-text-input .bt-input-text-shell:active{
border:0 none;
outline:none;
}
.shell-btn-group{
height:30px;
position:absolute;
bottom:10px;
right:10px;
}
.shell_btn_close{
margin-right:8px;
}
/*重启*/
.rebt-con {
height: 106px;
@@ -4794,7 +4770,7 @@ select[disabled]{
/*6.0终端样式*/
.term-box{
padding:0 10px 10px;
padding:5px 10px 10px;
background-color:#333333;
}
.shell-text-input .bt-input-text-shell{
@@ -4805,14 +4781,16 @@ select[disabled]{
overflow:auto;
resize:none;
}
.shell-text-input .bt-input-text-shell:focus,.shell-text-input .bt-input-text-shell:active{
border:0 none;
outline:none;
}
.shell-btn-group{
.shell-btn-group {
height:30px;
position:absolute;
bottom:10px;
bottom:20px;
right:10px;
}
.shell_btn_close {
+136
View File
@@ -0,0 +1,136 @@
function Terms_WebSocketIO (el, config) {
if (typeof config == "undefined") {
config = {};
}
this.el = el;
this.id = config.ssh_info.id || '';
this.ws = null; //websocket对象
this.route = 'webssh_websocketio'; // 访问的方法
this.term = null; //term对象
this.info = null; // 请求数据
this.last_body = null;
this.fontSize = 14; //终端字体大小
this.ssh_info = config.ssh_info;
this.term_timer = null;
this.is_connected = false;
this.callback_close = null;
this.callback_connected = null;
this.run();
}
Terms_WebSocketIO.prototype = {
registerCloseCallBack:function(callback){
this.callback_close = callback;
},
registerConnectedCallBack:function(callback){
this.callback_connected = callback;
},
registerExitCallBack:function(callback){
this.callback_exit = callback;
},
connectWs: function (callback) {
this.ws = io.connect();
// console.log(this.ws);
},
connectSsh:function(){
this.send(this.ssh_info);
// this.send('\n');
},
close:function(){
this.ws.disconnect();
this.ws.close();
},
on_message: function (ws_event) {
this.term.write(ws_event.data);
if (ws_event.data == '\r\n登出\r\n' || ws_event.data == '登出\r\n' ||
ws_event.data == '\r\nlogout\r\n' || ws_event.data == 'logout\r\n'||
ws_event.data == '\r\nexit\r\n' || ws_event.data == 'exit\r\n') {
this.term.destroy();
this.ws.disconnect();
this.ws.close();
clearInterval(this.term_timer);
if (this.callback_close){
this.callback_close();
}
}
},
on_connect:function(ws_event){
this.is_connected = true;
if (this.callback_connected){
this.callback_connected();
}
},
on_reconnect:function(ws_event){
this.is_connected = false;
// if (this.callback_connected){
// this.callback_connected();
// }
},
on_exit:function(){
if (this.callback_exit){
this.callback_exit();
}
},
send:function(data){
this.ws.emit(this.route, data);
},
resize: function (size) {
if (this.ws && this.is_connected) {
size['resize'] = 1;
this.send(size)
}
},
run: function (ssh_info) {
this.connectWs();
var that = this;
var termCols = 83;
var termRows = 21;
this.term = new Terminal({fontSize: this.fontSize,screenKeys: true, useStyle: true});
this.term.open($('#'+this.id)[0]);
this.term.setOption('cursorBlink', true);
this.ws.on('server_response', function (ev) { that.on_message(ev)});
this.ws.on('connect', function (ev) { that.on_connect(ev)});
this.ws.on('reconnect', function (ev) { that.on_reconnect(ev)});
this.ws.on('exit', function (ev) { that.on_exit(ev)});
if (this.ws) {
this.term_timer = setInterval(function () {
if (that.is_connected){
that.send('');
} else{
that.on_exit();
}
}, 600);
}
this.term.on('data', function (data) {
if (that.is_connected){
that.send(data);
} else{
that.term.write('\r\n连接丢失,正在尝试重新连接!\r\n');
that.connectSsh();
}
});
this.term.write('\r\n请稍等,正在链接中...\r\n');
this.connectSsh();
this.term.focus();
}
}
+158
View File
@@ -0,0 +1,158 @@
function Terms (el, config) {
if (typeof config == "undefined") config = {};
this.el = el;
this.id = config.ssh_info.id || '';
this.bws = null; //websocket对象
this.route = '/webssh'; // 访问的方法
this.term = null; //term对象
this.info = null; // 请求数据
this.last_body = null;
this.fontSize = 15; //终端字体大小
this.ssh_info = config.ssh_info;
this.run();
}
Terms.prototype = {
// websocket持久化连接
connect: function (callback) {
var that = this;
// 判断当前websocket连接是否存在
if (!this.bws || this.bws.readyState == 3 || this.bws.readyState == 2) {
this.bws = new WebSocket((window.location.protocol === 'http:' ? 'ws://' : 'wss://') + window.location.host + this.route);
this.bws.addEventListener('message', function (ev) { that.on_message(ev) });
this.bws.addEventListener('close', function (ev) { that.on_close(ev) });
this.bws.addEventListener('error', function (ev) { that.on_error(ev) });
this.bws.addEventListener('open', function (ev) { that.on_open(ev) });
if (callback) callback(this.bws)
}
},
//连接服务器成功
on_open: function (ws_event) {
var http_token = $("#request_token_head").attr('token');
this.ssh_info['x-http-token'] = http_token;
this.send(JSON.stringify(this.ssh_info || { 'x-http-token': http_token }))
this.term.FitAddon.fit();
this.resize({ cols: this.term.cols, rows: this.term.rows });
},
//服务器消息事件
on_message: function (ws_event) {
result = ws_event.data;
if (!result) return;
that = this;
if ((result.indexOf("@127.0.0.1:") != -1 || result.indexOf("@localhost:") != -1) && result.indexOf('Authentication failed') != -1) {
that.term.write(result);
host_trem.localhost_login_form(result);
that.close();
return;
}
if (result.length > 1 && that.last_body === false) {
that.last_body = true;
}
that.term.write(result);
that.set_term_icon(1);
if (result == '\r\n登出\r\n' || result == '登出\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') {
that.close();
that.bws = null;
}
},
//websocket关闭事件
on_close: function (ws_event) {
this.set_term_icon(0);
this.bws = null;
},
/**
* @name 设置终端标题状态
* @param {number} status 终端状态
* @return void
*/
set_term_icon: function (status) {
var icon_list = ['icon-warning', 'icon-sucess', 'icon-info'];
if (status == 1) {
if ($("[data-id='" + this.id + "']").attr("class").indexOf('active') == -1) {
status = 2;
}
}
$("[data-id='" + this.id + "']").find('.icon').removeAttr('class').addClass(icon_list[status] + ' icon');
if (status == 2) {
that = this;
setTimeout(function () {
$("[data-id='" + that.id + "']").find('.icon').removeAttr('class').addClass(icon_list[1] + ' icon');
}, 200);
}
},
//websocket错误事件
on_error: function (ws_event) {
if (ws_event.target.readyState === 3) {
// var msg = '错误: 无法创建WebSocket连接,请在面板设置页面关闭【开发者模式】';
// layer.msg(msg,{time:5000})
// if(Term.state === 3) return
// Term.term.write(msg)
// Term.state = 3;
} else {
console.log(ws_event)
}
},
//发送数据
//@param event 唯一事件名称
//@param data 发送的数据
//@param callback 服务器返回结果时回调的函数,运行完后将被回收
send: function (data, num) {
var that = this;
//如果没有连接,则尝试连接服务器
if (!this.bws || this.bws.readyState == 3 || this.bws.readyState == 2) {
this.connect();
}
//判断当前连接状态,如果!=1,则100ms后尝试重新发送
if (this.bws.readyState === 1) {
this.bws.send(data);
} else {
if (this.state === 3) return;
if (!num) num = 0;
if (num < 5) {
num++;
setTimeout(function () { that.send(data, num++); }, 100)
}
}
},
//关闭连接
close: function () {
this.bws.close();
this.set_term_icon(0);
},
resize: function (size) {
if (this.bws) {
size['resize'] = 1;
this.send(JSON.stringify(size));
}
},
run: function (ssh_info) {
var that = this;
this.term = new Terminal({ fontSize: this.fontSize, screenKeys: true, useStyle: true });
this.term.setOption('cursorBlink', true);
this.last_body = false;
this.term.open($(this.el)[0]);
// this.term.FitAddon = new window.FitAddon();
// this.term.loadAddon(this.term.FitAddon);
// this.term.WebLinksAddon = new WebLinksAddon.WebLinksAddon();
// this.term.loadAddon(this.term.WebLinksAddon);
if (ssh_info) this.ssh_info = ssh_info;
this.connect();
that.term.onData(function (data) {
try {
that.bws.send(data);
} catch (e) {
that.term.write('\r\n连接丢失,正在尝试重新连接!\r\n');
that.connect();
}
});
this.term.focus();
}
}
+53 -2
View File
@@ -23,6 +23,14 @@
gtag('js', new Date());
gtag('config', 'G-FC74BB2RGD');
</script>
{% for menu in data['hook_menu'] %}
{% if menu['js_path'] %}
<!-- 加载插件css -->
<link href="/plugins/file?name={{menu['name']}}&v={{config.version}}&f={{menu['css_path']}}" rel="stylesheet" />
{% endif %}
{% endfor %}
</head>
<body>
@@ -33,12 +41,18 @@
<div id="task" class="task cw" onclick="messageBox();"></div>
<h3 class="mypcip"><span class="f14 cw">{{data['ip']}}</span></h3>
<ul class="menu">
<li id="memuA"> <a class="menu_home" href="/">首页</a></li>
<li id="memuA"><a class="menu_home" href="/">首页</a></li>
<li id="memuAsite"><a class="menu_web" href="/site">网站</a></li>
<li id="memuAcontrol"><a class="menu_control" href="/control">监控</a></li>
<li id="memuAfirewall"><a class="menu_firewall" href="/firewall">安全</a></li>
<li id="memuAfiles"><a class="menu_folder" href="/files">文件</a></li>
<li id="memuAcrontab"><a class="menu_day" href="/crontab">计划任务</a></li>
<!-- 插件设置的菜单 -->
{% for menu in data['hook_menu'] %}
<li id="memuAplugins_{{menu['name']}}">
<a class="menu_plugin_{{menu['name']}}" href="/plugins/menu?tag={{menu['name']}}">{{menu['title']}}</a>
</li>
{% endfor %}
<li id="memuAsoft"><a class="menu_soft" href="/soft">软件管理</a><span class="softnum">1</span></li>
<li id="memuAconfig"><a class="menu_set" href="/config">面板设置</a></li>
<li><a class="menu_exit" href="javascript:;" id="signout">退出</a></li>
@@ -61,6 +75,7 @@
<script src="/static/build/addons/fullscreen/fullscreen.js?v={{config.version}}"></script>
<script src="/static/js/socket.io.min.js?v={{config.version}}"></script>
<script src="/static/build/addons/winptyCompat/winptyCompat.js?v={{config.version}}"></script>
<script src="/static/js/term-websocketio.js?v={{config.version}}"></script>
<script src="/static/app/upload.js?v={{config.version}}"></script>
<script src="/static/app/public.js?v={{config.version}}"></script>
<script src="/static/js/echarts.min.js?v={{config.version}}"></script>
@@ -77,6 +92,14 @@
<script type="text/javascript">
(function ($) {
$.getUrlParam = function (name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
})(jQuery);
function showAd(){
layer.open({
type: 1
@@ -103,8 +126,29 @@ function showAd(){
$('.panel_ad_list_mode').click(function(){
showAd();
});
</script>
function getUrlPath(){
var thisUrl = window.location.href;
var pathArr = thisUrl.split('/');
return pathArr[pathArr.length - 1];
}
var thisPath = getUrlPath();
if (thisPath.indexOf('?')>-1){
var tag = $.getUrlParam('tag');
if(tag != undefined){
$('#memuAplugins_'+tag).css('background-color','#2c3138');
} else {
$('#memuA').css('background-color','#f2f2f2');
}
} else{
if(thisPath != undefined){
$('#memuA'+thisPath).css('background-color','#2c3138');
} else {
$('#memuA').css('background-color','#f2f2f2');
}
}
</script>
<script src="/static/codemirror/lib/codemirror.js?v={{config.version}}"></script>
<script src="/static/codemirror/addon/edit/editAll.js?v={{config.version}}"></script>
<script src="/static/codemirror/mode/modeAll.js?v={{config.version}}"></script>
@@ -113,4 +157,11 @@ $('.panel_ad_list_mode').click(function(){
<script src="/static/codemirror/addon/scroll/annotatescrollbar.js?v={{config.version}}"></script>
<script src="/static/laydate/laydate.js?v={{config.version}}"></script>
{% for menu in data['hook_menu'] %}
{% if menu['js_path'] %}
<!-- 加载插件js -->
<script src="/plugins/file?name={{menu['name']}}&f={{menu['js_path']}}&v={{config.version}}"></script>
{% endif %}
{% endfor %}
</html>
+4
View File
@@ -0,0 +1,4 @@
{% extends "layout.html" %}
{% block content %}
{{data['plugin_content']|safe }}
{% endblock %}
+13 -1
View File
@@ -14,7 +14,7 @@
PATH=/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export LANG=en_US.UTF-8
# export LANG=en_US.UTF-8
mw_path={$SERVER_PATH}
PATH=$PATH:$mw_path/bin
@@ -215,6 +215,17 @@ mw_update_dev()
cd /www/server/mdserver-web
}
mw_mirror()
{
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
if [ ! -z "$cn" ];then
bash <(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh)
else
bash <(curl -sSL https://raw.githubusercontent.com/midoks/change-linux-mirrors/main/change-mirrors.sh)
fi
cd /www/server/mdserver-web
}
mw_install_app()
{
bash $mw_path/scripts/quick/app.sh
@@ -280,6 +291,7 @@ case "$1" in
'close_admin_path') mw_close_admin_path;;
'unbind_domain') mw_unbind_domain;;
'debug') mw_debug;;
'mirror') mw_mirror;;
'default')
cd $mw_path
port=7200
+8 -4
View File
@@ -50,7 +50,6 @@ if [ -f /usr/sbin/ufw ];then
# ufw allow 7200/tcp
# ufw allow 3306/tcp
# ufw allow 30000:40000/tcp
fi
if [ -f /usr/sbin/ufw ];then
@@ -58,8 +57,13 @@ if [ -f /usr/sbin/ufw ];then
fi
if [ ! -f /usr/sbin/ufw ];then
# look
# firewall-cmd --list-all
apt install -y firewalld
systemctl enable firewalld
#取消服务锁定
systemctl unmask firewalld
systemctl start firewalld
firewall-cmd --permanent --zone=public --add-port=22/tcp
@@ -75,10 +79,10 @@ if [ ! -f /usr/sbin/ufw ];then
sed -i 's#IndividualCalls=no#IndividualCalls=yes#g' /etc/firewalld/firewalld.conf
firewall-cmd --reload
fi
#安装时不开启
systemctl stop firewalld
#安装时不开启
systemctl stop firewalld
fi
#fix zlib1g-dev fail
echo -e "\e[0;32mfix zlib1g-dev install question start\e[0m"
+6 -1
View File
@@ -43,7 +43,12 @@ if [ -f /usr/sbin/iptables ];then
iptables_status=`systemctl status iptables | grep 'inactive'`
if [ "${iptables_status}" != '' ];then
service iptables restart
# iptables -P FORWARD DROP
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -p tcp -s 127.0.0.1 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-5
View File
@@ -74,11 +74,6 @@ $CP_CMD -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
rm -rf /tmp/master.zip
rm -rf /tmp/mdserver-web-master
if [ -f /etc/rc.d/init.d/mw ];then
sh /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
#pip uninstall public
echo "use system version: ${OSNAME}"
cd /www/server/mdserver-web && bash scripts/update/${OSNAME}.sh
+3
View File
@@ -14,6 +14,9 @@ sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+3
View File
@@ -16,6 +16,9 @@ yum install -y curl-devel libmcrypt libmcrypt-devel python3-devel
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+3 -3
View File
@@ -8,12 +8,12 @@ LANG=en_US.UTF-8
# echo y | pacman -Sy yaourt
# echo y | pacman -Sy python3
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "start mw"
cd /www/server/mdserver-web && bash cli.sh start
+3
View File
@@ -16,6 +16,9 @@ yum install -y curl-devel libmcrypt libmcrypt-devel python3-devel
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+12 -5
View File
@@ -3,11 +3,15 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
export DEBIAN_FRONTEND=noninteractive
apt install -y locate
locale-gen en_US.UTF-8
export LC_CTYPE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
# apt install -y locate
# locale-gen C.UTF-8
# export LC_CTYPE=C.UTF-8
# export LC_ALL=C.UTF-8
# export LANG=C.UTF-8
# echo "LC_ALL=en_US.UTF-8" > /etc/default/locale
# echo "LANG=en_US.UTF-8" > /etc/default/locale
if grep -Eq "Ubuntu" /etc/*-release; then
@@ -28,6 +32,9 @@ fi
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+3
View File
@@ -13,6 +13,9 @@ sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+3
View File
@@ -8,6 +8,9 @@ cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "start mw"
cd /www/server/mdserver-web && bash cli.sh start
+3
View File
@@ -11,6 +11,9 @@ LANG=en_US.UTF-8
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "start mw"
cd /www/server/mdserver-web && bash cli.sh start
+4
View File
@@ -16,6 +16,10 @@ fi
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+4
View File
@@ -18,6 +18,10 @@ cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+3
View File
@@ -16,6 +16,9 @@ cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
if [ -f /etc/rc.d/init.d/mw ];then
bash /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
echo -e "stop mw"
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
+8 -9
View File
@@ -64,20 +64,19 @@ fi
# wget -O /tmp/dev.zip https://github.com/midoks/mdserver-web/archive/refs/heads/dev.zip
cd /tmp && unzip /tmp/dev.zip
CP_CMD=/usr/bin/cp
if [ -f /bin/cp ];then
CP_CMD=/bin/cp
echo "update mdserver-web code start"
if [ -f /usr/bin/cp ];then
/usr/bin/cp -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
elif [ -f /bin/cp ];then
/bin/cp -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
else
/usr/bin/cp -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
fi
$CP_CMD -rf /tmp/mdserver-web-dev/* /www/server/mdserver-web
echo "update mdserver-web code end"
rm -rf /tmp/dev.zip
rm -rf /tmp/mdserver-web-dev
if [ -f /etc/rc.d/init.d/mw ];then
sh /etc/rc.d/init.d/mw stop && rm -rf /www/server/mdserver-web/scripts/init.d/mw && rm -rf /etc/rc.d/init.d/mw
fi
#pip uninstall public
echo "use system version: ${OSNAME}"
cd /www/server/mdserver-web && bash scripts/update/${OSNAME}.sh
+18 -15
View File
@@ -47,20 +47,21 @@ def mwcli(mw_input=0):
raw_tip = "======================================================"
if not mw_input:
print("===============mdserver-web cli tools=================")
print("(1) 重启面板服务")
print("(2) 停止面板服务")
print("(3) 启动面板服务")
print("(4) 重载面板服务")
print("(5) 修改面板端口")
print("(10) 查看面板默认信息")
print("(11) 修改面板密码")
print("(12) 修改面板用户名")
print("(13) 显示面板错误日志")
print("(20) 关闭BasicAuth认证")
print("(21) 解除域名绑定")
print("(100) 开启PHP52显示")
print("(101) 关闭PHP52显示")
print("(0) 取消")
print("(1) 重启面板服务")
print("(2) 停止面板服务")
print("(3) 启动面板服务")
print("(4) 重载面板服务")
print("(5) 修改面板端口")
print("(10) 查看面板默认信息")
print("(11) 修改面板密码")
print("(12) 修改面板用户名")
print("(13) 显示面板错误日志")
print("(20) 关闭BasicAuth认证")
print("(21) 解除域名绑定")
print("(100) 开启PHP52显示")
print("(101) 关闭PHP52显示")
print("(200) 切换Linux系统软件源")
print("(0) 取消")
print(raw_tip)
try:
mw_input = input("请输入命令编号:")
@@ -69,7 +70,7 @@ def mwcli(mw_input=0):
except:
mw_input = 0
nums = [1, 2, 3, 4, 5, 10, 11, 12, 13, 20, 21, 100, 101]
nums = [1, 2, 3, 4, 5, 10, 11, 12, 13, 20, 21, 100, 101, 200]
if not mw_input in nums:
print(raw_tip)
print("已取消!")
@@ -135,6 +136,8 @@ def mwcli(mw_input=0):
cont = re.sub("\"5.2.17\",", cont)
mw.writeFile(php_conf, cont)
print("|-执行PHP52隐藏成功!")
elif mw_input == 200:
os.system(INIT_CMD + " mirror")
def set_panel_pwd(password, ncli=False):