Merge pull request #628 from midoks/dev

0.17.4
pull/630/head 0.17.4
Mr Chen 11 months ago committed by GitHub
commit 2438717c79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      .gitignore
  2. 5
      README.md
  3. 4
      class/core/config_api.py
  4. 4
      class/core/files_api.py
  5. 6
      class/core/logs_api.py
  6. 14
      class/core/mw.py
  7. 2
      class/core/plugins_api.py
  8. 120
      class/core/site_api.py
  9. 2
      class/core/system_api.py
  10. 1
      clear.sh
  11. 2
      data/tpl/nginx.conf
  12. 113
      new_cli.sh
  13. 626
      panel_task.py
  14. 306
      panel_tools.py
  15. BIN
      plugins/alist/ico.png
  16. 31
      plugins/alist/index.html
  17. 292
      plugins/alist/index.py
  18. 17
      plugins/alist/info.json
  19. 13
      plugins/alist/init.d/alist.service.tpl
  20. 46
      plugins/alist/init.d/alist.tpl
  21. 94
      plugins/alist/install.sh
  22. 92
      plugins/alist/js/alist.js
  23. 5
      plugins/clean/index.py
  24. BIN
      plugins/cloudreve/ico.png
  25. 31
      plugins/cloudreve/index.html
  26. 288
      plugins/cloudreve/index.py
  27. 17
      plugins/cloudreve/info.json
  28. 13
      plugins/cloudreve/init.d/cloudreve.service.tpl
  29. 46
      plugins/cloudreve/init.d/cloudreve.tpl
  30. 91
      plugins/cloudreve/install.sh
  31. 82
      plugins/cloudreve/js/cloudreve.js
  32. 8
      plugins/data_query/nosql_memcached.py
  33. 7
      plugins/data_query/nosql_mongodb.py
  34. 9
      plugins/data_query/nosql_redis.py
  35. 8
      plugins/data_query/sql_mysql.py
  36. 2
      plugins/data_query/static/html/index.html
  37. 6
      plugins/docker/index.py
  38. 4
      plugins/fail2ban/index.html
  39. 126
      plugins/fail2ban/index.py
  40. 2
      plugins/fail2ban/info.json
  41. 7
      plugins/fail2ban/install.sh
  42. 58
      plugins/fail2ban/js/fail2ban.js
  43. 25
      plugins/fail2ban/tpl/fail2ban.d/default.conf
  44. 2
      plugins/fail2ban/tpl/jail.d/default.conf
  45. 11
      plugins/fail2ban/tpl/jail.d/sshd.conf
  46. 6
      plugins/gitea/index.py
  47. 18
      plugins/gogs/index.py
  48. 2
      plugins/gorse/index.py
  49. 6
      plugins/memcached/index.py
  50. 2
      plugins/mongodb/scripts/backup.py
  51. 2
      plugins/mongodb/versions/5.0/centos.sh
  52. 2
      plugins/mongodb/versions/5.0/debian.sh
  53. 2
      plugins/mongodb/versions/5.0/macos.sh
  54. 2
      plugins/mongodb/versions/5.0/opensuse.sh
  55. 2
      plugins/mongodb/versions/5.0/ubuntu.sh
  56. 2
      plugins/mongodb/versions/6.0/debian.sh
  57. 2
      plugins/mongodb/versions/6.0/macos.sh
  58. 2
      plugins/mongodb/versions/6.0/opensuse.sh
  59. 2
      plugins/mongodb/versions/6.0/ubuntu.sh
  60. 2
      plugins/mongodb/versions/7.0/centos.sh
  61. 7
      plugins/mongodb/versions/7.0/debian.sh
  62. 2
      plugins/mongodb/versions/7.0/euler.sh
  63. 2
      plugins/mongodb/versions/7.0/macos.sh
  64. 2
      plugins/mongodb/versions/7.0/opensuse.sh
  65. 2
      plugins/mongodb/versions/7.0/ubuntu.sh
  66. 2
      plugins/msonedrive/install.sh
  67. 2
      plugins/mysql-apt/index.py
  68. 5
      plugins/mysql/index.py
  69. 32
      plugins/mysql/js/mysql.js
  70. 3
      plugins/pgadmin/init.d/pgadmin.service.tpl
  71. 2
      plugins/pgadmin/install.sh
  72. 4
      plugins/php/info.json
  73. 4
      plugins/php/versions/81/install.sh
  74. 21
      plugins/php/versions/84/install.sh
  75. 5
      plugins/php/versions/common/mcrypt.sh
  76. 6
      plugins/php/versions/common/redis.sh
  77. 87
      plugins/php/versions/phplib.conf
  78. 2
      plugins/redis/index.py
  79. 12
      plugins/rsyncd/index.py
  80. 2
      plugins/simpleping/index.py
  81. 16
      plugins/simpleping/simpleping_index.py
  82. 8
      plugins/task_manager/task_manager_index.py
  83. 2
      plugins/tgbot/startup/extend/push_notice_msg.py
  84. 8
      plugins/webstats/webstats_index.py
  85. 6
      requirements.txt
  86. 2
      scripts/init.d/mw-task.service.tpl
  87. 10
      scripts/init.d/mw.tpl
  88. 7
      scripts/install.sh
  89. 8
      scripts/install_dev.sh
  90. 182
      scripts/install_new.sh
  91. 4
      scripts/quick/app.sh
  92. 8
      scripts/update.sh
  93. 7
      scripts/update_dev.sh
  94. 4
      version/r3.7.txt
  95. 236
      web/admin/__init__.py
  96. 37
      web/admin/common.py
  97. 34
      web/admin/crontab/__init__.py
  98. 240
      web/admin/dashboard/__init__.py
  99. 156
      web/admin/files/__init__.py
  100. 84
      web/admin/firewall/__init__.py
  101. Some files were not shown because too many files have changed in this diff Show More

3
.gitignore vendored

@ -183,3 +183,6 @@ plugins/tidb
plugins/goedge-admin
plugins/goedge-node
plugins/goedge-happy
plugins/dztasks
data/default_new.pl

@ -182,6 +182,11 @@ curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_new.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_new.sh | bash
```
### 捐赠地址 USDT(TRC20)

@ -28,7 +28,7 @@ from flask import request
class config_api:
__version = '0.17.3'
__version = '0.17.4'
__api_addr = 'data/api.json'
# 统一默认配置文件
@ -42,7 +42,7 @@ class config_api:
'bind_domain' : 'data/bind_domain.pl', # 面板域名绑定
'unauth_status' : 'data/unauthorized_status.pl', # URL路径未成功显示状态
'auth_secret': 'data/auth_secret.pl', # 二次验证密钥
'ssl':'ssl/choose.pl', # ssl设置
'ssl':'ssl/choose.pl', # ssl设置
'hook_database' : 'data/hook_database.json', # 数据库钩子
'hook_menu' : 'data/hook_menu.json', # 菜单钩子
'hook_global_static' : 'data/hook_global_static.json', # 静态文件钩子

@ -1074,9 +1074,9 @@ class files_api:
order_arr = order.split(' ')
if len(order_arr) < 2:
plist = mw.sortFileList(path, order_arr[0],'')
plist = mw.sortFileList(path, order_arr[0], '')
else:
plist = mw.sortFileList(path, order_arr[0],order_arr[1])
plist = mw.sortFileList(path, order_arr[0], order_arr[1])
for filename in plist:
if search:

@ -173,14 +173,12 @@ class logs_api:
def __to_date2(self, date_str):
tmp = date_str.split()
s_date = str(tmp[-1]) + '-' + self.__months.get(tmp[1],
tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
s_date = str(tmp[-1]) + '-' + self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
return s_date
def __to_date3(self, date_str):
tmp = date_str.split()
s_date = str(datetime.now().year) + '-' + \
self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
s_date = str(datetime.now().year) + '-' + self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
return s_date
def __to_date4(self, date_str):

@ -593,8 +593,11 @@ def writeLog(stype, msg, args=()):
if 'uid' in session:
uid = session['uid']
except Exception as e:
pass
print('writeL:',e)
# pass
# writeFileLog(getTracebackInfo())
print(stype, msg)
return writeDbLog(stype, msg, args, uid)
@ -716,11 +719,9 @@ def enPunycode(domain):
newdomain += dkey + '.'
else:
if sys.version_info[0] == 2:
newdomain += 'xn--' + \
dkey.decode('utf-8').encode('punycode') + '.'
newdomain += 'xn--' + dkey.decode('utf-8').encode('punycode') + '.'
else:
newdomain += 'xn--' + \
dkey.encode('punycode').decode('utf-8') + '.'
newdomain += 'xn--' + dkey.encode('punycode').decode('utf-8') + '.'
if tmp[0] == '*':
newdomain = "*." + newdomain
return newdomain[0:-1]
@ -732,8 +733,7 @@ def dePunycode(domain):
newdomain = ''
for dkey in tmp:
if dkey.find('xn--') >= 0:
newdomain += dkey.replace('xn--',
'').encode('utf-8').decode('punycode') + '.'
newdomain += dkey.replace('xn--','').encode('utf-8').decode('punycode') + '.'
else:
newdomain += dkey + '.'
return newdomain[0:-1]

@ -663,7 +663,7 @@ class plugins_api:
return mw.readFile(version_f).strip()
return ''
# 构造本地插件信息
# 构造本地插件信息
def getPluginInfo(self, info):
checks = ''
path = ''

@ -727,43 +727,43 @@ class site_api:
conf = mw.readFile(file)
if conf:
rep = "\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_certificate\s+.+;\s+ssl_certificate_key\s+.+;"
rep = "\\s+ssl_certificate\\s+.+;\\s+ssl_certificate_key\\s+.+;"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_protocols\s+.+;\n"
rep = "\\s+ssl_protocols\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_ciphers\s+.+;\n"
rep = "\\s+ssl_ciphers\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_prefer_server_ciphers\s+.+;\n"
rep = "\\s+ssl_prefer_server_ciphers\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_cache\s+.+;\n"
rep = "\\s+ssl_session_cache\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_timeout\s+.+;\n"
rep = r"\s+ssl_session_timeout\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_ecdh_curve\s+.+;\n"
rep = r"\s+ssl_ecdh_curve\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_tickets\s+.+;\n"
rep = r"\s+ssl_session_tickets\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_stapling\s+.+;\n"
rep = r"\s+ssl_stapling\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_stapling_verify\s+.+;\n"
rep = r"\s+ssl_stapling_verify\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+add_header\s+.+;\n"
rep = r"\s+add_header\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+add_header\s+.+;\n"
rep = r"\s+add_header\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl\s+on;"
rep = r"\s+ssl\s+on;"
conf = re.sub(rep, '', conf)
rep = "\s+error_page\s497.+;"
rep = r"\s+error_page\s497.+;"
conf = re.sub(rep, '', conf)
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
rep = r"\s+if.+server_port.+\n.+\n\s+\s*}"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+443.*;"
rep = r"\s+listen\s+443.*;"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+\[\:\:\]\:443.*;"
rep = r"\s+listen\s+\[\:\:\]\:443.*;"
conf = re.sub(rep, '', conf)
rep = "\s+http2\s+on;"
rep = r"\s+http2\s+on;"
conf = re.sub(rep, '', conf)
mw.writeFile(file, conf)
@ -888,7 +888,7 @@ class site_api:
# fix binddir domain ssl apply question
mw.backFile(host_conf_file)
auth_to = self.getSitePath(siteName)
rep = "\s*root\s*(.+);"
rep = r"\s*root\s*(.+);"
replace_root = "\n\troot " + auth_to + ";"
siteConf = re.sub(rep, replace_root, siteConf)
mw.writeFile(host_conf_file, siteConf)
@ -1043,7 +1043,7 @@ class site_api:
src_path = mw.getAcmeDomainDir(domains[0])
src_cert = src_path + '/fullchain.cer'
src_key = src_path + '/' + domains[0] + '.key'
src_cert.replace("\*", "*")
src_cert.replace("\\*", "*")
msg = '签发失败,您尝试申请证书的失败次数已达上限!<p>1、检查域名是否绑定到对应站点</p>\
<p>2检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
@ -1115,9 +1115,9 @@ class site_api:
file = self.getHostConf(site_name)
conf = mw.readFile(file)
if conf:
rep = "\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
rep = r"\n\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
conf = re.sub(rep, '', conf)
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
rep = r"\s+if.+server_port.+\n.+\n\s+\s*}"
conf = re.sub(rep, '', conf)
mw.writeFile(file, conf)
@ -1282,7 +1282,7 @@ class site_api:
domain_name = self.toPunycode(domain[0])
domain_port = '80'
reg = "^([\w\-\*]{1,100}\.){1,4}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
reg = r"^([\w\-\*]{1,100}\.){1,4}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
if not re.match(reg, domain_name):
return mw.returnJson(False, '域名格式不正确!')
@ -1339,7 +1339,7 @@ class site_api:
if dirName == '':
mw.returnJson(False, '目录不能为空!')
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
reg = r"^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
if not re.match(reg, domain):
return mw.returnJson(False, '主域名格式不正确!')
@ -1355,7 +1355,7 @@ class site_api:
filename = self.getHostConf(siteInfo['name'])
conf = mw.readFile(filename)
if conf:
rep = "enable-php-([0-9]{2,3})\.conf"
rep = r"enable-php-([0-9]{2,3})\.conf"
tmp = re.search(rep, conf).groups()
version = tmp[0]
@ -1507,7 +1507,7 @@ class site_api:
filename = self.getHostConf(siteName)
if os.path.exists(filename):
conf = mw.readFile(filename)
rep = '\s*root\s*(.+);'
rep = r'\s*root\s*(.+);'
path = re.search(rep, conf).groups()[0]
conf = conf.replace(path, newPath)
mw.writeFile(filename, conf)
@ -1578,7 +1578,7 @@ class site_api:
if os.path.exists(configFile):
conf = mw.readFile(configFile)
rep = "\n\s*#AUTH_START(.|\n){1,200}#AUTH_END"
rep = r"\n\s*#AUTH_START(.|\n){1,200}#AUTH_END"
conf = re.sub(rep, '', conf)
mw.writeFile(configFile, conf)
@ -1604,19 +1604,19 @@ class site_api:
conf = mw.readFile(file)
if conf:
# 删除域名
rep = "server_name\s+(.+);"
rep = r"server_name\s+(.+);"
tmp = re.search(rep, conf).group()
newServerName = tmp.replace(' ' + domain + ';', ';')
newServerName = newServerName.replace(' ' + domain + ' ', ' ')
conf = conf.replace(tmp, newServerName)
# 删除端口
rep = "listen\s+([0-9]+);"
rep = r"listen\s+([0-9]+);"
tmp = re.findall(rep, conf)
port_count = mw.M('domain').where(
'pid=? AND port=?', (pid, port)).count()
if mw.inArray(tmp, port) == True and port_count < 2:
rep = "\n*\s+listen\s+" + port + ";"
rep = r"\n*\s+listen\s+" + port + ";"
conf = re.sub(rep, '', conf)
# 保存配置
mw.writeFile(file, conf)
@ -1778,7 +1778,7 @@ class site_api:
if item["r_from"] == _from:
return mw.returnJson(False, "重复的规则!")
rep = "http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
rep = r"http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
if not re.match(rep, _to):
return mw.returnJson(False, "错误的目标地址")
@ -1942,7 +1942,7 @@ class site_api:
if _name == "" or _siteName == "" or _from == "" or _to == "" or _host == "":
return mw.returnJson(False, "必填项不能为空")
rep = "http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
rep = r"http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
if not re.match(rep, _to):
return mw.returnJson(False, "错误的目标地址!")
@ -1990,7 +1990,7 @@ location ^~ {from} {\n\
}\n\
# PROXY-END"
tpl_proxy_cache = "\n\
tpl_proxy_cache = r"\n\
if ( $uri ~* \"\.(gif|png|jpg|css|js|woff|woff2)$\" )\n\
{\n\
expires {cache_time}m;\n\
@ -2001,7 +2001,7 @@ location ^~ {from} {\n\
proxy_cache_valid 200 304 301 302 {cache_time}m;\n\
"
tpl_proxy_nocache = "\n\
tpl_proxy_nocache = r"\n\
set $static_files_app 0; \n\
if ( $uri ~* \"\.(gif|png|jpg|css|js|woff|woff2)$\" )\n\
{\n\
@ -2219,7 +2219,7 @@ location ^~ {from} {\n\
file = self.getHostConf(siteName)
if os.path.exists(file):
conf = mw.readFile(file)
rep = '\s*root\s*(.+);'
rep = r'\s*root\s*(.+);'
find_cnf = re.search(rep, conf)
if not find_cnf:
return ''
@ -2236,7 +2236,7 @@ location ^~ {from} {\n\
filename = self.getHostConf(siteName)
if os.path.exists(filename):
conf = mw.readFile(filename)
rep = '\s*root\s*(.+);'
rep = r'\s*root\s*(.+);'
path = re.search(rep, conf).groups()[0]
data = {}
@ -2321,7 +2321,7 @@ location ^~ {from} {\n\
def getSitePhpVersion(self, siteName):
conf = mw.readFile(self.getHostConf(siteName))
rep = "enable-php-(.*)\.conf"
rep = r"enable-php-(.*)\.conf"
find_php_cnf = re.search(rep, conf)
def_pver = '00'
@ -2337,7 +2337,7 @@ location ^~ {from} {\n\
siteName = mw.M('sites').where("id=?", (sid,)).getField('name')
file = self.getHostConf(siteName)
conf = mw.readFile(file)
rep = "\s+index\s+(.+);"
rep = r"\s+index\s+(.+);"
tmp = re.search(rep, conf).groups()
return tmp[0].replace(' ', ',')
@ -2356,7 +2356,7 @@ location ^~ {from} {\n\
file = self.getHostConf(siteName)
conf = mw.readFile(file)
if conf:
rep = "\s+index\s+.+;"
rep = r"\s+index\s+.+;"
conf = re.sub(rep, "\n\tindex " + index_l + ";", conf)
mw.writeFile(file, conf)
@ -2370,17 +2370,17 @@ location ^~ {from} {\n\
data = {}
conf = mw.readFile(filename)
try:
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
rep = r"\s+limit_conn\s+perserver\s+([0-9]+);"
tmp = re.search(rep, conf).groups()
data['perserver'] = int(tmp[0])
# IP并发限制
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
rep = r"\s+limit_conn\s+perip\s+([0-9]+);"
tmp = re.search(rep, conf).groups()
data['perip'] = int(tmp[0])
# 请求并发限制
rep = "\s+limit_rate\s+([0-9]+)\w+;"
rep = r"\s+limit_rate\s+([0-9]+)\w+;"
tmp = re.search(rep, conf).groups()
data['limit_rate'] = int(tmp[0])
except:
@ -2410,15 +2410,15 @@ location ^~ {from} {\n\
conf = mw.readFile(filename)
if(conf.find('limit_conn perserver') != -1):
# 替换总并发
rep = "limit_conn\s+perserver\s+([0-9]+);"
rep = r"limit_conn\s+perserver\s+([0-9]+);"
conf = re.sub(rep, str_perserver, conf)
# 替换IP并发限制
rep = "limit_conn\s+perip\s+([0-9]+);"
rep = r"limit_conn\s+perip\s+([0-9]+);"
conf = re.sub(rep, str_perip, conf)
# 替换请求流量限制
rep = "limit_rate\s+([0-9]+)\w+;"
rep = r"limit_rate\s+([0-9]+)\w+;"
conf = re.sub(rep, str_limit_rate, conf)
else:
conf = conf.replace('#error_page 404/404.html;', "#error_page 404/404.html;\n " +
@ -2434,15 +2434,15 @@ location ^~ {from} {\n\
filename = self.getHostConf(siteName)
conf = mw.readFile(filename)
# 清理总并发
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
rep = r"\s+limit_conn\s+perserver\s+([0-9]+);"
conf = re.sub(rep, '', conf)
# 清理IP并发限制
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
rep = r"\s+limit_conn\s+perip\s+([0-9]+);"
conf = re.sub(rep, '', conf)
# 清理请求流量限制
rep = "\s+limit_rate\s+([0-9]+)\w+;"
rep = r"\s+limit_rate\s+([0-9]+)\w+;"
conf = re.sub(rep, '', conf)
mw.writeFile(filename, conf)
mw.restartWeb()
@ -2458,15 +2458,15 @@ location ^~ {from} {\n\
rep = "#SECURITY-START(\n|.){1,500}#SECURITY-END"
tmp = re.search(rep, conf).group()
data['fix'] = re.search(
"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
r"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
data['status'] = False
data['none'] = False
valid_referers = re.search(
"valid_referers\s+(.+);\n", tmp)
r"valid_referers\s+(.+);\n", tmp)
valid_referers_none = re.search(
"valid_referers\s+none\s+blocked\s+(.+);\n", tmp)
r"valid_referers\s+none\s+blocked\s+(.+);\n", tmp)
if valid_referers or valid_referers_none:
data['status'] = True
@ -2500,11 +2500,11 @@ location ^~ {from} {\n\
if os.path.exists(file):
conf = mw.readFile(file)
if status == 'false':
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
rep = r"\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
conf = re.sub(rep, '', conf)
mw.writeLog('网站管理', '站点[' + name + ']已关闭防盗链设置!')
else:
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
rep = r"\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
conf = re.sub(rep, '', conf)
valid_referers = domains.strip().replace(',', ' ')
@ -2512,8 +2512,8 @@ location ^~ {from} {\n\
valid_referers = 'none blocked ' + valid_referers
pre_path = self.setupPath + "/php/conf"
re_path = "include\s+" + pre_path + "/enable-php-"
rconf = '''#SECURITY-START 防盗链配置
re_path = r"include\s+" + pre_path + "/enable-php-"
rconf = r'''#SECURITY-START 防盗链配置
location ~ .*\.(%s)$
{
expires 30d;
@ -2555,7 +2555,7 @@ location ^~ {from} {\n\
conf_dir = mw.getServerDir() + "/web_conf/php/conf"
conf_list = os.listdir(conf_dir)
l = len(conf_list)
rep = "enable-php-(.*?)\.conf"
rep = r"enable-php-(.*?)\.conf"
for name in conf_list:
tmp = {}
try:
@ -2611,7 +2611,7 @@ location ^~ {from} {\n\
return
# 添加域名
rep = "server_name\s*(.*);"
rep = r"server_name\s*(.*);"
tmp = re.search(rep, conf).group()
domains = tmp.split(' ')
if not mw.inArray(domains, domain):
@ -2619,7 +2619,7 @@ location ^~ {from} {\n\
conf = conf.replace(tmp, newServerName)
# 添加端口
rep = "listen\s+([0-9]+)\s*[default_server]*\s*;"
rep = r"listen\s+([0-9]+)\s*[default_server]*\s*;"
tmp = re.findall(rep, conf)
if not mw.inArray(tmp, port):
listen = re.search(rep, conf).group()
@ -2820,7 +2820,7 @@ location ^~ {from} {\n\
conf = conf.replace('#error_page 404/404.html;', sslStr)
rep = "listen\s+([0-9]+)\s*[default_server|reuseport]*;"
rep = r"listen\s+([0-9]+)\s*[default_server|reuseport]*;"
tmp = re.findall(rep, conf)
if not mw.inArray(tmp, '443'):
listen = re.search(rep, conf).group()

@ -717,7 +717,6 @@ class system_api:
self.cache[iokey] = {'info':diskio_group,'time':mtime}
except Exception as e:
# print(mw.getTracebackInfo())
pass
return diskInfo
@ -866,6 +865,7 @@ class system_api:
return {}
def updateServer(self, stype, version=''):
return mw.returnJson(False, '与后续版本差异太大,不再提供更新')
# 更新服务
try:
if not mw.isRestart():

@ -3,5 +3,6 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/usr/loc
find . -name .DS_Store -print0 | xargs -0 git rm -f --ignore-unmatch
find . -name .DS_Store | xargs rm -rf
find . -type d -name "*.pyc" | xargs rm -rf

@ -40,7 +40,7 @@ server
allow all;
}
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf|js|css)$
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf|js|css|ttf|woff2)$
{
expires 30d;
error_log /dev/null;

@ -0,0 +1,113 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
DIR=$(cd "$(dirname "$0")"; pwd)
MDIR=$(dirname "$DIR")
# echo $DIR
PATH=$PATH:$DIR/bin
if [ -f ${DIR}/bin/activate ];then
source ${DIR}/bin/activate
if [ "$?" != "0" ];then
echo "load local python env fail!"
fi
fi
export LC_ALL="en_US.UTF-8"
mw_start_task()
{
isStart=$(ps aux |grep 'panel_task.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "starting mw-tasks... \c"
cd $DIR && python3 panel_task.py >> ${DIR}/logs/panel_task.log 2>&1 &
sleep 0.3
isStart=$(ps aux |grep 'panel_task.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "\033[31mfailed\033[0m"
echo '------------------------------------------------------'
tail -n 20 $DIR/logs/panel_task.log
echo '------------------------------------------------------'
echo -e "\033[31mError: mw-tasks service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "starting mw-tasks... mw-tasks (pid $(echo $isStart)) already running"
fi
}
mw_start(){
cd web && gunicorn -c setting.py app:app
#安全启动
mw_start_task
}
mw_start_debug(){
if [ ! -f $DIR/logs/panel_task.log ];then
echo '' > $DIR/logs/panel_task.log
fi
python3 panel_task.py >> $DIR/logs/panel_task.log 2>&1 &
port=7200
if [ -f /www/server/mdserver-web/data/port.pl ];then
port=$(cat /www/server/mdserver-web/data/port.pl)
fi
if [ -f ${DIR}/data/port.pl ];then
port=$(cat ${DIR}/data/port.pl)
fi
# gunicorn -b :${port} -k gevent -w 1 app:app
cd web && gunicorn -b :${port} -w 1 app:app
}
mw_start_debug2(){
python3 panel_task.py >> $DIR/logs/panel_task.log 2>&1 &
gunicorn -b :7200 -w 1 app:app
}
mw_start_debug3(){
gunicorn -c setting.py app:app
python3 panel_task.py
}
mw_stop()
{
PLIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
for i in $PLIST
do
kill -9 $i > /dev/null 2>&1
done
pids=`ps -ef|grep panel_task.py | grep -v grep |awk '{print $2}'`
arr=($pids)
for p in ${arr[@]}
do
kill -9 $p > /dev/null 2>&1
done
}
case "$1" in
'start') mw_start;;
'stop') mw_stop;;
'restart')
mw_stop
mw_start
;;
'debug')
mw_stop
mw_start_debug
;;
'debug2')
mw_stop
mw_start_debug2
;;
'debug3')
mw_stop
mw_start_debug3
;;
esac

@ -0,0 +1,626 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 计划任务
# ---------------------------------------------------------------------------------
import sys
import os
import json
import time
import threading
import psutil
web_dir = os.getcwd() + "/web"
os.chdir(web_dir)
sys.path.append(web_dir)
from admin import app
from admin import model
import core.mw as mw
import core.db as db
# print(mw.getPanelDir())
# print sys.path
# cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
# info = mw.execShell(cmd)
# p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
# sys.path.append(p)
global pre, timeoutCount, logPath, isTask, oldEdate, isCheck
pre = 0
timeoutCount = 0
isCheck = 0
oldEdate = None
g_log_file = mw.getPanelTaskLog()
isTask = mw.getMWLogs() + '/panelTask.pl'
if not os.path.exists(g_log_file):
os.system("touch " + g_log_file)
def execShell(cmdstring, cwd=None, timeout=None, shell=True):
try:
global g_log_file
import shlex
import datetime
import subprocess
if timeout:
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
cmd = cmdstring + ' > ' + g_log_file + ' 2>&1'
sub = subprocess.Popen(cmd, cwd=cwd, stdin=subprocess.PIPE, shell=shell, bufsize=4096)
while sub.poll() is None:
time.sleep(0.1)
data = sub.communicate()
# python3 fix 返回byte数据
if isinstance(data[0], bytes):
t1 = str(data[0], encoding='utf-8')
if isinstance(data[1], bytes):
t2 = str(data[1], encoding='utf-8')
return (t1, t2)
except Exception as e:
return (None, None)
def service_cmd(method):
cmd = '/etc/init.d/mw'
if os.path.exists(cmd):
execShell(cmd + ' ' + method)
return
cmd = mw.getRunDir() + '/scripts/init.d/mw'
if os.path.exists(cmd):
execShell(cmd + ' ' + method)
return
def openresty_cmd(method = 'reload'):
# 检查是否安装
odir = mw.getServerDir() + '/openresty'
if not os.path.exists(odir):
return False
# systemd
systemd = mw.systemdCfgDir()+'/openresty.service'
if os.path.exists(systemd):
execShell('systemctl ' + method + ' openresty')
return True
sys_initd = '/etc/init.d/openresty'
if os.path.exists(sys_initd):
os.system(sys_initd + ' ' + method)
return True
install_initd = mw.getServerDir()+'/openresty/init.d/openresty'
if os.path.exists(install_initd):
os.system(install_initd + ' ' + method)
return True
return False
def mw_async(f):
def wrapper(*args, **kwargs):
thr = threading.Thread(target=f, args=args, kwargs=kwargs)
thr.start()
return wrapper
@mw_async
def restartMw():
time.sleep(1)
cmd = mw.getRunDir() + '/scripts/init.d/mw reload &'
mw.execShell(cmd)
def downloadFile(url, filename):
# 下载文件
try:
import urllib
import socket
socket.setdefaulttimeout(300)
headers = ('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36')
opener = urllib.request.build_opener()
opener.addheaders = [headers]
urllib.request.install_opener(opener)
urllib.request.urlretrieve(url, filename=filename, reporthook=downloadHook)
if not mw.isAppleSystem():
os.system('chown www.www ' + filename)
writeLogs('done')
except Exception as e:
writeLogs(str(e))
return True
def downloadHook(count, blockSize, totalSize):
# 下载文件进度回调
global pre
used = count * blockSize
pre1 = int((100.0 * used / totalSize))
if pre == (100 - pre1):
return
speed = {'total': totalSize, 'used': used, 'pre': pre1}
writeLogs(json.dumps(speed))
def writeLogs(data):
# 写输出日志
try:
fp = open(g_log_file, 'w+')
fp.write(data)
fp.close()
except:
pass
def runPanelTask():
try:
bash_list = model.getTaskList(status=-1)
for task in bash_list:
model.setTaskStatus(task['id'], 0)
run_list = model.getTaskList(status=0)
for run_task in run_list:
start = int(time.time())
model.setTaskData(run_task['id'], start=start)
model.setTaskStatus(run_task['id'], -1)
if run_task['type'] == 'download':
argv = run_task['cmd'].split('|mw|')
downloadFile(argv[0], argv[1])
elif run_task['type'] == 'execshell':
execShell(run_task['cmd'])
end = int(time.time())
model.setTaskData(run_task['id'], end=end)
model.setTaskStatus(run_task['id'], 1)
except Exception as e:
print(str(e))
# 站点过期检查
# siteEdate()
# 任务队列
def startPanelTask():
try:
while True:
runPanelTask()
time.sleep(1)
except Exception as e:
print(str(e))
time.sleep(10)
startPanelTask()
# 网站到期处理
def siteEdate():
global oldEdate
try:
if not oldEdate:
oldEdate = mw.readFile('data/edate.pl')
if not oldEdate:
oldEdate = '0000-00-00'
mEdate = time.strftime('%Y-%m-%d', time.localtime())
if oldEdate == mEdate:
return False
edateSites = mw.M('sites').where('edate>? AND edate<? AND (status=? OR status=?)',
('0000-00-00', mEdate, 1, '正在运行')).field('id,name').select()
import site_api
for site in edateSites:
site_api.site_api().stop(site['id'], site['name'])
oldEdate = mEdate
mw.writeFile('data/edate.pl', mEdate)
except Exception as e:
print(str(e))
def systemTask():
# 系统监控任务
try:
import system_api
import psutil
sm = system_api.system_api()
filename = 'data/control.conf'
sql = db.Sql().dbfile('system')
csql = mw.readFile('data/sql/system.sql')
csql_list = csql.split(';')
for index in range(len(csql_list)):
sql.execute(csql_list[index], ())
cpuIo = cpu = {}
cpuCount = psutil.cpu_count()
used = count = 0
reloadNum = 0
network_up = network_down = diskio_1 = diskio_2 = networkInfo = cpuInfo = diskInfo = None
while True:
if not os.path.exists(filename):
time.sleep(10)
continue
day = 30
try:
day = int(mw.readFile(filename))
if day < 1:
time.sleep(10)
continue
except:
day = 30
tmp = {}
# 取当前CPU Io
tmp['used'] = psutil.cpu_percent(interval=1)
if tmp['used'] > 80:
panel_title = mw.getConfig('title')
ip = mw.getHostAddr()
now_time = mw.getDateFromNow()
msg = now_time + '|节点[' + panel_title + ':' + ip + \
']处于高负载[' + str(tmp['used']) + '],请排查原因!'
mw.notifyMessage(msg, '面板监控', 600)
if not cpuInfo:
tmp['mem'] = sm.getMemUsed()
cpuInfo = tmp
if cpuInfo['used'] < tmp['used']:
tmp['mem'] = sm.getMemUsed()
cpuInfo = tmp
# 取当前网络Io
networkIo = sm.psutilNetIoCounters()
if not network_up:
network_up = networkIo[0]
network_down = networkIo[1]
tmp = {}
tmp['upTotal'] = networkIo[0]
tmp['downTotal'] = networkIo[1]
tmp['up'] = round(float((networkIo[0] - network_up) / 1024), 2)
tmp['down'] = round(float((networkIo[1] - network_down) / 1024), 2)
tmp['downPackets'] = networkIo[3]
tmp['upPackets'] = networkIo[2]
network_up = networkIo[0]
network_down = networkIo[1]
if not networkInfo:
networkInfo = tmp
if (tmp['up'] + tmp['down']) > (networkInfo['up'] + networkInfo['down']):
networkInfo = tmp
# 取磁盘Io
# if os.path.exists('/proc/diskstats'):
diskio_2 = psutil.disk_io_counters()
if not diskio_1:
diskio_1 = diskio_2
tmp = {}
tmp['read_count'] = diskio_2.read_count - diskio_1.read_count
tmp['write_count'] = diskio_2.write_count - diskio_1.write_count
tmp['read_bytes'] = diskio_2.read_bytes - diskio_1.read_bytes
tmp['write_bytes'] = diskio_2.write_bytes - diskio_1.write_bytes
tmp['read_time'] = diskio_2.read_time - diskio_1.read_time
tmp['write_time'] = diskio_2.write_time - diskio_1.write_time
if not diskInfo:
diskInfo = tmp
else:
diskInfo['read_count'] += tmp['read_count']
diskInfo['write_count'] += tmp['write_count']
diskInfo['read_bytes'] += tmp['read_bytes']
diskInfo['write_bytes'] += tmp['write_bytes']
diskInfo['read_time'] += tmp['read_time']
diskInfo['write_time'] += tmp['write_time']
diskio_1 = diskio_2
# print diskInfo
if count >= 12:
try:
addtime = int(time.time())
deltime = addtime - (day * 86400)
data = (cpuInfo['used'], cpuInfo['mem'], addtime)
sql.table('cpuio').add('pro,mem,addtime', data)
sql.table('cpuio').where("addtime<?", (deltime,)).delete()
data = (networkInfo['up'] / 5, networkInfo['down'] / 5, networkInfo['upTotal'], networkInfo[
'downTotal'], networkInfo['downPackets'], networkInfo['upPackets'], addtime)
sql.table('network').add(
'up,down,total_up,total_down,down_packets,up_packets,addtime', data)
sql.table('network').where(
"addtime<?", (deltime,)).delete()
# if os.path.exists('/proc/diskstats'):
data = (diskInfo['read_count'], diskInfo['write_count'], diskInfo['read_bytes'], diskInfo[
'write_bytes'], diskInfo['read_time'], diskInfo['write_time'], addtime)
sql.table('diskio').add(
'read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime', data)
sql.table('diskio').where(
"addtime<?", (deltime,)).delete()
# LoadAverage
load_average = sm.getLoadAverage()
lpro = round(
(load_average['one'] / load_average['max']) * 100, 2)
if lpro > 100:
lpro = 100
sql.table('load_average').add('pro,one,five,fifteen,addtime', (lpro, load_average[
'one'], load_average['five'], load_average['fifteen'], addtime))
lpro = None
load_average = None
cpuInfo = None
networkInfo = None
diskInfo = None
count = 0
reloadNum += 1
if reloadNum > 1440:
reloadNum = 0
mw.writeFile('logs/sys_interrupt.pl',
"reload num:" + str(reloadNum))
restartMw()
except Exception as ex:
print(str(ex))
mw.writeFile('logs/sys_interrupt.pl', str(ex))
del(tmp)
time.sleep(5)
count += 1
except Exception as ex:
print(str(ex))
mw.writeFile('logs/sys_interrupt.pl', str(ex))
restartMw()
time.sleep(30)
systemTask()
# -------------------------------------- PHP监控 start --------------------------------------------- #
# 502错误检查线程
def check502Task():
try:
while True:
if os.path.exists(mw.getPanelDir() + '/data/502Task.pl'):
check502()
time.sleep(30)
except:
time.sleep(30)
check502Task()
def check502():
try:
verlist = [
'52', '53', '54', '55', '56', '70',
'71', '72', '73', '74', '80', '81',
'82', '83', '84'
]
for ver in verlist:
sdir = mw.getServerDir()
php_path = sdir + '/php/' + ver + '/sbin/php-fpm'
if not os.path.exists(php_path):
continue
if checkPHPVersion(ver):
continue
if startPHPVersion(ver):
print('检测到PHP-' + ver + '处理异常,已自动修复!')
mw.writeLog('PHP守护程序', '检测到PHP-' + ver + '处理异常,已自动修复!')
except Exception as e:
print(str(e))
# 处理指定PHP版本
def startPHPVersion(version):
sdir = mw.getServerDir()
try:
# system
phpService = mw.systemdCfgDir() + '/php' + version + '.service'
if os.path.exists(phpService):
mw.execShell("systemctl restart php" + version)
if checkPHPVersion(version):
return True
# initd
fpm = sdir + '/php/init.d/php' + version
php_path = sdir + '/php/' + version + '/sbin/php-fpm'
if not os.path.exists(php_path):
if os.path.exists(fpm):
os.remove(fpm)
return False
if not os.path.exists(fpm):
return False
# 尝试重载服务
os.system(fpm + ' reload')
if checkPHPVersion(version):
return True
# 尝试重启服务
cgi = '/tmp/php-cgi-' + version + '.sock'
pid = sdir + '/php/' + version + '/var/run/php-fpm.pid'
data = mw.execShell("ps -ef | grep php/" + version +" | grep -v grep|grep -v python |awk '{print $2}'")
if data[0] != '':
os.system("ps -ef | grep php/" + version + " | grep -v grep|grep -v python |awk '{print $2}' | xargs kill ")
time.sleep(0.5)
if not os.path.exists(cgi):
os.system('rm -f ' + cgi)
if not os.path.exists(pid):
os.system('rm -f ' + pid)
os.system(fpm + ' start')
if checkPHPVersion(version):
return True
# 检查是否正确启动
if os.path.exists(cgi):
return True
except Exception as e:
print(str(e))
return True
def getFpmConfFile(version):
return mw.getServerDir() + '/php/' + version + '/etc/php-fpm.d/www.conf'
def getFpmAddress(version):
fpm_address = '/tmp/php-cgi-{}.sock'.format(version)
php_fpm_file = getFpmConfFile(version)
try:
content = readFile(php_fpm_file)
tmp = re.findall(r"listen\s*=\s*(.+)", content)
if not tmp:
return fpm_address
if tmp[0].find('sock') != -1:
return fpm_address
if tmp[0].find(':') != -1:
listen_tmp = tmp[0].split(':')
if bind:
fpm_address = (listen_tmp[0], int(listen_tmp[1]))
else:
fpm_address = ('127.0.0.1', int(listen_tmp[1]))
else:
fpm_address = ('127.0.0.1', int(tmp[0]))
return fpm_address
except:
return fpm_address
def checkPHPVersion(version):
# 检查指定PHP版本
try:
sock = getFpmAddress(version)
data = mw.requestFcgiPHP(sock, '/phpfpm_status_' + version + '?json')
result = str(data, encoding='utf-8')
except Exception as e:
result = 'Bad Gateway'
# print(version,result)
# 检查openresty
if result.find('Bad Gateway') != -1:
return False
if result.find('HTTP Error 404: Not Found') != -1:
return False
# 检查Web服务是否启动
if result.find('Connection refused') != -1:
return False
# global isTask
# if os.path.exists(isTask):
# isStatus = mw.readFile(isTask)
# if isStatus == 'True':
# return True
# # systemd
# systemd = mw.systemdCfgDir() + '/openresty.service'
# if os.path.exists(systemd):
# execShell('systemctl reload openresty')
# return True
# # initd
# initd = '/etc/init.d/openresty'
# if os.path.exists(initd):
# os.system(initd + ' reload')
return True
# --------------------------------------PHP监控 end--------------------------------------------- #
# --------------------------------------OpenResty Auto Restart Start --------------------------------------------- #
# 解决acme.sh续签后,未起效。
def openrestyAutoRestart():
try:
while True:
# 检查是否安装
odir = mw.getServerDir() + '/openresty'
if not os.path.exists(odir):
time.sleep(86400)
continue
openresty_cmd('reload')
time.sleep(86400)
except Exception as e:
print(str(e))
time.sleep(86400)
# --------------------------------------OpenResty Auto Restart End --------------------------------------------- #
# ------------------------------------ OpenResty Restart At Once Start ------------------------------------------ #
def openrestyRestartAtOnce():
restart_nginx_tip = 'data/restart_nginx.pl'
while True:
if os.path.exists(restart_nginx_tip):
os.remove(restart_nginx_tip)
openresty_cmd('reload')
time.sleep(1)
# ----------------------------------- OpenResty Restart At Once End ------------------------------------------ #
# --------------------------------------Panel Restart Start --------------------------------------------- #
def restartPanelService():
restartTip = 'data/restart.pl'
while True:
if os.path.exists(restartTip):
os.remove(restartTip)
service_cmd('restart_panel')
time.sleep(1)
# --------------------------------------Panel Restart End --------------------------------------------- #
def setDaemon(t):
if sys.version_info.major == 3 and sys.version_info.minor >= 10:
t.daemon = True
else:
t.setDaemon(True)
return t
def run():
# # 系统监控
# sysTask = threading.Thread(target=systemTask)
# sysTask = setDaemon(sysTask)
# sysTask.start()
# # PHP 502错误检查线程
# php502 = threading.Thread(target=check502Task)
# php502 = setDaemon(php502)
# php502.start()
# # OpenResty Restart At Once Start
# oraos = threading.Thread(target=openrestyRestartAtOnce)
# oraos = setDaemon(oraos)
# oraos.start()
# # OpenResty Auto Restart Start
# oar = threading.Thread(target=openrestyAutoRestart)
# oar = setDaemon(oar)
# oar.start()
# # Panel Restart Start
# rps = threading.Thread(target=restartPanelService)
# rps = setDaemon(rps)
# rps.start()
# 面板后台任务
startPanelTask()
if __name__ == "__main__":
with app.app_context():
run()

@ -0,0 +1,306 @@
# coding=utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 工具箱
# ---------------------------------------------------------------------------------
import sys
import os
import json
import time
import re
web_dir = os.getcwd() + "/web"
os.chdir(web_dir)
sys.path.append(web_dir)
import core.mw as mw
import core.db as db
# cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
# info = mw.execShell(cmd)
# p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
# sys.path.append(p)
INIT_DIR = "/etc/rc.d/init.d"
if mw.isAppleSystem():
INIT_DIR = mw.getPanelDir() + "/scripts/init.d"
INIT_CMD = INIT_DIR + "/mw"
def mw_input_cmd(msg):
if sys.version_info[0] == 2:
in_val = raw_input(msg)
else:
in_val = input(msg)
return in_val
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("(22) 解除面板SSL绑定")
print("(23) 开启IPV6支持")
print("(24) 关闭IPV6支持")
print("(25) 开启防火墙SSH端口")
print("(26) 关闭二次验证")
print("(27) 查看防火墙信息")
print("(100) 开启PHP52显示")
print("(101) 关闭PHP52显示")
print("(200) 切换Linux系统软件源")
print("(201) 简单速度测试")
print("(0) 取消")
print(raw_tip)
try:
mw_input = input("请输入命令编号:")
if sys.version_info[0] == 3:
mw_input = int(mw_input)
except:
mw_input = 0
nums = [
1, 2, 3, 4, 5, 10, 11, 12, 13,
20, 21, 22, 23, 24, 25, 26, 27,
100, 101,
200, 201
]
if not mw_input in nums:
print(raw_tip)
print("已取消!")
exit()
if mw_input == 1:
os.system(INIT_CMD + " restart")
elif mw_input == 2:
os.system(INIT_CMD + " stop")
elif mw_input == 3:
os.system(INIT_CMD + " start")
elif mw_input == 4:
os.system(INIT_CMD + " reload")
elif mw_input == 5:
in_port = mw_input_cmd("请输入新的面板端口:")
in_port_int = int(in_port.strip())
if in_port_int < 65536 and in_port_int > 0:
import firewall_api
firewall_api.firewall_api().addAcceptPortArgs(
in_port, 'WEB面板[TOOLS修改]', 'port')
mw.writeFile('data/port.pl', in_port)
os.system(INIT_CMD + " restart_panel")
os.system(INIT_CMD + " default")
else:
print("|-端口范围在0-65536之间")
return
elif mw_input == 10:
os.system(INIT_CMD + " default")
elif mw_input == 11:
input_pwd = mw_input_cmd("请输入新的面板密码:")
if len(input_pwd.strip()) < 5:
print("|-错误,密码长度不能小于5位")
return
set_panel_pwd(input_pwd.strip(), True)
elif mw_input == 12:
input_user = mw_input_cmd("请输入新的面板用户名(>=5位):")
set_panel_username(input_user.strip())
elif mw_input == 13:
os.system('tail -100 ' + mw.getPanelDir() + '/logs/error.log')
elif mw_input == 20:
basic_auth = 'data/basic_auth.json'
if os.path.exists(basic_auth):
os.remove(basic_auth)
os.system(INIT_CMD + " restart")
print("|-关闭basic_auth成功")
elif mw_input == 21:
bind_domain = 'data/bind_domain.pl'
if os.path.exists(bind_domain):
os.remove(bind_domain)
os.system(INIT_CMD + " unbind_domain")
print("|-解除域名绑定成功")
elif mw_input == 22:
ssl_choose = 'ssl/choose.pl'
if os.path.exists(ssl_choose):
os.remove(ssl_choose)
os.system(INIT_CMD + " unbind_ssl")
print("|-解除面板SSL绑定成功")
elif mw_input == 23:
listen_ipv6 = 'data/ipv6.pl'
if not os.path.exists(listen_ipv6):
mw.writeFile(listen_ipv6,'True')
os.system(INIT_CMD + " restart")
print("|-开启IPv6支持了")
else:
print("|-已开启IPv6支持!")
elif mw_input == 24:
listen_ipv6 = 'data/ipv6.pl'
if not os.path.exists(listen_ipv6):
print("|-已关闭IPv6支持!")
else:
os.remove(listen_ipv6)
os.system(INIT_CMD + " restart")
print("|-关闭IPv6支持了")
elif mw_input == 25:
open_ssh_port()
print("|-已开启!")
elif mw_input == 26:
auth_secret = 'data/auth_secret.pl'
if os.path.exists(auth_secret):
os.remove(auth_secret)
print("|-关闭二次验证成功!")
else:
print("|-二次验证已关闭!")
elif mw_input == 27:
cmd = 'which ufw'
run_cmd = False
find_cmd = mw.execShell(cmd)
if find_cmd[0].strip() != '':
run_cmd = True
os.system('ufw status')
cmd = 'which firewall-cmd'
find_cmd = mw.execShell(cmd)
if find_cmd[0].strip() != '':
run_cmd = True
os.system('firewall-cmd --list-all')
if not run_cmd:
mw.echoInfo("未检测到防火墙!")
elif mw_input == 100:
php_conf = 'plugins/php/info.json'
if os.path.exists(php_conf):
cont = mw.readFile(php_conf)
cont = re.sub("\"53\"", "\"52\",\"53\"", cont)
cont = re.sub("\"5.3.29\"", "\"5.2.17\",\"5.3.29\"", cont)
mw.writeFile(php_conf, cont)
print("|-执行PHP52显示成功!")
elif mw_input == 101:
php_conf = 'plugins/php/info.json'
if os.path.exists(php_conf):
cont = mw.readFile(php_conf)
cont = re.sub("\"52\",", "", cont)
cont = re.sub("\"5.2.17\",", cont)
mw.writeFile(php_conf, cont)
print("|-执行PHP52隐藏成功!")
elif mw_input == 200:
os.system(INIT_CMD + " mirror")
elif mw_input == 201:
os.system('curl -Lso- bench.sh | bash')
def open_ssh_port():
import firewall_api
find_ssh_port_cmd = "cat /etc/ssh/sshd_config | grep '^Port \\d*' | tail -1"
cmd_data = mw.execShell(find_ssh_port_cmd)
ssh_port = cmd_data[0].replace("Port ", '').strip()
if ssh_port == '':
ssh_port = '22'
print("|-SSH端口: "+ str(ssh_port))
firewall_api.firewall_api().addAcceptPortArgs(ssh_port, 'SSH远程管理服务', 'port')
return True
def set_panel_pwd(password, ncli=False):
# 设置面板密码
import db
sql = db.Sql()
result = sql.table('users').where('id=?', (1,)).setField(
'password', mw.md5(password))
username = sql.table('users').where('id=?', (1,)).getField('username')
if ncli:
print("|-用户名: " + username)
print("|-新密码: " + password)
else:
print(username)
def show_panel_pwd():
# 设置面板密码
import db
sql = db.Sql()
password = sql.table('users').where('id=?', (1,)).getField('password')
file_pwd = ''
if os.path.exists('data/default.pl'):
file_pwd = mw.readFile('data/default.pl').strip()
if mw.md5(file_pwd) == password:
print('password: ' + file_pwd)
return
print("password has been changed!")
def set_panel_username(username=None):
# 随机面板用户名
import db
sql = db.Sql()
if username:
if len(username) < 5:
print("|-错误,用户名长度不能少于5位")
return
if username in ['admin', 'root']:
print("|-错误,不能使用过于简单的用户名")
return
sql.table('users').where('id=?', (1,)).setField('username', username)
print("|-新用户名: %s" % username)
return
username = sql.table('users').where('id=?', (1,)).getField('username')
if username == 'admin':
username = mw.getRandomString(8).lower()
sql.table('users').where('id=?', (1,)).setField('username', username)
print('username: ' + username)
def getServerIp():
version = sys.argv[2]
# ip = mw.execShell(
# "curl --insecure -{} -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text".format(version))
ip = mw.execShell(
"curl --insecure -{} -sS --connect-timeout 5 -m 60 https://ip.cachecha.com/?format=text".format(version))
print(ip[0])
if __name__ == "__main__":
method = sys.argv[1]
if method == 'panel':
set_panel_pwd(sys.argv[2])
elif method == 'username':
if len(sys.argv) > 2:
set_panel_username(sys.argv[2])
else:
set_panel_username()
elif method == 'password':
show_panel_pwd()
elif method == 'getServerIp':
getServerIp()
elif method == "cli":
clinum = 0
try:
if len(sys.argv) > 2:
clinum = int(sys.argv[2]) if sys.argv[2][:6] else sys.argv[2]
except:
clinum = sys.argv[2]
mwcli(clinum)
else:
print('ERROR: Parameter error')

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

@ -0,0 +1,31 @@
<style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('alist');">服务</p>
<p onclick="pluginInitD('alist');">自启动</p>
<p onclick="alistCommonFunc();">常用功能</p>
<p onclick="pluginConfigTpl('alist',$('.plugin_version').attr('version'));">配置修改</p>
<p onclick="pluginLogs('alist','','run_log');">运行日志</p>
<p onclick="alistReadme();">相关说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=alist&f=js/alist.js", function(){
pluginService('alist', $('.plugin_version').attr('version'));
});
</script>

@ -0,0 +1,292 @@
# coding:utf-8
import sys
import io
import os
import time
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'alist'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def getConf():
path = getServerDir() + "/data/config.json"
return path
def configTpl():
path = getPluginDir() + '/tpl'
pathFile = os.listdir(path)
tmp = []
for one in pathFile:
file = path + '/' + one
tmp.append(file)
return mw.getJson(tmp)
def readConfigTpl():
args = getArgs()
data = checkArgs(args, ['file'])
if not data[0]:
return data[1]
content = mw.readFile(args['file'])
content = contentReplace(content)
return mw.returnJson(True, 'ok', content)
def status():
data = mw.execShell(
"ps aux|grep alist |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$SERVER_APP}', service_path + '/'+getPluginName())
return content
def initDreplace():
file_tpl = getInitDTpl()
service_path = os.path.dirname(os.getcwd())
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
# initd replace
if not os.path.exists(file_bin):
content = mw.readFile(file_tpl)
content = content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(file_bin, content)
mw.execShell('chmod +x ' + file_bin)
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/' + getPluginName() + '.service'
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(systemService, se_content)
mw.execShell('systemctl daemon-reload')
return file_bin
def alistOp(method):
file = initDreplace()
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
if current_os.startswith("freebsd"):
data = mw.execShell('service ' + getPluginName() + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
if data[1] == '':
return 'ok'
return data[1]
def start():
return alistOp('start')
def stop():
return alistOp('stop')
def restart():
status = alistOp('restart')
return status
def reload():
return alistOp('reload')
def initdStatus():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initdInstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
# freebsd initd install
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
return 'ok'
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
def initdUinstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
return 'ok'
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
def runLog():
return getServerDir() + '/data/log/log.log'
def pSqliteDb(dbname='databases'):
pos_file = getServerDir() + '/data/'
file = pos_file + '/data.db'
name = 'data'
conn = mw.M(dbname).dbPos(pos_file, name)
return conn
def clearCopyTask():
conn = pSqliteDb('x_task_items')
conn.where('key=?', ('copy',)).setField('persist_data','[]')
restart()
return mw.returnJson(True, '清空成功并重启服务!')
def homePage():
import json
content = mw.readFile(getConf())
data = json.loads(content)
http_port = data['scheme']['http_port']
ip = mw.getLocalIp()
if mw.isAppleSystem():
ip = '127.0.0.1'
url = 'http://'+ip+":"+str(http_port)
# print(url)
return mw.returnJson(True, 'ok!', url)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'conf':
print(getConf())
elif func == 'run_log':
print(runLog())
elif func == 'config_tpl':
print(configTpl())
elif func == 'read_config_tpl':
print(readConfigTpl())
elif func == 'clear_copy_task':
print(clearCopyTask())
elif func == 'home_page':
print(homePage())
else:
print('error')

@ -0,0 +1,17 @@
{
"sort": 7,
"ps": "一个支持多种存储的文件列表程序",
"name": "alist",
"title": "Alist",
"shell": "install.sh",
"versions":["3.37.4","3.38.0"],
"tip": "soft",
"checks": "server/alist",
"path": "server/alist",
"display": 1,
"author": "alist",
"date": "2022-10-09",
"home": "https://alist.nn.ci",
"type": 0,
"pid": "5"
}

@ -0,0 +1,13 @@
[Unit]
Description=A file list program that supports multiple storage
After=network.target
[Service]
Type=simple
WorkingDirectory={$SERVER_PATH}/alist
ExecStart={$SERVER_PATH}/alist/alist server
ExecReload=/bin/kill -USR2 $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target

@ -0,0 +1,46 @@
#!/bin/sh
# chkconfig: 2345 55 25
# description: alist Service
### BEGIN INIT INFO
# Provides: alist
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts alist
# Description: starts the MDW-Web
### END INIT INFO
# Simple alist init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
app_start(){
echo "Starting alist server..."
cd {$SERVER_PATH}/alist
./alist server >> {$SERVER_PATH}/alist/logs.pl 2>&1 &
}
app_stop(){
echo "dztasks stopped"
ps -ef| grep alist | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'| xargs kill
}
case "$1" in
start)
app_start
;;
stop)
app_stop
;;
restart|reload)
app_stop
sleep 0.3
app_start
;;
*)
echo "Please use start or stop as first argument"
;;
esac

@ -0,0 +1,94 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/alist && bash install.sh install 3.37.4
# cd /www/server/mdserver-web/plugins/alist && bash install.sh install 3.37.4
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
sysArch=`arch`
sysName=`uname`
ALIST_ARCH_NAME=amd64
if [ "$sysArch" == "arm64" ];then
ALIST_ARCH_NAME=arm64
elif [ "$sysArch" == "x86_64" ]; then
ALIST_ARCH_NAME=amd64
elif [ "$sysArch" == "aarch64" ]; then
ALIST_ARCH_NAME=arm64
fi
ALIST_NAME=linux
if [ "$sysName" == "Darwin" ];then
ALIST_NAME=darwin
fi
Install_App()
{
echo '正在安装脚本文件...'
mkdir -p $serverPath/source
mkdir -p $serverPath/source/alist
FILE_TGZ=alist-${ALIST_NAME}-${ALIST_ARCH_NAME}.tar.gz
ALIST_DIR=$serverPath/source/alist
if [ ! -f $ALIST_DIR/${FILE_TGZ} ];then
wget -O $ALIST_DIR/${FILE_TGZ} https://github.com/alist-org/alist/releases/download/v${VERSION}/${FILE_TGZ}
fi
mkdir -p $serverPath/alist
cd $ALIST_DIR && tar -zxvf ${FILE_TGZ} -C $serverPath/alist
echo "${VERSION}" > $serverPath/alist/version.pl
cd ${rootPath} && python3 ${rootPath}/plugins/alist/index.py start
cd ${rootPath} && python3 ${rootPath}/plugins/alist/index.py initd_install
cd $serverPath/alist && ./alist admin set admin
# cd /www/server/alist && ./alist admin set admin
echo '安装完成'
}
Uninstall_App()
{
if [ -f /usr/lib/systemd/system/alist.service ];then
systemctl stop alist
systemctl disable alist
rm -rf /usr/lib/systemd/system/alist.service
systemctl daemon-reload
fi
if [ -f /lib/systemd/system/alist.service ];then
systemctl stop alist
systemctl disable alist
rm -rf /lib/systemd/system/alist.service
systemctl daemon-reload
fi
if [ -f $serverPath/alist/initd/alist ];then
$serverPath/alist/initd/alist stop
fi
if [ -d $serverPath/alist ];then
rm -rf $serverPath/alist
fi
echo "卸载alist成功"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi

@ -0,0 +1,92 @@
function alistPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'alist';
req_data['func'] = method;
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
if (!data.status){
//错误展示10S
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function alistPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'alist';
req_data['func'] = method;
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function clearTaskCopy(){
layer.confirm('您真的要清空复制任务吗?', { icon: 3, closeBtn: 2 }, function() {
alistPost('clear_copy_task', '', {}, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg, function(){},{ icon: rdata.status ? 1 : 2 });
});
});
}
function commonHomePage(){
alistPost('home_page', '', {}, function(data){
var rdata = $.parseJSON(data.data);
window.open(rdata.data);
});
}
function alistCommonFunc(){
var con = '';
con += '<hr/><p class="conf_p" style="text-align:center;">\
<button class="btn btn-default btn-sm" onclick="commonHomePage()">主页</button>\
<button class="btn btn-default btn-sm" onclick="clearTaskCopy()">清空复制任务</button>\
</p>';
$(".soft-man-con").html(con);
}
function alistReadme(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>默认admin:admin</li>';
readme += '<li>手动改密码: cd /www/server/alist && ./alist admin set NEW_PASSWORD</li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}

@ -113,6 +113,9 @@ def initConf():
"/tmp/yum_save_*",
"/tmp/tmp.*",
"/www/server/dztasks/logs/dztasks.*.log",
"/www/server/dztasks/logs/dztasks_*",
]
for i in clog:
content += i + "\n"
@ -147,6 +150,8 @@ def initConf():
"/www/server/openresty/nginx/logs",
"/www/server/phpmyadmin",
"/www/server/redis/data",
"/www/server/alist/data/log",
"/www/server/dztasks/logs",
"/www/server/cron",
]
for i in clogcom:

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

@ -0,0 +1,31 @@
<style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('cloudreve');">服务</p>
<p onclick="pluginInitD('cloudreve');">自启动</p>
<p onclick="alistCommonFunc();">常用功能</p>
<p onclick="pluginConfigTpl('cloudreve',$('.plugin_version').attr('version'));">配置修改</p>
<p onclick="pluginLogs('cloudreve','','run_log');">运行日志</p>
<p onclick="alistReadme();">相关说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=cloudreve&f=js/cloudreve.js", function(){
pluginService('cloudreve', $('.plugin_version').attr('version'));
});
</script>

@ -0,0 +1,288 @@
# coding:utf-8
import sys
import io
import os
import time
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'cloudreve'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def getConf():
path = getServerDir() + "/conf.ini"
return path
def configTpl():
path = getPluginDir() + '/tpl'
pathFile = os.listdir(path)
tmp = []
for one in pathFile:
file = path + '/' + one
tmp.append(file)
return mw.getJson(tmp)
def readConfigTpl():
args = getArgs()
data = checkArgs(args, ['file'])
if not data[0]:
return data[1]
content = mw.readFile(args['file'])
content = contentReplace(content)
return mw.returnJson(True, 'ok', content)
def status():
data = mw.execShell(
"ps aux|grep cloudreve |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$SERVER_APP}', service_path + '/'+getPluginName())
return content
def initDreplace():
file_tpl = getInitDTpl()
service_path = os.path.dirname(os.getcwd())
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
# initd replace
if not os.path.exists(file_bin):
content = mw.readFile(file_tpl)
content = content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(file_bin, content)
mw.execShell('chmod +x ' + file_bin)
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/' + getPluginName() + '.service'
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(systemService, se_content)
mw.execShell('systemctl daemon-reload')
return file_bin
def alistOp(method):
file = initDreplace()
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
if current_os.startswith("freebsd"):
data = mw.execShell('service ' + getPluginName() + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
if data[1] == '':
return 'ok'
return data[1]
def start():
return alistOp('start')
def stop():
return alistOp('stop')
def restart():
status = alistOp('restart')
return status
def reload():
return alistOp('reload')
def initdStatus():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initdInstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
# freebsd initd install
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
return 'ok'
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
def initdUinstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
return 'ok'
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
def runLog():
return getServerDir() + '/logs.pl'
def pSqliteDb(dbname='databases'):
pos_file = getServerDir() + '/data/'
file = pos_file + '/data.db'
name = 'data'
conn = mw.M(dbname).dbPos(pos_file, name)
return conn
def getCloudrevePort():
file = getConf()
content = mw.readFile(file)
rep = r'Listen\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def homePage():
http_port = getCloudrevePort()
ip = mw.getLocalIp()
if mw.isAppleSystem():
ip = '127.0.0.1'
url = 'http://'+ip+""+str(http_port)
# print(url)
return mw.returnJson(True, 'ok!', url)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'conf':
print(getConf())
elif func == 'run_log':
print(runLog())
elif func == 'config_tpl':
print(configTpl())
elif func == 'read_config_tpl':
print(readConfigTpl())
elif func == 'home_page':
print(homePage())
else:
print('error')

@ -0,0 +1,17 @@
{
"sort": 7,
"ps": "一个支持多种存储的文件列表程序",
"name": "cloudreve",
"title": "cloudreve",
"shell": "install.sh",
"versions":["3.8.3"],
"tip": "soft",
"checks": "server/cloudreve",
"path": "server/cloudreve",
"display": 1,
"author": "cloudreve",
"date": "2024-10-14",
"home": "https://cloudreve.org/",
"type": 0,
"pid": "5"
}

@ -0,0 +1,13 @@
[Unit]
Description=A file list program that supports multiple storage
After=network.target
[Service]
Type=simple
WorkingDirectory={$SERVER_PATH}/cloudreve
ExecStart={$SERVER_PATH}/cloudreve/cloudreve
ExecReload=/bin/kill -USR2 $MAINPID
Restart=on-failure
[Install]
WantedBy=multi-user.target

@ -0,0 +1,46 @@
#!/bin/sh
# chkconfig: 2345 55 25
# description: cloudreve Service
### BEGIN INIT INFO
# Provides: cloudreve
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts cloudreve
# Description: starts the MDW-Web
### END INIT INFO
# Simple cloudreve init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
app_start(){
echo "Starting cloudreve server..."
cd {$SERVER_PATH}/cloudreve
./cloudreve >> {$SERVER_PATH}/cloudreve/logs.pl 2>&1 &
}
app_stop(){
echo "dztasks stopped"
ps -ef| grep cloudreve | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'| xargs kill
}
case "$1" in
start)
app_start
;;
stop)
app_stop
;;
restart|reload)
app_stop
sleep 0.3
app_start
;;
*)
echo "Please use start or stop as first argument"
;;
esac

@ -0,0 +1,91 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/cloudreve && bash install.sh install 3.8.3
# cd /www/server/mdserver-web/plugins/cloudreve && bash install.sh install 3.8.3
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
sysArch=`arch`
sysName=`uname`
ALIST_ARCH_NAME=amd64
if [ "$sysArch" == "arm64" ];then
ALIST_ARCH_NAME=arm64
elif [ "$sysArch" == "x86_64" ]; then
ALIST_ARCH_NAME=amd64
elif [ "$sysArch" == "aarch64" ]; then
ALIST_ARCH_NAME=aarch64
fi
ALIST_NAME=linux
if [ "$sysName" == "Darwin" ];then
ALIST_NAME=darwin
fi
Install_App()
{
echo '正在安装脚本文件...'
mkdir -p $serverPath/source
mkdir -p $serverPath/source/cloudreve
FILE_TGZ=cloudreve_${VERSION}_${ALIST_NAME}_${ALIST_ARCH_NAME}.tar.gz
CLOUDREVE_DIR=$serverPath/source/cloudreve
if [ ! -f $CLOUDREVE_DIR/${FILE_TGZ} ];then
wget -O $CLOUDREVE_DIR/${FILE_TGZ} https://github.com/cloudreve/Cloudreve/releases/download/${VERSION}/${FILE_TGZ}
fi
mkdir -p $serverPath/cloudreve
cd $CLOUDREVE_DIR && tar -zxvf ${FILE_TGZ} -C $serverPath/cloudreve
echo "${VERSION}" > $serverPath/cloudreve/version.pl
cd ${rootPath} && python3 ${rootPath}/plugins/cloudreve/index.py start
cd ${rootPath} && python3 ${rootPath}/plugins/cloudreve/index.py initd_install
# cd $serverPath/cloudreve && ./alist admin set admin
echo '安装cloudreve完成'
}
Uninstall_App()
{
if [ -f /usr/lib/systemd/system/cloudreve.service ];then
systemctl stop cloudreve
systemctl disable cloudreve
rm -rf /usr/lib/systemd/system/cloudreve.service
systemctl daemon-reload
fi
if [ -f /lib/systemd/system/cloudreve.service ];then
systemctl stop cloudreve
systemctl disable cloudreve
rm -rf /lib/systemd/system/cloudreve.service
systemctl daemon-reload
fi
if [ -f $serverPath/cloudreve/initd/cloudreve ];then
$serverPath/cloudreve/initd/cloudreve stop
fi
if [ -d $serverPath/cloudreve ];then
rm -rf $serverPath/cloudreve
fi
echo "卸载cloudreve成功"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi

@ -0,0 +1,82 @@
function alistPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'cloudreve';
req_data['func'] = method;
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
if (!data.status){
//错误展示10S
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function alistPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'cloudreve';
req_data['func'] = method;
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function commonHomePage(){
alistPost('home_page', '', {}, function(data){
var rdata = $.parseJSON(data.data);
window.open(rdata.data);
});
}
function alistCommonFunc(){
var con = '';
con += '<hr/><p class="conf_p" style="text-align:center;">\
<button class="btn btn-default btn-sm" onclick="commonHomePage()">主页</button>\
</p>';
$(".soft-man-con").html(con);
}
function alistReadme(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>记住安装时生成的用户+密码</li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}

@ -11,8 +11,12 @@ import re
import json
import pymemcache
sys.path.append(os.getcwd() + "/class/core")
import mw
try:
sys.path.append(os.getcwd() + "/class/core")
import mw
except Exception as e:
import core.mw as mw
def singleton(cls):
_instance = {}

@ -12,8 +12,11 @@ import yaml
from bson.objectid import ObjectId
from bson.json_util import dumps
sys.path.append(os.getcwd() + "/class/core")
import mw
try:
sys.path.append(os.getcwd() + "/class/core")
import mw
except Exception as e:
import core.mw as mw
def singleton(cls):
_instance = {}

@ -7,8 +7,13 @@ import time
import re
import redis
sys.path.append(os.getcwd() + "/class/core")
import mw
try:
sys.path.append(os.getcwd() + "/class/core")
import mw
except Exception as e:
import core.mw as mw
# def getPluginName():
# return 'data_query'

@ -8,9 +8,11 @@ import re
import pymongo
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
try:
sys.path.append(os.getcwd() + "/class/core")
import mw
except Exception as e:
import core.mw as mw
def singleton(cls):
_instance = {}

@ -13,7 +13,7 @@
<div class="bgw mtb15 pd15 tab-view-box firewall-tab-view safe" style="overflow: hidden;">
<div class="mask_layer" style="display:none;">
<div class="prompt_description">当前未安装本地服务器,<a class="btlink install_server" href="/soft">点击安装</a></div>
<div class="prompt_description">当前未安装本地服务器,<a class="btlink install_server" href="/soft/index">点击安装</a></div>
</div>
<!-- mysql start -->

@ -10,7 +10,11 @@ import json
sys.path.append(os.getcwd() + "/class/core")
import mw
import docker
try:
import docker
except Exception as e:
pass
app_debug = False

@ -14,7 +14,7 @@
<p class="bgw" onclick="pluginService('fail2ban');">服务</p>
<p onclick="pluginInitD('fail2ban');">自启动</p>
<p onclick="pluginConfigTpl('fail2ban',$('.plugin_version').attr('version'));">配置修改</p>
<!-- <p onclick="getRedisConfig($('.plugin_version').attr('version'));">性能调整</p> -->
<p onclick="f2bBanIp();">IP黑名单</p>
<!-- <p onclick="redisStatus($('.plugin_version').attr('version'));">负载状态</p> -->
<p onclick="pluginLogs('fail2ban','','run_log');">运行日志</p>
</div>
@ -24,6 +24,8 @@
</div>
</div>
<script type="text/javascript">
resetPluginWinWidth(1000);
// resetPluginWinHeight(500);
$.getScript( "/plugins/file?name=fail2ban&f=js/fail2ban.js", function(){
pluginService('fail2ban', $('.plugin_version').attr('version'));
});

@ -5,6 +5,7 @@ import io
import os
import time
import re
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
@ -18,10 +19,10 @@ def getPluginName():
return 'fail2ban'
def f2bDir():
return '/run/fail2ban'
return '/run/'+getPluginName()
def f2bEtcDir():
return '/etc/fail2ban'
return '/etc/'+getPluginName()
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
@ -48,7 +49,7 @@ def getConf():
def getConfTpl():
path = getPluginDir() + "/config/redis.conf"
path = getPluginDir() + "/tpl/fail2ban.conf"
return path
@ -89,7 +90,7 @@ def configTpl():
for one in pathFile:
if one.endswith("conf"):
file = path + '/' + one
tmp.append(file)
tmp.append(file)
return mw.getJson(tmp)
@ -123,6 +124,21 @@ def contentReplace(content):
return content
def initFail2BanD():
dst_conf = f2bEtcDir() + '/fail2ban.d/default.conf'
dst_conf_tpl = getPluginDir() + '/tpl/fail2ban.d/default.conf'
if not os.path.exists(dst_conf):
content = mw.readFile(dst_conf_tpl)
content = contentReplace(content)
mw.writeFile(dst_conf, content)
def initJailD():
dst_conf = f2bEtcDir() + '/jail.d/default.conf'
dst_conf_tpl = getPluginDir() + '/tpl/jail.d/default.conf'
if not os.path.exists(dst_conf):
content = mw.readFile(dst_conf_tpl)
content = contentReplace(content)
mw.writeFile(dst_conf, content)
def initDreplace():
@ -134,12 +150,17 @@ def initDreplace():
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
# initd replace
# if not os.path.exists(file_bin):
# content = mw.readFile(file_tpl)
# content = content.replace('{$SERVER_PATH}', service_path)
# mw.writeFile(file_bin, content)
# mw.execShell('chmod +x ' + file_bin)
# config replace
# dst_conf = getConf()
# dst_conf_init = getServerDir() + '/init.pl'
# if not os.path.exists(dst_conf_init):
# content = mw.readFile(getConfTpl())
# content = contentReplace(content)
# mw.writeFile(dst_conf, content)
# mw.writeFile(dst_conf_init, 'ok')
initFail2BanD()
initJailD()
# systemd
systemDir = mw.systemdCfgDir()
@ -147,9 +168,9 @@ def initDreplace():
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(systemService, se_content)
content = mw.readFile(systemServiceTpl)
content = content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(systemService, content)
mw.execShell('systemctl daemon-reload')
return file_bin
@ -249,8 +270,83 @@ def initdUinstall():
return 'ok'
# 读取配置
def _read_conf(path, l=None):
conf = mw.readFile(path)
if not conf:
if not l:
conf = {}
else:
conf = []
mw.writeFile(path, json.dumps(conf))
return conf
return json.loads(conf)
def getBlackFile():
return getServerDir() + "/black_list.json"
def getConfigFile():
return getServerDir() + "/config.json"
def getBlackListArr():
_black_list = getBlackFile()
conf = _read_conf(_black_list, l=1)
if not conf:
conf = []
return conf
def getBlackList():
conf = getBlackListArr()
content = "\n".join(conf)
return mw.returnJson(True, 'ok', content)
def setBlackIp():
ip_list = getBlackListArr()
args = getArgs()
data = checkArgs(args, ['black_ip'])
if not data[0]:
return data[1]
new_ip_list = args['black_ip']
add_ip_list = [new_ip for new_ip in new_ip_list if new_ip not in ip_list]
del_ip_list = [del_ip for del_ip in ip_list if del_ip not in new_ip_list]
rep_ip = "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}($|[\\/\\d]+$)"
rep_ipv6 = "^\\s*((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}(:|((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\\d|[01]?\\d{1,2})(\\.(25[0-5]|2[0-4]\\d|[01]?\\d{1,2})){3})))(%.+)?\\s*$"
data = _read_conf(getConfigFile())
if new_ip_list == '':
for d in data:
for ip in ip_list:
mw.execShell('fail2ban-client -vvv set {jail} unbanip {ip}'.format(jail=d, ip=ip))
mw.writeFile(getBlackFile(), json.dumps([]))
return nw.returnJson(True, "禁止IP成功")
# 检查IP格式
for ip in add_ip_list:
if not re.search(rep_ip, ip) and not re.search(rep_ipv6, ip):
return mw.returnJson(False, "IP格式错误 {}".format(ip))
# 添加新域名到黑名单
for d in data:
for ip in add_ip_list:
mw.execShell('fail2ban-client -vvv set {jail} banip {ip}'.format(jail=d, ip=ip))
# 检查是否有清理掉的IP
for d in data:
for ip in del_ip_list:
mw.execShell('fail2ban-client -vvv set {jail} unbanip {ip}'.format(jail=d, ip=ip))
for ip in add_ip_list:
ip_list.append(ip)
mw.writeFile(getBlackFile(), json.dumps(ip_list))
return mw.returnJson(True, "添加黑名单成功")
if __name__ == "__main__":
func = sys.argv[1]
@ -280,5 +376,9 @@ if __name__ == "__main__":
print(configTpl())
elif func == 'read_config_tpl':
print(readConfigTpl())
elif func == 'get_black_list':
print(getBlackList())
elif func == 'set_black_ip':
print(setBlackIp())
else:
print('error')

@ -11,7 +11,7 @@
"path": "server/fail2ban",
"display": 1,
"author": "fail2ban",
"date": "2025-07-28",
"date": "2024-07-28",
"home": "https://www.fail2ban.org",
"type": 0,
"pid": "4"

@ -12,6 +12,7 @@ install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
# cd /www/server/mdserver-web/plugins/fail2ban && bash install.sh install 1.1.0
# cd /www/server/mdserver-web && python3 plugins/fail2ban/index.py config_tpl
Install_App()
{
@ -31,7 +32,7 @@ Install_App()
Uninstall_App()
{
apt remove -y fail2ban
apt purge -y fail2ban
if [ -f /usr/lib/systemd/system/fail2ban.service ];then
systemctl stop fail2ban
@ -54,6 +55,10 @@ Uninstall_App()
if [ -d $serverPath/fail2ban ];then
rm -rf $serverPath/fail2ban
fi
if [ -d /etc/fail2ban ];then
rm -rf /etc/fail2ban
fi
echo "卸载fail2ban成功"
}

@ -1,3 +1,7 @@
function getVersion(){
return $('.plugin_version').attr('version');
}
function f2bPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
@ -26,7 +30,7 @@ function f2bPost(method, version, args,callback){
},'json');
}
function f2bPostCallbak(method, version, args,callback){
function f2bPostCallbak(method, version, args, callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
@ -52,3 +56,55 @@ function f2bPostCallbak(method, version, args,callback){
}
},'json');
}
function f2bBanIpSave(black_ip){
var ver = getVersion();
f2bPost('set_black_ip', ver, {'black_ip':black_ip}, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
function f2bBanIp(){
var con = '<p style="color: #666; margin-bottom: 7px">提示Ctrl+F 搜索关键字Ctrl+G 查找下一个Ctrl+S 保存Ctrl+Shift+R 查找替换!</p>\
<textarea class="bt-input-text" style="height: 320px; line-height:18px;" id="textBody"></textarea>\
<button id="onlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">保存</button>\
<ul class="help-info-text c7 ptb15">\
<li>如有多个请以换行隔开例<br/>\
192.168.1.1<br/>\
192.168.1.0/24\
</li>\
</ul>';
$(".soft-man-con").html(con);
$("#textBody").empty();
var editor = CodeMirror.fromTextArea(document.getElementById("textBody"), {
extraKeys: {
"Ctrl-Space": "autocomplete",
"Ctrl-F": "findPersistent",
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
$("#textBody").text(editor.getValue());
f2bPost('set_black_list', '', {'black_ip':editor.getValue()}, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
f2bBanIpSave(editor.getValue());
}
},
lineNumbers: true,
matchBrackets:true,
});
editor.focus();
f2bPost('get_black_list', '', {}, function(data){
var rdata = $.parseJSON(data.data);
$("#textBody").text(rdata.data);
});
$("#onlineEditFileBtn").click(function(){
f2bBanIpSave(editor.getValue());
});
}

@ -0,0 +1,25 @@
[DEFAULT]
allowipv6 = auto
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mw = %(action_)s
%(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mwl = %(action_)s
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
action_xarf = %(action_)s
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
%(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
action_abuseipdb = abuseipdb
action = %(action_)s

@ -0,0 +1,2 @@
[DEFAULT]
backend = systemd

@ -0,0 +1,11 @@
#sshd-START
[sshd]
enabled = true
filter = sshd
port = 2022,no
maxretry = 5
findtime = 300
bantime = 86400
action = %(action_mwl)s
logpath = /var/log/auth.log
#sshd-END

@ -220,7 +220,7 @@ def getDbConfValue():
rep_scope = r"\[database\](.*?)\["
tmp = re.findall(rep_scope, content, re.S)
rep = '(\w*)\s*=\s*(.*)'
rep = '(\\w*)\\s*=\\s*(.*)'
tmp = re.findall(rep, tmp[0])
r = {}
for x in range(len(tmp)):
@ -418,7 +418,7 @@ def getGogsConf():
result = []
for g in gets:
rep = g['name'] + '\s*=\s*(.*)'
rep = g['name'] + '\\s*=\\s*(.*)'
tmp = re.search(rep, conf)
if not tmp:
continue
@ -447,7 +447,7 @@ def submitGogsConf():
conf = mw.readFile(filename)
for g in gets:
if g in args:
rep = g + '\s*=\s*(.*)'
rep = g + '\\s*=\\s*(.*)'
val = g + ' = ' + args[g]
conf = re.sub(rep, val, conf)
mw.writeFile(filename, conf)

@ -173,12 +173,12 @@ def initDreplace():
def getRootUrl():
content = mw.readFile(getConf())
rep = r'ROOT_URL\s*=\s*(.*)'
rep = r'ROOT_URL\\s*=\\s*(.*)'
tmp = re.search(rep, content)
if tmp:
return tmp.groups()[0]
rep = r'EXTERNAL_URL\s*=\s*(.*)'
rep = r'EXTERNAL_URL\\s*=\s*(.*)'
tmp = re.search(rep, content)
if tmp:
return tmp.groups()[0]
@ -187,7 +187,7 @@ def getRootUrl():
def getSshPort():
content = mw.readFile(getConf())
rep = r'SSH_PORT\s*=\s*(.*)'
rep = r'SSH_PORT\\s*=\\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
@ -196,7 +196,7 @@ def getSshPort():
def getHttpPort():
content = mw.readFile(getConf())
rep = r'HTTP_PORT\s*=\s*(.*)'
rep = r'HTTP_PORT\\s*=\\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
@ -205,7 +205,7 @@ def getHttpPort():
def getRootPath():
content = mw.readFile(getConf())
rep = r'ROOT\s*=\s*(.*)'
rep = r'ROOT\\s*=\\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
@ -218,10 +218,10 @@ def getDbConfValue():
return {}
content = mw.readFile(conf)
rep_scope = r"\[database\](.*?)\["
rep_scope = r"\\[database\\](.*?)\\["
tmp = re.findall(rep_scope, content, re.S)
rep = r'(\w*)\s*=\s*(.*)'
rep = r'(\\w*)\\s*=\\s*(.*)'
tmp = re.findall(rep, tmp[0])
r = {}
for x in range(len(tmp)):
@ -419,7 +419,7 @@ def getGogsConf():
result = []
for g in gets:
rep = g['name'] + '\s*=\s*(.*)'
rep = g['name'] + '\\s*=\\s*(.*)'
tmp = re.search(rep, conf)
if not tmp:
continue
@ -448,7 +448,7 @@ def submitGogsConf():
conf = mw.readFile(filename)
for g in gets:
if g in args:
rep = g + '\s*=\s*(.*)'
rep = g + '\\s*=\\s*(.*)'
val = g + ' = ' + args[g]
conf = re.sub(rep, val, conf)
mw.writeFile(filename, conf)

@ -238,7 +238,7 @@ def getPort():
conf = getServerDir() + '/gorse.conf'
content = mw.readFile(conf)
rep = "^(" + 'port' + ')\s*([.0-9A-Za-z_& ~]+)'
rep = "^(" + 'port' + ')\\s*([.0-9A-Za-z_& ~]+)'
tmp = re.search(rep, content, re.M)
if tmp:
return tmp.groups()[1]

@ -209,10 +209,10 @@ def runInfo():
conf = mw.readFile(getServerDir() + '/memcached.env')
result['bind'] = re.search('IP=(.+)', conf).groups()[0]
result['port'] = int(re.search('PORT=(\d+)', conf).groups()[0])
result['maxconn'] = int(re.search('MAXCONN=(\d+)', conf).groups()[0])
result['port'] = int(re.search('PORT=(\\d+)', conf).groups()[0])
result['maxconn'] = int(re.search('MAXCONN=(\\d+)', conf).groups()[0])
result['cachesize'] = int(
re.search('CACHESIZE=(\d+)', conf).groups()[0])
re.search('CACHESIZE=(\\d+)', conf).groups()[0])
return mw.getJson(result)
except Exception as e:
return mw.getJson({})

@ -172,7 +172,7 @@ class backupTools:
if auth != 'disabled':
uoption =' --authenticationDatabase admin -u root -p '+mg_root
cmd = db_path + "/bin/mongodump "+uoption+" --port "+str(port)+" -d test -o "+backup_path
cmd = db_path + "/bin/mongodump "+uoption+" --port "+str(port)+" -d "+name+" -o "+backup_path
# print(cmd)
mw.execShell(cmd)
cmd_gz = "cd "+backup_path+"/"+name+" && tar -zcvf "+filename + " ./"

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=5.0.20
VERSION=5.0.29
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=5.0.20
VERSION=5.0.29
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
SYS_NAME=${SYS_VERSION_ID/./}

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=5.0.20
VERSION=5.0.29
MG_DIR=$serverPath/source/mongodb
mkdir -p $MG_DIR

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=5.0.20
VERSION=5.0.29
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}' | awk -F . '{print $1}'`

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=5.0.20
VERSION=5.0.29
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=6.0.9
VERSION=6.0.18
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
SYS_NAME=${SYS_VERSION_ID/./}

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=6.0.9
VERSION=6.0.18
MG_DIR=$serverPath/source/mongodb
mkdir -p $MG_DIR

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=6.0.9
VERSION=6.0.18
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}' | awk -F . '{print $1}'`

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=6.0.9
VERSION=6.0.18
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=7.0.9
VERSION=7.0.14
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`

@ -9,11 +9,12 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=7.0.9
VERSION=7.0.14
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
SYS_NAME=${SYS_VERSION_ID/./}
if [ "$SYS_NAME" -gt "11" ];then
SYS_NAME="11"
fi
@ -22,6 +23,10 @@ if [ "$SYS_NAME" -lt "11" ];then
SYS_NAME="11"
fi
if [ "$SYS_NAME" == "" ];then
SYS_NAME="11"
fi
FILE_NAME=mongodb-linux-${SYS_ARCH}-debian${SYS_NAME}-${VERSION}
FILE_NAME_TGZ=${FILE_NAME}.tgz

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=7.0.9
VERSION=7.0.14
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`

@ -10,7 +10,7 @@ serverPath=$(dirname "$rootPath")
SYS_ARCH=`arch`
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=7.0.9
VERSION=7.0.14
MG_DIR=$serverPath/source/mongodb
mkdir -p $MG_DIR

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=7.0.9
VERSION=7.0.14
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}' | awk -F . '{print $1}'`

@ -9,7 +9,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=7.0.9
VERSION=7.0.14
SYS_ARCH=`arch`
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`

@ -10,6 +10,8 @@ serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
# cd /www/server/mdserver-web/plugins/msonedrive && bash install.sh install 1.0
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi

@ -1,4 +1,4 @@
# coding:utf-8
# coding=utf-8
import sys
import io

@ -1,4 +1,5 @@
# coding:utf-8
#!/usr/bin/env python
# coding=utf-8
import sys
import io
@ -2241,7 +2242,7 @@ def getMasterStatus(version=''):
return mw.returnJson(master_status, '设置成功', data)
except Exception as e:
return mw.returnJson(False, "数据库密码错误,在管理列表-点击【修复】,"+str(e), 'pwd')
return mw.returnJson(False, "数据库密码错误,在管理列表-点击【修复】,"+str(mw.getTracebackInfo()), 'pwd')
def setMasterStatus(version=''):

@ -259,6 +259,8 @@ function myPerfOpt() {
<option value="3">4-8GB</option>\
<option value="4">8-16GB</option>\
<option value="5">16-32GB</option>\
<option value="6">32-64GB</option>\
<option value="7">64-128GB</option>\
</select>\
<span>' + lan.soft.mysql_set_maxmem + ': </span><input style="width:70px;background-color:#eee;" class="bt-input-text mr5" name="memSize" type="text" value="' + memSize.toFixed(2) + '" readonly>MB\
</div>\
@ -439,6 +441,36 @@ function mySQLMemOpt(opt) {
$("input[name='table_open_cache']").val(2048);
$("input[name='max_connections']").val(500);
break;
case '6':
$("input[name='key_buffer_size']").val(2048);
if (query_size) $("input[name='query_cache_size']").val(384);
$("input[name='tmp_table_size']").val(4096);
$("input[name='innodb_buffer_pool_size']").val(8192);
$("input[name='sort_buffer_size']").val(8192);
$("input[name='read_buffer_size']").val(8192);
$("input[name='read_rnd_buffer_size']").val(4096);
$("input[name='join_buffer_size']").val(16384);
$("input[name='thread_stack']").val(1024);
$("input[name='binlog_cache_size']").val(512);
$("input[name='thread_cache_size']").val(512);
$("input[name='table_open_cache']").val(4096);
$("input[name='max_connections']").val(1000);
break;
case '7':
$("input[name='key_buffer_size']").val(4096);
if (query_size) $("input[name='query_cache_size']").val(384);
$("input[name='tmp_table_size']").val(8192);
$("input[name='innodb_buffer_pool_size']").val(16384);
$("input[name='sort_buffer_size']").val(16384);
$("input[name='read_buffer_size']").val(16384);
$("input[name='read_rnd_buffer_size']").val(8192);
$("input[name='join_buffer_size']").val(16384);
$("input[name='thread_stack']").val(2048);
$("input[name='binlog_cache_size']").val(1024);
$("input[name='thread_cache_size']").val(1024);
$("input[name='table_open_cache']").val(8192);
$("input[name='max_connections']").val(2000);
break;
}
}

@ -8,7 +8,8 @@ Description=pgadmin service
After=network.target
[Service]
ExecStart=gunicorn --bind unix:/tmp/pgadmin4.sock --workers=1 --threads=25 --chdir {$SERVER_PATH}/pgadmin/run/lib/{$PY_VER}/site-packages/pgadmin4 pgAdmin4:app
ExecStart={$SERVER_PATH}/pgadmin/run/bin/gunicorn --bind unix:/tmp/pgadmin4.sock --workers=1 --threads=25 --chdir {$SERVER_PATH}/pgadmin/run/lib/{$PY_VER}/site-packages/pgadmin4 pgAdmin4:app
ExecReload=/bin/kill -USR2 $MAINPID
PrivateTmp=false

@ -79,10 +79,10 @@ Install_pgadmin()
fi
fi
if [ -f ${PG_DIR}/bin/activate ];then
source ${PG_DIR}/bin/activate
fi
pip install gunicorn
# pip install https://ftp.postgresql.org/pub/pgadmin/pgadmin4/v8.10/pip/pgadmin4-8.10-py3-none-any.whl
pip install https://ftp.postgresql.org/pub/pgadmin/pgadmin4/v8.12/pip/pgadmin4-8.12-py3-none-any.whl

@ -5,8 +5,8 @@
"name": "php",
"title": "PHP",
"coexist": true,
"versions": ["53","54","55","56","70","71","72","73","74","80","81","82","83"],
"updates": ["5.3.29","5.4.45","5.6.36","7.0.30","7.1.33","7.2.32","7.3.20","7.4.30","8.0.30","8.1.24","8.2.11","8.3.0"],
"versions": ["53","54","55","56","70","71","72","73","74","80","81","82","83","84"],
"updates": ["5.3.29","5.4.45","5.6.36","7.0.30","7.1.33","7.2.32","7.3.20","7.4.30","8.0.30","8.1.29","8.2.24","8.3.12","8.4.0"],
"tip": "soft",
"install_pre_inspection":true,
"checks": "server/php/VERSION/bin/php",

@ -16,7 +16,7 @@ function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)"
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.1.29
version=8.1.30
PHP_VER=81
Install_php()
{
@ -56,7 +56,7 @@ if [ ! -d $sourcePath/php/php${PHP_VER} ];then
fi
#检测文件是否损坏.
md5_file_ok=288884af60581d4284baba2ace9ca6d646f72facbd3e3c2dd2acc7fe6f903536
md5_file_ok=f24a6007f0b25a53cb7fbaee69c85017e0345b62089c2425a0afb7e177192ed1
if [ -f $sourcePath/php/php-${version}.tar.xz ];then
md5_file=`sha256sum $sourcePath/php/php-${version}.tar.xz | awk '{print $1}'`
if [ "${md5_file}" != "${md5_file_ok}" ]; then

@ -15,7 +15,7 @@ function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)"
function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; }
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.4
version=8.4.0RC2
PHP_VER=84
Install_php()
{
@ -37,18 +37,19 @@ if [ ! -d $sourcePath/php/php${PHP_VER} ];then
if [ ! -f $sourcePath/php/php-${version}.tar.xz ];then
wget --no-check-certificate -O $sourcePath/php/php-${version}.tar.xz https://www.php.net/distributions/php-${version}.tar.xz
# wget --no-check-certificate -O $sourcePath/php/php-${version}.tar.xz https://www.php.net/distributions/php-${version}.tar.xz
wget --no-check-certificate -O $sourcePath/php/php-${version}.tar.xz https://downloads.php.net/~calvinb/php-${version}.tar.xz
fi
#检测文件是否损坏.
md5_file_ok=xxx
if [ -f $sourcePath/php/php-${version}.tar.xz ];then
md5_file=`sha256sum $sourcePath/php/php-${version}.tar.xz | awk '{print $1}'`
if [ "${md5_file}" != "${md5_file_ok}" ]; then
echo "PHP${version} 下载文件不完整,重新安装"
rm -rf $sourcePath/php/php-${version}.tar.xz
fi
fi
# md5_file_ok=xxx
# if [ -f $sourcePath/php/php-${version}.tar.xz ];then
# md5_file=`sha256sum $sourcePath/php/php-${version}.tar.xz | awk '{print $1}'`
# if [ "${md5_file}" != "${md5_file_ok}" ]; then
# echo "PHP${version} 下载文件不完整,重新安装"
# rm -rf $sourcePath/php/php-${version}.tar.xz
# fi
# fi
cd $sourcePath/php && tar -Jxf $sourcePath/php/php-${version}.tar.xz
mv $sourcePath/php/php-${version} $sourcePath/php/php${PHP_VER}

@ -21,6 +21,11 @@ if [ "$version" -lt "72" ];then
exit 1
fi
if [ "$version" == "84" ];then
LIBV=1.0.7
fi
LIB_PATH_NAME=lib/php
if [ -d $serverPath/php/${version}/lib64 ];then
LIB_PATH_NAME=lib64

@ -12,7 +12,7 @@ serverPath=$(dirname "$rootPath")
sourcePath=${serverPath}/source/php
SYS_ARCH=`arch`
LIBNAME=redis
LIBV=5.3.7
LIBV=6.1.0
sysName=`uname`
actionType=$1
version=$2
@ -21,8 +21,10 @@ if [ "$version" == "52" ];then
LIBV=2.2.7
elif [ "$version" -lt "70" ];then
LIBV=4.2.0
elif [ "$version" -gt "74" ];then
elif [ "$version" -lt "80" ];then
LIBV=5.3.7
elif [ "$version" -gt "80" ];then
LIBV=6.1.0
else
echo 'ok'
fi

@ -58,7 +58,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "脚本解密",
"msg": "用于解密ionCube Encoder加密脚本!",
@ -76,7 +77,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "加密库",
"msg": "Sodium加密库的包装器",
@ -94,7 +96,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "运算库",
"msg": "一个开源的数学运算库",
@ -116,7 +119,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "缓存器",
"msg": "用于加速PHP脚本!",
@ -138,7 +142,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "SSL!",
@ -155,7 +160,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "加密软件!",
@ -177,7 +183,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "高精度计算!",
@ -200,7 +207,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "缓存器",
"msg": "用于信号控制!",
@ -223,7 +231,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "编码转换!",
@ -244,7 +253,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "用于FILE!",
@ -264,7 +274,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "提供到libevent库的接口",
@ -285,7 +296,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "用于图像文件格式!",
@ -303,7 +315,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "序列化扩展!",
@ -326,7 +339,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "国际化与本地化!",
@ -349,7 +363,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "通用GD库!",
@ -372,7 +387,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "提供国际化支持",
@ -417,7 +433,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "缓存器",
"msg": "强大的内容缓存器,支持集群",
@ -440,7 +457,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "缓存器",
"msg": "更强大的内容缓存器,支持集群",
@ -488,7 +506,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "比GD更强大的图形库",
@ -510,7 +529,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "调试器",
"msg": "不多说,不了解的不要安装",
@ -533,7 +553,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "性能分析",
"msg": "不多说,不了解的不要安装!",
@ -555,7 +576,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "异步、并行、高性能网络通信引擎",
@ -601,7 +623,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "框架",
"msg": "Yaf是一个C语言编写的PHP框架",
@ -618,7 +641,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "YAML-1.1解析器和发射器",
@ -651,7 +675,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "通用扩展",
"msg": "Mongodb数据库连接驱动",
@ -669,7 +694,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "缓存器",
"msg": "高性能无锁共享内存Cache",
@ -691,7 +717,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "大数据",
"msg": "SOLR全文搜索服务",
@ -713,7 +740,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "日志",
"msg": "SeasLog高性能日志记录",
@ -738,7 +766,8 @@
"80",
"81",
"82",
"83"
"83",
"84"
],
"type": "压缩",
"msg": "压缩组件",

@ -120,7 +120,7 @@ def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$SERVER_APP}', service_path + '/redis')
content = content.replace('{$SERVER_APP}', service_path + '/'+getPluginName())
content = content.replace('{$REDIS_PASS}', mw.getRandomString(10))
return content

@ -331,7 +331,7 @@ def getRecListData():
path = appConf()
content = mw.readFile(path)
flist = re.findall("\[(.*)\]", content)
flist = re.findall("\\[(.*)\\]", content)
flist_len = len(flist)
ret_list = []
@ -341,15 +341,15 @@ def getRecListData():
n = i + 1
reg = ''
if n == flist_len:
reg = '\[' + flist[i] + '\](.*)\[?'
reg = '\\[' + flist[i] + '\\](.*)\\[?'
else:
reg = '\[' + flist[i] + '\](.*)\[' + flist[n] + '\]'
reg = '\\[' + flist[i] + '\\](.*)\\[' + flist[n] + '\\]'
t1 = re.search(reg, content, re.S)
if t1:
args = t1.groups()[0]
# print('args start', args, 'args_end')
t2 = re.findall('\s*(.*)\s*\=\s*?(.*)?', args, re.M | re.I)
t2 = re.findall('\\s*(.*)\\s*\\=\\s*?(.*)?', args, re.M | re.I)
for i in range(len(t2)):
tmp[t2[i][0].strip()] = t2[i][1].strip()
ret_list.append(tmp)
@ -456,9 +456,9 @@ def delRecBy(name):
next_name = reclist[x + 1]['name']
reg = ''
if is_end:
reg = '\[' + name + '\]\s*(.*)'
reg = '\\[' + name + '\\]\\s*(.*)'
else:
reg = '\[' + name + '\]\s*(.*)\s*\[' + next_name + '\]'
reg = '\\[' + name + '\\]\\s*(.*)\\s*\\[' + next_name + '\\]'
conre = re.search(reg, content, re.S)
content = content.replace(

@ -268,7 +268,7 @@ def runLog():
def ipList():
config = getServerDir() + '/conf/app.conf'
content = mw.readFile(config)
rep = 'ip\s*=\s*(.*)'
rep = r'ip\s*=\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''

@ -26,6 +26,7 @@ def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def pingData(args = ()):
# print(args)
conn = mw.M('sp_ping').dbPos(getServerDir()+'/data', 'simpleping', 'db3')
field = 'id,speed,created_unix'
conn = conn.field(field)
@ -36,16 +37,21 @@ def pingData(args = ()):
ip = 'all'
else:
ip = args['ip']
if ip != 'all':
conn = conn.where('ip=?',(ip,))
if atype == 'pos':
pos = args['pos']
data = conn.where('created_unix>?',(pos,)).limit("3000").select()
if 'pos' in args:
pos = args['pos']
conn.where('created_unix>?',(pos,)).limit("3000")
if ip != 'all':
conn.andWhere('ip=?',(ip,))
elif atype == 'range':
start = args['start']
end = args['end']
data = conn.where('created_unix>=? and created_unix<=?',(start,end)).limit("1000").select()
conn.where('created_unix>=? and created_unix<=?',(start,end,)).limit("1000")
if ip != 'all':
conn.andWhere('ip=?',(ip,))
data = conn.select()
return data

@ -11,8 +11,12 @@ import json
from typing import List, Dict
sys.path.append(os.getcwd() + "/class/core")
import mw
try:
sys.path.append(os.getcwd() + "/class/core")
import mw
except Exception as e:
import core.mw as mw
app_debug = False
if mw.isAppleSystem():

@ -52,7 +52,7 @@ def send_msg(bot, tag='ad', trigger_time=300):
# https://t.me/gjgzs2022 | 22/m | @GJ_gzs
# https://zhaoziyuan1.cc | web | 15/m | 2m | next,12/15 | @baleite
# 综合包网/NG接口开户 | 28/m | 6m | next,10/28 | @aabbcx888
# 综合包网/NG接口开户 | 28/m | 6m | next,4/28 | x
# 实名认证/过人脸🕵各种账号处理✅ | 30/m| next,12/30 | @nngzs
# 桃花资源采集| 13/m| next,1/13 | @xiaolizi1122
keyboard = [

@ -7,8 +7,12 @@ import time
import json
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
try:
sys.path.append(os.getcwd() + "/class/core")
import mw
except Exception as e:
import core.mw as mw
app_debug = False

@ -14,7 +14,11 @@ gevent>=22.10.2
gevent-websocket==0.10.1
psutil==5.9.1
chardet==3.0.4
flask-sqlalchemy==2.3.2
SQLAlchemy==2.*
Flask-SQLAlchemy==3.1.*
Flask-Migrate==4.*
#Flask-Security-Too==5.5.*; python_version >= '3.10'
#Flask-Security-Too==5.4.*; python_version <= '3.9'
pyOpenSSL==23.2.0
cryptography>=40.0.2
configparser==5.2.0

@ -6,7 +6,7 @@ After=network.target
Type=simple
WorkingDirectory={$SERVER_PATH}
EnvironmentFile={$SERVER_PATH}/scripts/init.d/service.sh
ExecStart=python3 task.py
ExecStart=python3 panel_task.py
ExecStop=kill -HUP $MAINID
ExecReload=kill -HUP $MAINID
KillMode=process

@ -231,6 +231,11 @@ error_logs()
mw_update()
{
if [ -f $mw_path/task.py ];then
echo "与后续版本差异太大,不再提供更新"
exit 0
fi
LOCAL_ADDR=common
cn=$(curl -fsSL -m 10 -s http://ipinfo.io/json | grep "\"country\": \"CN\"")
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
@ -246,6 +251,11 @@ mw_update()
mw_update_dev()
{
if [ -f $mw_path/task.py ];then
echo "与后续版本差异太大,不再提供更新"
exit 0
fi
LOCAL_ADDR=common
cn=$(curl -fsSL -m 10 -s http://ipinfo.io/json | grep "\"country\": \"CN\"")
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then

@ -4,6 +4,13 @@ export PATH
# LANG=en_US.UTF-8
is64bit=`getconf LONG_BIT`
if [ -f /www/server/mdserver-web/tools.py ];then
echo -e "存在旧版代码,不能安装!,已知风险的情况下"
echo -e "rm -rf /www/server/mdserver-web"
echo -e "可安装!"
exit 0
fi
LOG_FILE=/var/log/mw-install.log
{

@ -4,6 +4,14 @@ export PATH
# LANG=en_US.UTF-8
is64bit=`getconf LONG_BIT`
if [ -f /www/server/mdserver-web/tools.py ];then
echo -e "存在旧版代码,不能安装!,已知风险的情况下"
echo -e "rm -rf /www/server/mdserver-web"
echo -e "可安装!"
exit 0
fi
echo -e "您正在安装的是\033[31mmdserver-web测试版\033[0m,非开发测试用途请使用正式版 install.sh !"
echo -e "You are installing\033[31m mdserver-web dev version\033[0m, normally use install.sh for production.\n"
sleep 1

@ -0,0 +1,182 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
# LANG=en_US.UTF-8
is64bit=`getconf LONG_BIT`
echo -e "您正在安装的是\033[31mmdserver-web测试版\033[0m,非开发测试用途请使用正式版 install.sh !"
echo -e "You are installing\033[31m mdserver-web dev version\033[0m, normally use install.sh for production.\n"
sleep 1
LOG_FILE=/var/log/mw-install.log
{
if [ -f /etc/motd ];then
echo "welcome to mdserver-web panel" > /etc/motd
fi
startTime=`date +%s`
_os=`uname`
echo "use system: ${_os}"
if [ ${_os} == "Darwin" ]; then
OSNAME='macos'
elif grep -Eq "openSUSE" /etc/*-release; then
OSNAME='opensuse'
zypper refresh
zypper install -y wget curl zip unzip unrar rar
elif grep -Eq "FreeBSD" /etc/*-release; then
OSNAME='freebsd'
pkg install -y wget curl zip unzip unrar rar
elif grep -Eqi "EulerOS" /etc/*-release || grep -Eqi "openEuler" /etc/*-release; then
OSNAME='euler'
yum install -y wget curl zip unzip tar crontabs
elif grep -Eqi "CentOS" /etc/issue || grep -Eqi "CentOS" /etc/*-release; then
OSNAME='rhel'
yum install -y wget zip unzip tar
elif grep -Eqi "Fedora" /etc/issue || grep -Eqi "Fedora" /etc/*-release; then
OSNAME='rhel'
yum install -y wget zip unzip tar
elif grep -Eqi "Rocky" /etc/issue || grep -Eqi "Rocky" /etc/*-release; then
OSNAME='rhel'
yum install -y wget zip unzip
elif grep -Eqi "AlmaLinux" /etc/issue || grep -Eqi "AlmaLinux" /etc/*-release; then
OSNAME='rhel'
yum install -y wget zip unzip tar
elif grep -Eqi "Amazon Linux" /etc/issue || grep -Eqi "Amazon Linux" /etc/*-release; then
OSNAME='amazon'
yum install -y wget zip unzip tar
elif grep -Eqi "Ubuntu" /etc/issue || grep -Eqi "Ubuntu" /etc/*-release; then
OSNAME='ubuntu'
apt install -y wget zip unzip tar
elif grep -Eqi "Debian" /etc/issue || grep -Eqi "Debian" /etc/*-release; then
OSNAME='debian'
apt update -y
apt install -y devscripts
apt install -y wget zip unzip tar
else
OSNAME='unknow'
fi
if [ "$EUID" -ne 0 ] && [ "$OSNAME" != "macos" ];then
echo "Please run as root!"
exit
fi
# HTTP_PREFIX="https://"
# LOCAL_ADDR=common
# ping -c 1 github.com > /dev/null 2>&1
# if [ "$?" != "0" ];then
# LOCAL_ADDR=cn
# HTTP_PREFIX="https://mirror.ghproxy.com/"
# fi
HTTP_PREFIX="https://"
LOCAL_ADDR=common
cn=$(curl -fsSL -m 10 -s http://ipinfo.io/json | grep "\"country\": \"CN\"")
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
LOCAL_ADDR=cn
HTTP_PREFIX="https://mirror.ghproxy.com/"
fi
echo "local:${LOCAL_ADDR}"
echo "OSNAME:${OSNAME}"
if [ $OSNAME != "macos" ];then
if id www &> /dev/null ;then
echo ""
else
groupadd www
useradd -g www -s /usr/sbin/nologin www
fi
mkdir -p /www/server
mkdir -p /www/wwwroot
mkdir -p /www/wwwlogs
mkdir -p /www/backup/database
mkdir -p /www/backup/site
if [ ! -d /www/server/mdserver-web ];then
if [ "$LOCAL_ADDR" == "common" ];then
curl --insecure -sSLo /tmp/dev.zip ${HTTP_PREFIX}github.com/midoks/mdserver-web/archive/refs/heads/dev.zip
cd /tmp && unzip /tmp/dev.zip
mv -f /tmp/mdserver-web-dev /www/server/mdserver-web
rm -rf /tmp/dev.zip
rm -rf /tmp/mdserver-web-dev
else
# curl --insecure -sSLo /tmp/dev.zip https://code.midoks.icu/midoks/mdserver-web/archive/dev.zip
wget --no-check-certificate -O /tmp/dev.zip https://code.midoks.icu/midoks/mdserver-web/archive/dev.zip
cd /tmp && unzip /tmp/dev.zip
mv -f /tmp/mdserver-web /www/server/mdserver-web
rm -rf /tmp/dev.zip
rm -rf /tmp/mdserver-web
fi
fi
# install acme.sh
if [ ! -d /root/.acme.sh ];then
if [ "$LOCAL_ADDR" != "common" ];then
# curl -sSL -o /tmp/acme.tar.gz ${HTTP_PREFIX}github.com/acmesh-official/acme.sh/archive/master.tar.gz
curl --insecure -sSLo /tmp/acme.tar.gz https://gitee.com/neilpang/acme.sh/repository/archive/master.tar.gz
tar xvzf /tmp/acme.tar.gz -C /tmp
cd /tmp/acme.sh-master
bash acme.sh install
fi
if [ ! -d /root/.acme.sh ];then
curl https://get.acme.sh | sh
fi
fi
fi
echo "use system version: ${OSNAME}"
if [ "${OSNAME}" == "macos" ];then
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/master/scripts/install/macos.sh | bash
else
cd /www/server/mdserver-web && bash scripts/install/${OSNAME}.sh
fi
if [ "${OSNAME}" == "macos" ];then
echo "macos end"
exit 0
fi
cd /www/server/mdserver-web && bash cli_new.sh start
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
n=0
while [ ! -f /etc/rc.d/init.d/mw ];
do
echo -e ".\c"
sleep 1
let n+=1
if [ $n -gt 20 ];then
echo -e "start mw fail"
exit 1
fi
done
cd /www/server/mdserver-web && bash /etc/rc.d/init.d/mw stop
cd /www/server/mdserver-web && bash /etc/rc.d/init.d/mw start
cd /www/server/mdserver-web && bash /etc/rc.d/init.d/mw default
sleep 2
if [ ! -e /usr/bin/mw ]; then
if [ -f /etc/rc.d/init.d/mw ];then
ln -s /etc/rc.d/init.d/mw /usr/bin/mw
fi
fi
endTime=`date +%s`
((outTime=(${endTime}-${startTime})/60))
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
} 1> >(tee $LOG_FILE) 2>&1
echo -e "\nInstall completed. If error occurs, please contact us with the log file mw-install.log ."
echo "安装完毕,如果出现错误,请带上同目录下的安装日志 mw-install.log 联系我们反馈."

@ -19,7 +19,7 @@ fi
# openresty
if [ ! -d /www/server/openresty ];then
cd /www/server/mdserver-web/plugins/openresty && bash install.sh install 1.21.4.1
cd /www/server/mdserver-web/plugins/openresty && bash install.sh install 1.25.3
else
echo "openresty alreay exist!"
fi
@ -50,7 +50,7 @@ fi
# mysql
if [ ! -d /www/server/mysql ];then
cd /www/server/mdserver-web/plugins/mysql && bash install.sh install 5.6
cd /www/server/mdserver-web/plugins/mysql && bash install.sh install 5.7
else
echo "mysql alreay exist!"
fi

@ -6,6 +6,14 @@ is64bit=`getconf LONG_BIT`
startTime=`date +%s`
if [ -f /www/server/mdserver-web/tools.py ];then
echo -e "存在旧版代码,不能安装!,已知风险的情况下"
echo -e "rm -rf /www/server/mdserver-web"
echo -e "可安装!"
exit 0
fi
_os=`uname`
echo "use system: ${_os}"

@ -6,6 +6,13 @@ is64bit=`getconf LONG_BIT`
startTime=`date +%s`
if [ -f /www/server/mdserver-web/tools.py ];then
echo -e "存在旧版代码,不能安装!,已知风险的情况下"
echo -e "rm -rf /www/server/mdserver-web"
echo -e "可安装!"
exit 0
fi
_os=`uname`
echo "use system: ${_os}"

@ -1,4 +1,6 @@
urllib3==1.21.1
gevent==22.10.2
gunicorn==21.2.0
pyyaml
sqlalchemy==1.4.47
flask-sqlalchemy==2.5.1
pyyaml

@ -0,0 +1,236 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import sys
import json
import time
import uuid
import logging
from datetime import timedelta
from flask import Flask
from flask_socketio import SocketIO, emit, send
from flask import Flask, abort, current_app, session, url_for
from flask import Blueprint, render_template
from flask import render_template_string
from flask import request
from flask import Response
from flask_migrate import Migrate
from flask_caching import Cache
from werkzeug.local import LocalProxy
from admin import model
from admin import setup
from admin.model import db as sys_db
import core.mw as mw
import config
import utils.config as utils_config
root_dir = mw.getRunDir()
socketio = SocketIO(manage_session=False, async_mode='threading',
logger=False, engineio_logger=False, debug=False,
ping_interval=25, ping_timeout=120)
app = Flask(__name__, template_folder='templates/default')
# 缓存配置
cache = Cache(config={'CACHE_TYPE': 'simple'})
cache.init_app(app, config={'CACHE_TYPE': 'simple'})
# 静态文件配置
from whitenoise import WhiteNoise
app.wsgi_app = WhiteNoise(app.wsgi_app, root="../web/static/", prefix="static/", max_age=604800)
# session配置
app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:]
# app.config['sessions'] = dict()
app.config['SESSION_PERMANENT'] = True
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)
# db的配置
app.config['SQLALCHEMY_DATABASE_URI'] = mw.getSqitePrefix()+config.SQLITE_PATH+"?timeout=20" # 使用 SQLite 数据库
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 初始化db
sys_db.init_app(app)
Migrate(app, sys_db)
# 检查数据库是否存在。如果没有就创建它。
setup_db_required = False
if not os.path.isfile(config.SQLITE_PATH):
setup_db_required = True
# with app.app_context():
# sys_db.create_all()
with app.app_context():
if setup_db_required:
sys_db.create_all()
# 初始化用户信息
with app.app_context():
if setup_db_required:
setup.init_admin_user()
setup.init_option()
app.config['BASIC_AUTH_OPEN'] = False
with app.app_context():
basic_auth = model.getOptionByJson('basic_auth', default={'open':False})
if basic_auth['open']:
app.config['BASIC_AUTH_OPEN'] = True
# 加载模块
from .submodules import get_submodules
for module in get_submodules():
app.logger.info('Registering blueprint module: %s' % module)
if app.blueprints.get(module.name) is None:
app.register_blueprint(module)
def sendAuthenticated():
# 发送http认证信息
request_host = mw.getHostAddr()
result = Response('', 401, {'WWW-Authenticate': 'Basic realm="%s"' % request_host.strip()})
if not 'login' in session and not 'admin_auth' in session:
session.clear()
return result
@app.before_request
def requestCheck():
# 自定义basic auth认证
if app.config['BASIC_AUTH_OPEN']:
basic_auth = model.getOptionByJson('basic_auth', default={'open':False})
if not basic_auth['open']:
return
auth = request.authorization
if request.path in ['/download', '/hook', '/down']:
return
if not auth:
return sendAuthenticated()
# print(auth.username.strip(),auth.password.strip())
salt = basic_auth['salt']
basic_user = mw.md5(auth.username.strip() + salt)
basic_pwd = mw.md5(auth.password.strip() + salt)
if basic_user != basic_auth['basic_user'] or basic_pwd != basic_auth['basic_pwd']:
return sendAuthenticated()
@app.after_request
def requestAfter(response):
response.headers['soft'] = config.APP_NAME
response.headers['mw-version'] = config.APP_VERSION
return response
@app.errorhandler(404)
def page_unauthorized(error):
return render_template_string('404 not found', error_info=error), 404
# 设置模板全局变量
@app.context_processor
def inject_global_variables():
ver = config.APP_VERSION;
if mw.isDebugMode():
ver = ver + str(time.time())
data = utils_config.getGlobalVar()
g_config = {
'version': ver,
'title' : 'MW面板',
'ip' : '127.0.0.1'
}
return dict(config=g_config, data=data)
# from flasgger import Swagger
# api = Api(app, version='1.0', title='API', description='API 文档')
# Swagger(app)
# @app.route('/colors/<palette>/')
# def colors(palette):
# """
# 根据调色板名称返回颜色列表
# ---
# parameters:
# - name: palette
# in: path
# type: string
# enum: ['all', 'rgb', 'cmyk']
# required: true
# default: all
# definitions:
# Palette:
# type: object
# properties:
# palette_name:
# type: array
# items:
# $ref: '#/definitions/Color'
# Color:
# type: string
# responses:
# 200:
# description: 返回的颜色列表,可按调色板过滤
# schema:
# $ref: '#/definitions/Palette'
# examples:
# rgb: ['red', 'green', 'blue']
# """
# all_colors = {
# 'cmyk': ['cyan', 'magenta', 'yellow', 'black'],
# 'rgb': ['red', 'green', 'blue']
# }
# if palette == 'all':
# result = all_colorselse
# result = {palette: all_colors.get(palette)}
# return jsonify(result)
# Log the startup
app.logger.info('########################################################')
app.logger.info('Starting %s v%s...', config.APP_NAME, config.APP_VERSION)
app.logger.info('########################################################')
app.logger.debug("Python syspath: %s", sys.path)
# OK
socketio.init_app(app, cors_allowed_origins="*")
# def create_app(app_name = None):
#
# if not app_name:
# app_name = config.APP_NAME
# # Check if app is created for CLI operations or Web
# cli_mode = False
# if app_name.endswith('-cli'):
# cli_mode = True
# return app

@ -0,0 +1,37 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import time
from admin import model
from admin import session
def isLogined():
if 'login' in session and session['login'] == True and 'username' in session:
username = session['username']
info = model.getUserByName(username)
if info is None:
return False
# print(userInfo)
if info['name'] != session['username']:
return False
now_time = int(time.time())
if 'overdue' in session and now_time > session['overdue']:
# 自动续期
session['overdue'] = int(time.time()) + 7 * 24 * 60 * 60
return False
if 'tmp_login_expire' in session and now_time > int(session['tmp_login_expire']):
session.clear()
return False
return True

@ -0,0 +1,34 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
from flask import Blueprint, render_template
from flask import request
from admin.user_login_check import panel_login_required
from admin.model import Crontab
blueprint = Blueprint('crontab', __name__, url_prefix='/crontab', template_folder='../../templates/default')
@blueprint.route('/index', endpoint='index')
def index():
return render_template('crontab.html')
# 插件列表
@blueprint.route('/list', endpoint='list', methods=['GET','POST'])
@panel_login_required
def list():
page = request.args.get('p', 1)
size = 10
count = Crontab.query.count()
print(count)
clist = Crontab.query.paginate(page=int(page), per_page=size)
print(clist)
return []

@ -0,0 +1,240 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import io
import time
from flask import Blueprint, render_template
from flask import make_response
from flask import redirect
from flask import Response
from flask import request,g
from admin.common import isLogined
from admin.user_login_check import panel_login_required
from admin import cache,session
from admin import model
from admin.model import db,TempLogin,Users
import core.mw as mw
blueprint = Blueprint('dashboard', __name__, url_prefix='/', template_folder='../../templates')
@blueprint.route('/')
@panel_login_required
def index():
return render_template('default/index.html')
# 仅针对webhook插件
@blueprint.route("/hook", methods=['POST', 'GET'])
def webhook():
# 兼容获取关键数据
access_key = request.args.get('access_key', '').strip()
if access_key == '':
access_key = request.form.get('access_key', '').strip()
params = request.args.get('params', '').strip()
if params == '':
params = request.form.get('params', '').strip()
input_args = {
'access_key': access_key,
'params': params,
}
wh_install_path = mw.getServerDir() + '/webhook'
if not os.path.exists(wh_install_path):
return mw.returnJson(False, '请先安装WebHook插件!')
package = mw.getPanelDir() + "/plugins/webhook"
if not package in sys.path:
sys.path.append(package)
try:
import webhook_index
return webhook_index.runShellArgs(input_args)
except Exception as e:
return str(e)
# 安全路径
@blueprint.route('/<path>',endpoint='admin_safe_path',methods=['GET'])
def admin_safe_path(path):
db_path = model.getOption('admin_path')
if db_path == path:
return render_template('default/login.html')
unauthorized_status = model.getOption('unauthorized_status')
if unauthorized_status == '0':
return render_template('default/path.html')
return Response(status=int(unauthorized_status))
# ---------------------------------------------------------------------------------
# 定义登录入口相关方法
# ---------------------------------------------------------------------------------
def getErrorNum(key, limit=None):
key = mw.md5(key)
num = cache.get(key)
if not num:
num = 0
if not limit:
return num
if limit > num:
return True
return False
def setErrorNum(key, empty=False, expire=3600):
key = mw.md5(key)
num = cache.get(key)
if not num:
num = 0
else:
if empty:
cache.delete(key)
return True
cache.set(key, num + 1, expire)
return True
def login_temp_user(token):
if len(token) != 32:
return '错误的参数!'
skey = mw.getClientIp() + '_temp_login'
if not getErrorNum(skey, 10):
return '连续10次验证失败,禁止1小时'
stime = int(time.time())
tmp_data = model.getTempLoginByToken(token)
if not tmp_data:
setErrorNum(skey)
return '验证失败!'
if stime > int(tmp_data['expire']):
setErrorNum(skey)
return "过期"
user_data = model.getUserById(1)
login_addr = mw.getClientIp() + ":" + str(request.environ.get('REMOTE_PORT'))
mw.writeLog('用户临时登录', "登录成功,帐号:{1},登录IP:{2}",(user_data['name'], login_addr))
TempLogin.query.filter(TempLogin.id==tmp_data['id']).update({"login_time": stime, 'state': 1, 'login_addr': login_addr})
db.session.commit()
session['login'] = True
session['username'] = user_data['name']
session['tmp_login'] = True
session['tmp_login_id'] = str(tmp_data['id'])
session['tmp_login_expire'] = int(tmp_data['expire'])
session['uid'] = user_data['id']
return redirect('/')
# 登录页: 当设置了安全路径,本页失效。
@blueprint.route('/login')
def login():
# 临时登录功能
token = request.args.get('tmp_token', '').strip()
if token != '':
return login_temp_user(token)
# 注销登录
signout = request.args.get('signout', '')
if signout == 'True':
session.clear()
session['login'] = False
session['overdue'] = 0
db_path = model.getOption('admin_path')
if db_path == '':
return render_template('default/login.html')
else:
unauthorized_status = model.getOption('unauthorized_status')
if unauthorized_status == '0':
return render_template('default/path.html')
return Response(status=int(unauthorized_status))
# 验证码
@blueprint.route('/code')
def code():
import utils.vilidate as vilidate
vie = vilidate.vieCode()
codeImage = vie.GetCodeImage(80, 4)
out = io.BytesIO()
codeImage[0].save(out, "png")
session['code'] = mw.md5(''.join(codeImage[1]).lower())
img = Response(out.getvalue(), headers={'Content-Type': 'image/png'})
return make_response(img)
# 检查是否登录
@blueprint.route('/check_login',methods=['GET','POST'])
def check_login():
if isLogined():
return mw.returnData(True,'已登录')
return mw.returnData(False,'未登录')
# 执行登录操作
@blueprint.route('/do_login', endpoint='do_login', methods=['POST'])
def do_login():
username = request.form.get('username', '').strip()
password = request.form.get('password', '').strip()
code = request.form.get('code', '').strip()
login_cache_count = 5
login_cache_limit = cache.get('login_cache_limit')
if 'code' in session:
if session['code'] != mw.md5(code):
if login_cache_limit == None:
login_cache_limit = 1
else:
login_cache_limit = int(login_cache_limit) + 1
if login_cache_limit >= login_cache_count:
model.setOption('admin_close', 'yes')
return mw.returnJson(False, '面板已经关闭!')
cache.set('login_cache_limit', login_cache_limit, timeout=10000)
login_cache_limit = cache.get('login_cache_limit')
login_err_msg = mw.getInfo("验证码错误,您还可以尝试[{1}]次!", (str(login_cache_count - login_cache_limit)))
mw.writeLog('用户登录', login_err_msg)
return mw.returnData(False, login_err_msg)
info = model.getUserByName(username)
password = mw.md5(password)
if info['name'] != username or info['password'] != password:
msg = "<a style='color: red'>密码错误</a>,帐号:{1},密码:{2},登录IP:{3}", (('****', '******', request.remote_addr))
if login_cache_limit == None:
login_cache_limit = 1
else:
login_cache_limit = int(login_cache_limit) + 1
if login_cache_limit >= login_cache_count:
model.setOption('admin_close', 'yes')
return mw.returnData(False, '面板已经关闭!')
cache.set('login_cache_limit', login_cache_limit, timeout=10000)
login_cache_limit = cache.get('login_cache_limit')
mw.writeLog('用户登录', mw.getInfo(msg))
return mw.returnData(-1, mw.getInfo("用户名或密码错误,您还可以尝试[{1}]次!", (str(login_cache_count - login_cache_limit))))
session['login'] = True
session['username'] = info['name']
session['overdue'] = int(time.time()) + 7 * 24 * 60 * 60
return mw.returnJson(1, '登录成功,正在跳转...')

@ -0,0 +1,156 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
from flask import Blueprint, render_template
from flask import request
from admin import model
from admin.user_login_check import panel_login_required
import core.mw as mw
import utils.file as file
blueprint = Blueprint('files', __name__, url_prefix='/files', template_folder='../../templates/default')
@blueprint.route('/index', endpoint='index')
@panel_login_required
def index():
return render_template('files.html')
# 获取文件内容
@blueprint.route('/get_body', endpoint='get_file_body', methods=['POST'])
@panel_login_required
def get_file_body():
path = request.form.get('path', '')
return file.getFileBody(path)
# 获取文件内容
@blueprint.route('/save_body', endpoint='save_body', methods=['POST'])
@panel_login_required
def save_body():
path = request.form.get('path', '')
data = request.form.get('data', '')
encoding = request.form.get('encoding', '')
if not os.path.exists(path):
return mw.returnData(False, '文件不存在')
try:
if encoding == 'ascii':
encoding = 'utf-8'
data = data.encode(encoding, errors='ignore').decode(encoding)
fp = open(path, 'w+', encoding=encoding)
fp.write(data)
fp.close()
if path.find("web_conf") > 0:
mw.restartWeb()
mw.writeLog('文件管理', '文件[{1}]保存成功', (path,))
return mw.returnData(True, '文件保存成功')
except Exception as ex:
return mw.returnData(False, '文件保存错误:' + str(ex))
# 获取文件内容(最新行数)
@blueprint.route('/get_last_body', endpoint='get_file_last_body', methods=['POST'])
@panel_login_required
def get_file_last_body():
path = request.form.get('path', '')
line = request.form.get('line', '100')
if not os.path.exists(path):
return mw.returnData(False, '文件不存在', (path,))
try:
data = mw.getLastLine(path, int(line))
return mw.returnData(True, 'OK', data)
except Exception as ex:
return mw.returnData(False, '无法正确读取文件!' + str(ex))
# 获取文件列表
@blueprint.route('/get_dir', endpoint='get_dir', methods=['POST'])
@panel_login_required
def get_dir():
path = request.form.get('path', '')
if not os.path.exists(path):
path = mw.getFatherDir() + '/wwwroot'
search = request.args.get('search', '').strip().lower()
search_all = request.args.get('all', '').strip().lower()
page = request.args.get('p', '1').strip().lower()
row = request.args.get('row', '10')
order = request.form.get('order', '')
if search_all == 'yes' and search != '':
dir_list = file.getAllDirList(path, int(page), int(row),order, search)
else:
dir_list = file.getDirList(path, int(page), int(row),order, search)
dir_list['page'] = mw.getPage({'p':page, 'row': row, 'tojs':'getFiles', 'count': dir_list['count']}, '1,2,3,4,5,6,7,8')
return dir_list
# 获取站点日志目录
@blueprint.route('/get_dir_size', endpoint='get_dir_size', methods=['POST'])
@panel_login_required
def get_dir_size():
path = request.form.get('path', '')
size = file.getDirSize(path)
return mw.returnData(True, mw.toSize(size))
# 删除文件
@blueprint.route('/delete', endpoint='delete', methods=['POST'])
@panel_login_required
def delete():
path = request.form.get('path', '')
return file.fileDelete(path)
# 删除文件
@blueprint.route('/delete_dir', endpoint='delete_dir', methods=['POST'])
@panel_login_required
def delete_dir():
path = request.form.get('path', '')
return file.dirDelete(path)
# 回收站文件
@blueprint.route('/get_recycle_bin', endpoint='get_recycle_bin', methods=['POST'])
@panel_login_required
def get_recycle_bin():
return file.getRecycleBin()
# 回收站文件恢复
@blueprint.route('/re_recycle_bin', endpoint='re_recycle_bin', methods=['POST'])
@panel_login_required
def re_recycle_bin():
path = request.form.get('path', '')
return file.reRecycleBin(path)
# 回收站文件
@blueprint.route('/recycle_bin', endpoint='recycle_bin', methods=['POST'])
@panel_login_required
def recycle_bin():
return file.toggleRecycleBin()

@ -0,0 +1,84 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
from flask import Blueprint, render_template
from flask import request
from admin.user_login_check import panel_login_required
from admin.model import db, Firewall
from utils.firewall import Firewall as MwFirewall
import core.mw as mw
blueprint = Blueprint('firewall', __name__, url_prefix='/firewall', template_folder='../../templates/default')
@blueprint.route('/index', endpoint='index')
@panel_login_required
def index():
return render_template('firewall.html')
# 防火墙列表
@blueprint.route('/get_list', endpoint='get_list', methods=['POST'])
@panel_login_required
def get_list():
p = request.form.get('p', '1').strip()
limit = request.form.get('limit', '10').strip()
count = Firewall.query.filter_by().count()
pagination = Firewall.query.filter_by().paginate(page=int(p), per_page=int(limit))
rows = []
for item in pagination.items:
t = {}
t['id'] = item.id
t['port'] = item.port
t['protocol'] = item.protocol
t['ps'] = item.ps
t['add_time'] = item.add_time
t['update_time'] = item.update_time
rows.append(t)
data = {}
data['data'] = rows
data['page'] = mw.getPage({'count':count,'tojs':'getLogs','p':p,'row':limit})
return data
# 获取站点日志目录
@blueprint.route('/get_www_path', endpoint='get_www_path', methods=['POST'])
@panel_login_required
def get_www_path():
path = mw.getLogsDir()
return {'path': path}
# 获取ssh信息
@blueprint.route('/get_ssh_info', endpoint='get_ssh_info', methods=['POST'])
@panel_login_required
def get_ssh_info():
mf = MwFirewall.instance()
return mf.getSshInfo()
# 切换ping开关
@blueprint.route('/set_ping', endpoint='set_ping', methods=['POST'])
@panel_login_required
def set_ping():
mf = MwFirewall.instance()
return mf.setPing()

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save