mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-11 01:59:25 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1b3e70816 | ||
|
|
6f4479558f | ||
|
|
f817792aeb | ||
|
|
c8c0e44143 | ||
|
|
6668c2e14b | ||
|
|
721f041c65 | ||
|
|
87239f5361 | ||
|
|
b48e3cbfcc | ||
|
|
4b41c6df57 | ||
|
|
b491a6e913 | ||
|
|
42271c5562 | ||
|
|
ef63465aea | ||
|
|
98745e8134 | ||
|
|
2fb293c89c | ||
|
|
4e0db8d0a1 | ||
|
|
4b1e40b42d | ||
|
|
935bee90f7 | ||
|
|
0489a9df2c | ||
|
|
20a4154240 | ||
|
|
a8ced31d32 | ||
|
|
ac97b8f7ec | ||
|
|
a797cd3741 | ||
|
|
a616736bf1 | ||
|
|
8a90f5cb90 | ||
|
|
419d4abe8e | ||
|
|
ba555fba63 | ||
|
|
7ead8708bc | ||
|
|
bd5b066afe | ||
|
|
6d08c160e0 | ||
|
|
f24f8a3a16 | ||
|
|
707b0d4b53 | ||
|
|
d19e9cd8f4 | ||
|
|
a2d0cc6cfe | ||
|
|
356fd831fb | ||
|
|
ec4988e732 | ||
|
|
3a694b8d7d | ||
|
|
d5945fd449 | ||
|
|
10186786d9 | ||
|
|
0eb8791e84 | ||
|
|
5234b55798 |
+1
-2
@@ -154,6 +154,7 @@ data/notify.json
|
||||
data/api.json
|
||||
data/bind_domain.pl
|
||||
data/unauthorized_status.pl
|
||||
data/auth_secret.pl
|
||||
|
||||
plugins/vip_*
|
||||
plugins/own_*
|
||||
@@ -175,7 +176,5 @@ plugins/proxysql
|
||||
debug.out
|
||||
|
||||
|
||||
|
||||
|
||||
mdioks.session-journal
|
||||
*.session
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
- 吹水组 - https://t.me/mdserver_web
|
||||
- 交流论坛 - https://bbs.midoks.icu
|
||||
|
||||
- discord - https://discord.gg/3zXk4mES
|
||||
```
|
||||
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
|
||||
Talk is cheap, show me the code. -- linus
|
||||
@@ -90,7 +90,7 @@ PHP[72-83]支持phpMyAdmin[5.2.0]
|
||||
|
||||
# 特别赞助
|
||||
|
||||
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.pw/)
|
||||
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan1.cc)
|
||||
|
||||
# AD - VPS推荐 - 🙏
|
||||
|
||||
@@ -110,15 +110,10 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
|
||||
```
|
||||
|
||||
|
||||
### 版本更新 0.16.3
|
||||
### 版本更新 0.16.4
|
||||
|
||||
* 面板配置-可以配置时区。
|
||||
* PHP(GD)扩展安装优化。
|
||||
* PHP界面功能调整。
|
||||
* PHP-FPM设置多个应用池(提高高并发稳定性)。
|
||||
* MySQL(apt/yum)调整优化。
|
||||
* 网站类型优化。
|
||||
* 增加数据管理插件。
|
||||
* 二次验证。
|
||||
* OP防火墙修复。
|
||||
|
||||
### JSDelivr安装地址
|
||||
|
||||
@@ -196,7 +191,7 @@ TVbNgrpeGBGZVm5gTLa21ADP7RpnPFhjya
|
||||
|
||||
### 微信赞助
|
||||
|
||||
[](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/weixin_zz.jpg)
|
||||
[](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/alipay_zz.jpg)
|
||||
|
||||
|
||||
### 无图不真相
|
||||
|
||||
+105
-47
@@ -28,9 +28,26 @@ from flask import request
|
||||
|
||||
class config_api:
|
||||
|
||||
__version = '0.16.3'
|
||||
__version = '0.16.4'
|
||||
__api_addr = 'data/api.json'
|
||||
|
||||
# 统一默认配置文件
|
||||
__file = {
|
||||
'api' : 'data/api.json', # API文件
|
||||
'debug' : 'data/debug.pl', # DEBUG文件
|
||||
'close' : 'data/close.pl', # 识别关闭面板文件
|
||||
'basic_auth' : 'data/basic_auth.json', # 面板Basic验证
|
||||
'admin_path' : 'data/admin_path.pl', # 面板后缀路径设置
|
||||
'ipv6' : 'data/ipv6.pl', # ipv6识别文件
|
||||
'bind_domain' : 'data/bind_domain.pl', # 面板域名绑定
|
||||
'unauth_status' : 'data/unauthorized_status.pl', # URL路径未成功显示状态
|
||||
'auth_secret': 'data/auth_secret.pl', # 二次验证密钥
|
||||
'ssl':'data/ssl.pl', # ssl设置
|
||||
'hook_database' : 'data/hook_database.json', # 数据库钩子
|
||||
'hook_menu' : 'data/hook_menu.json', # 菜单钩子
|
||||
'hook_global_static' : 'data/hook_global_static.json', # 静态文件钩子
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -179,7 +196,7 @@ class config_api:
|
||||
basic_open = request.form.get('is_open', '').strip()
|
||||
|
||||
salt = '_md_salt'
|
||||
path = 'data/basic_auth.json'
|
||||
path = self.__file['basic_auth']
|
||||
is_open = True
|
||||
|
||||
if basic_open == 'false':
|
||||
@@ -224,7 +241,7 @@ class config_api:
|
||||
backup_path = request.form.get('backup_path', '')
|
||||
|
||||
if domain != '':
|
||||
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
|
||||
reg = "^([\\w\\-\\*]{1,100}\\.){1,4}(\\w{1,10}|\\w{1,10}\\.\\w{1,10})$"
|
||||
if not re.match(reg, domain):
|
||||
return mw.returnJson(False, '主域名格式不正确')
|
||||
|
||||
@@ -286,7 +303,7 @@ class config_api:
|
||||
return mw.returnJson(False, '安全入口地址长度不能小于6位!')
|
||||
if admin_path in admin_path_checks:
|
||||
return mw.returnJson(False, '该入口已被面板占用,请使用其它入口!')
|
||||
if not re.match("^/[\w\./-_]+$", admin_path):
|
||||
if not re.match("^/[\\w\\./-_]+$", admin_path):
|
||||
return mw.returnJson(False, '入口地址格式不正确,示例: /mw_rand')
|
||||
# else:
|
||||
# domain = mw.readFile('data/bind_domain.pl')
|
||||
@@ -300,7 +317,7 @@ class config_api:
|
||||
# '警告,关闭安全入口等于直接暴露你的后台地址在外网,十分危险,至少开启以下一种安全方式才能关闭:<a
|
||||
# style="color:red;"><br>1、绑定访问域名<br>2、绑定授权IP</a>')
|
||||
|
||||
admin_path_file = 'data/admin_path.pl'
|
||||
admin_path_file = self.__file['admin_path']
|
||||
admin_path_old = '/'
|
||||
if os.path.exists(admin_path_file):
|
||||
admin_path_old = mw.readFile(admin_path_file).strip()
|
||||
@@ -311,7 +328,7 @@ class config_api:
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
def closePanelApi(self):
|
||||
filename = 'data/close.pl'
|
||||
filename = self.__file['close']
|
||||
if os.path.exists(filename):
|
||||
os.remove(filename)
|
||||
return mw.returnJson(True, '开启成功')
|
||||
@@ -329,8 +346,8 @@ class config_api:
|
||||
return mw.returnJson(True, '开发模式开启!')
|
||||
|
||||
def setIpv6StatusApi(self):
|
||||
ipv6_file = 'data/ipv6.pl'
|
||||
if os.path.exists('data/ipv6.pl'):
|
||||
ipv6_file = self.__file['ipv6']
|
||||
if os.path.exists(ipv6_file):
|
||||
os.remove(ipv6_file)
|
||||
mw.writeLog('面板设置', '关闭面板IPv6兼容!')
|
||||
else:
|
||||
@@ -400,7 +417,7 @@ class config_api:
|
||||
# 设置面板SSL证书设置
|
||||
def setPanelHttpToHttpsApi(self):
|
||||
|
||||
bind_domain = 'data/bind_domain.pl'
|
||||
bind_domain = self.__file['bind_domain']
|
||||
if not os.path.exists(bind_domain):
|
||||
return mw.returnJson(False, '先要绑定域名!')
|
||||
|
||||
@@ -430,9 +447,9 @@ class config_api:
|
||||
else:
|
||||
conf = mw.readFile(panel_ssl)
|
||||
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+if.+server_port.+\n.+\n\s+\s*}"
|
||||
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeFile(panel_ssl, conf)
|
||||
|
||||
@@ -445,7 +462,7 @@ class config_api:
|
||||
|
||||
# 删除面板证书
|
||||
def delPanelSslApi(self):
|
||||
bind_domain = 'data/bind_domain.pl'
|
||||
bind_domain = self.__file['bind_domain']
|
||||
if not os.path.exists(bind_domain):
|
||||
return mw.returnJson(False, '未绑定域名!')
|
||||
|
||||
@@ -474,7 +491,7 @@ class config_api:
|
||||
def applyPanelLetSslApi(self):
|
||||
|
||||
# check domain is bind?
|
||||
bind_domain = 'data/bind_domain.pl'
|
||||
bind_domain = self.__file['bind_domain']
|
||||
if not os.path.exists(bind_domain):
|
||||
return mw.returnJson(False, '先要绑定域名!')
|
||||
|
||||
@@ -531,7 +548,7 @@ class config_api:
|
||||
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
|
||||
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
|
||||
|
||||
cfg_domain = 'data/bind_domain.pl'
|
||||
cfg_domain = self.__file['bind_domain']
|
||||
if domain == '':
|
||||
os.remove(cfg_domain)
|
||||
os.remove(dst_panel_path)
|
||||
@@ -560,7 +577,7 @@ class config_api:
|
||||
|
||||
# 设置面板SSL
|
||||
def setPanelSslApi(self):
|
||||
sslConf = mw.getRunDir() + '/data/ssl.pl'
|
||||
sslConf = mw.getRunDir() + '/' + self.__file['ssl']
|
||||
|
||||
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
|
||||
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
|
||||
@@ -569,35 +586,35 @@ class config_api:
|
||||
|
||||
conf = mw.readFile(dst_panel_path)
|
||||
if 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 = "\\s+ssl_session_timeout\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_ecdh_curve\s+.+;\n"
|
||||
rep = "\\s+ssl_ecdh_curve\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_session_tickets\s+.+;\n"
|
||||
rep = "\\s+ssl_session_tickets\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_stapling\s+.+;\n"
|
||||
rep = "\\s+ssl_stapling\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl_stapling_verify\s+.+;\n"
|
||||
rep = "\\s+ssl_stapling_verify\\s+.+;\n"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+ssl\s+on;"
|
||||
rep = "\\s+ssl\\s+on;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+error_page\s497.+;"
|
||||
rep = "\\s+error_page\\s497.+;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
|
||||
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+listen\s+443.*;"
|
||||
rep = "\\s+listen\\s+443.*;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
rep = "\s+listen\s+\[\:\:\]\:443.*;"
|
||||
rep = "\\s+listen\\s+\\[\\:\\:\\]\\:443.*;"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeFile(dst_panel_path, conf)
|
||||
|
||||
@@ -628,7 +645,7 @@ class config_api:
|
||||
|
||||
conf = conf.replace('#error_page 404/404.html;', sslStr)
|
||||
|
||||
rep = "listen\s+([0-9]+)\s*[default_server]*;"
|
||||
rep = "listen\\s+([0-9]+)\\s*[default_server]*;"
|
||||
tmp = re.findall(rep, conf)
|
||||
if not mw.inArray(tmp, '443'):
|
||||
listen = re.search(rep, conf).group()
|
||||
@@ -744,15 +761,15 @@ class config_api:
|
||||
|
||||
def setStatusCodeApi(self):
|
||||
status_code = request.form.get('status_code', '').strip()
|
||||
if re.match("^\d+$", status_code):
|
||||
if re.match("^\\d+$", status_code):
|
||||
status_code = int(status_code)
|
||||
if status_code != 0:
|
||||
if status_code < 100 or status_code > 999:
|
||||
return mw.returnJson(False, '状态码范围错误!')
|
||||
else:
|
||||
return mw.returnJson(False, '状态码范围错误!')
|
||||
|
||||
mw.writeFile('data/unauthorized_status.pl', str(status_code))
|
||||
unauthorized_status = self.__file['unauth_status']
|
||||
mw.writeFile(unauthorized_status, str(status_code))
|
||||
mw.writeLog('面板设置', '将未授权响应状态码设置为:{}'.format(status_code))
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
@@ -871,8 +888,7 @@ class config_api:
|
||||
if not 'token_crypt' in data:
|
||||
token = mw.getRandomString(32)
|
||||
data['token'] = mw.md5(token)
|
||||
data['token_crypt'] = mw.enCrypt(
|
||||
data['token'], token).decode('utf-8')
|
||||
data['token_crypt'] = mw.enCrypt(data['token'], token).decode('utf-8')
|
||||
|
||||
token = stats[data['open']] + '成功!'
|
||||
mw.writeLog('API配置', '%sAPI接口' % stats[data['open']])
|
||||
@@ -888,7 +904,7 @@ class config_api:
|
||||
return mw.returnJson(True, '保存成功!')
|
||||
|
||||
def renderUnauthorizedStatus(self, data):
|
||||
cfg_unauth_status = 'data/unauthorized_status.pl'
|
||||
cfg_unauth_status = self.__file['unauth_status']
|
||||
if os.path.exists(cfg_unauth_status):
|
||||
status_code = mw.readFile(cfg_unauth_status)
|
||||
data['status_code'] = status_code
|
||||
@@ -927,6 +943,37 @@ class config_api:
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
def getAuthSecretApi(self):
|
||||
reset = request.form.get('reset', '')
|
||||
|
||||
import pyotp
|
||||
auth = self.__file['auth_secret']
|
||||
tag = 'mdserver-web'
|
||||
if os.path.exists(auth) and reset != '1':
|
||||
content = mw.readFile(auth)
|
||||
sec = mw.deDoubleCrypt(tag,content)
|
||||
else:
|
||||
sec = pyotp.random_base32()
|
||||
crypt_data = mw.enDoubleCrypt(tag, sec)
|
||||
mw.writeFile(auth, crypt_data)
|
||||
|
||||
ip = mw.getHostAddr()
|
||||
url = pyotp.totp.TOTP(sec).provisioning_uri(name=ip, issuer_name='mdserver-web')
|
||||
|
||||
rdata = {}
|
||||
rdata['secret'] = sec
|
||||
rdata['url'] = url
|
||||
return mw.returnJson(True, '设置成功!', rdata)
|
||||
|
||||
def setAuthSecretApi(self):
|
||||
auth = self.__file['auth_secret']
|
||||
if os.path.exists(auth):
|
||||
os.remove(auth)
|
||||
return mw.returnJson(True, '关闭成功!', 0)
|
||||
else:
|
||||
return mw.returnJson(True, '开启成功!', 1)
|
||||
|
||||
|
||||
def get(self):
|
||||
|
||||
data = {}
|
||||
@@ -939,31 +986,38 @@ class config_api:
|
||||
data['port'] = mw.getHostPort()
|
||||
data['ip'] = mw.getHostAddr()
|
||||
|
||||
admin_path_file = 'data/admin_path.pl'
|
||||
admin_path_file = self.__file['admin_path']
|
||||
if not os.path.exists(admin_path_file):
|
||||
data['admin_path'] = '/'
|
||||
else:
|
||||
data['admin_path'] = mw.readFile(admin_path_file)
|
||||
|
||||
ipv6_file = 'data/ipv6.pl'
|
||||
ipv6_file = self.__file['ipv6']
|
||||
if os.path.exists(ipv6_file):
|
||||
data['ipv6'] = 'checked'
|
||||
else:
|
||||
data['ipv6'] = ''
|
||||
|
||||
debug_file = 'data/debug.pl'
|
||||
debug_file = self.__file['debug']
|
||||
if os.path.exists(debug_file):
|
||||
data['debug'] = 'checked'
|
||||
else:
|
||||
data['debug'] = ''
|
||||
|
||||
ssl_file = 'data/ssl.pl'
|
||||
if os.path.exists('data/ssl.pl'):
|
||||
ssl_file = self.__file['ssl']
|
||||
if os.path.exists(ssl_file):
|
||||
data['ssl'] = 'checked'
|
||||
else:
|
||||
data['ssl'] = ''
|
||||
|
||||
basic_auth = 'data/basic_auth.json'
|
||||
|
||||
auth_secret = self.__file['auth_secret']
|
||||
if os.path.exists(auth_secret):
|
||||
data['auth_secret'] = 'checked'
|
||||
else:
|
||||
data['auth_secret'] = ''
|
||||
|
||||
basic_auth = self.__file['basic_auth']
|
||||
if os.path.exists(basic_auth):
|
||||
bac = mw.readFile(basic_auth)
|
||||
bac = json.loads(bac)
|
||||
@@ -972,7 +1026,7 @@ class config_api:
|
||||
else:
|
||||
data['basic_auth'] = ''
|
||||
|
||||
cfg_domain = 'data/bind_domain.pl'
|
||||
cfg_domain = self.__file['bind_domain']
|
||||
if os.path.exists(cfg_domain):
|
||||
domain = mw.readFile(cfg_domain)
|
||||
data['bind_domain'] = domain.strip()
|
||||
@@ -981,6 +1035,7 @@ class config_api:
|
||||
|
||||
data = self.renderUnauthorizedStatus(data)
|
||||
|
||||
#api
|
||||
api_token = self.__api_addr
|
||||
if os.path.exists(api_token):
|
||||
bac = mw.readFile(api_token)
|
||||
@@ -990,6 +1045,9 @@ class config_api:
|
||||
else:
|
||||
data['api_token'] = ''
|
||||
|
||||
#auth
|
||||
|
||||
|
||||
data['site_count'] = mw.M('sites').count()
|
||||
|
||||
data['username'] = mw.M('users').where(
|
||||
@@ -998,7 +1056,7 @@ class config_api:
|
||||
data['hook_tag'] = request.args.get('tag', '')
|
||||
|
||||
# databases hook
|
||||
database_hook_file = 'data/hook_database.json'
|
||||
database_hook_file = self.__file['hook_database']
|
||||
if os.path.exists(database_hook_file):
|
||||
df = mw.readFile(database_hook_file)
|
||||
df = json.loads(df)
|
||||
@@ -1007,7 +1065,7 @@ class config_api:
|
||||
data['hook_database'] = []
|
||||
|
||||
# menu hook
|
||||
menu_hook_file = 'data/hook_menu.json'
|
||||
menu_hook_file = self.__file['hook_menu']
|
||||
if os.path.exists(menu_hook_file):
|
||||
df = mw.readFile(menu_hook_file)
|
||||
df = json.loads(df)
|
||||
@@ -1016,7 +1074,7 @@ class config_api:
|
||||
data['hook_menu'] = []
|
||||
|
||||
# global_static hook
|
||||
global_static_hook_file = 'data/hook_global_static.json'
|
||||
global_static_hook_file = self.__file['hook_global_static']
|
||||
if os.path.exists(global_static_hook_file):
|
||||
df = mw.readFile(global_static_hook_file)
|
||||
df = json.loads(df)
|
||||
|
||||
+7
-7
@@ -246,7 +246,7 @@ def isInstalledWeb():
|
||||
|
||||
def isIpAddr(ip):
|
||||
check_ip = re.compile(
|
||||
'^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$')
|
||||
'^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$')
|
||||
if check_ip.match(ip):
|
||||
return True
|
||||
else:
|
||||
@@ -1176,10 +1176,10 @@ def getLocalIpBack():
|
||||
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
|
||||
req = urllib.request.urlopen(url, timeout=10)
|
||||
content = req.read().decode('utf-8')
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', content).group(0)
|
||||
ipaddress = re.search('\\d+.\\d+.\\d+.\\d+', content).group(0)
|
||||
writeFile(filename, ipaddress)
|
||||
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', ipaddress).group(0)
|
||||
ipaddress = re.search('\\d+.\\d+.\\d+.\\d+', ipaddress).group(0)
|
||||
return ipaddress
|
||||
except Exception as ex:
|
||||
# print(ex)
|
||||
@@ -1244,7 +1244,7 @@ def checkIp(ip):
|
||||
# 检查是否为IPv4地址
|
||||
import re
|
||||
p = re.compile(
|
||||
'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')
|
||||
'^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$')
|
||||
if p.match(ip):
|
||||
return True
|
||||
else:
|
||||
@@ -1382,13 +1382,13 @@ def getCpuType():
|
||||
|
||||
# 取CPU类型
|
||||
cpuinfo = open('/proc/cpuinfo', 'r').read()
|
||||
rep = "model\s+name\s+:\s+(.+)"
|
||||
rep = "model\\s+name\\s+:\\s+(.+)"
|
||||
tmp = re.search(rep, cpuinfo, re.I)
|
||||
if tmp:
|
||||
cpuType = tmp.groups()[0]
|
||||
else:
|
||||
cpuinfo = execShell('LANG="en_US.UTF-8" && lscpu')[0]
|
||||
rep = "Model\s+name:\s+(.+)"
|
||||
rep = "Model\\s+name:\\s+(.+)"
|
||||
tmp = re.search(rep, cpuinfo, re.I)
|
||||
if tmp:
|
||||
cpuType = tmp.groups()[0]
|
||||
@@ -1772,7 +1772,7 @@ def getSSHPort():
|
||||
try:
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = readFile(file)
|
||||
rep = "(#*)?Port\s+([0-9]+)\s*\n"
|
||||
rep = "(#*)?Port\\s+([0-9]+)\\s*\n"
|
||||
port = re.search(rep, conf).groups(0)[1]
|
||||
return int(port)
|
||||
except:
|
||||
|
||||
@@ -202,6 +202,11 @@ class nosqlMySQLCtr():
|
||||
sql = 'select * from ' + table + where_sql + ' limit '+str(start_index)+',10';
|
||||
# print(sql)
|
||||
result = my_instance.query(sql)
|
||||
|
||||
for i in range(len(result)):
|
||||
for f in result[i]:
|
||||
result[i][f] = str(result[i][f])
|
||||
|
||||
# print(result)
|
||||
|
||||
page_args = {}
|
||||
|
||||
@@ -38,7 +38,7 @@ Install_App()
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
HTTP_PREFIX="https://"
|
||||
if [ ! -z "$cn" ];then
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
# FlameGraph start
|
||||
|
||||
@@ -15,7 +15,9 @@ if [ ! -d $GIT_PROJECT_DIR ];then
|
||||
fi
|
||||
|
||||
unset GIT_DIR
|
||||
git config pull.rebase false
|
||||
|
||||
git config pull.rebase true
|
||||
git config credential.helper store
|
||||
|
||||
cd $GIT_PROJECT_DIR && git pull
|
||||
|
||||
|
||||
@@ -2598,6 +2598,10 @@ def trySlaveSyncBugfix(version=''):
|
||||
|
||||
gtid_purged = ''
|
||||
|
||||
var_slave_gtid = sdb.query('show VARIABLES like "%gtid_purged%"')
|
||||
if len(var_slave_gtid) > 0:
|
||||
gtid_purged += var_slave_gtid[0]['Value'] + ','
|
||||
|
||||
for i in range(len(slave_sync_data)):
|
||||
port = slave_sync_data[i]['port']
|
||||
password = slave_sync_data[i]['pass']
|
||||
@@ -2617,6 +2621,8 @@ def trySlaveSyncBugfix(version=''):
|
||||
if len(var_gtid) > 0:
|
||||
gtid_purged += var_gtid[0]['Value'] + ','
|
||||
|
||||
|
||||
|
||||
gtid_purged = gtid_purged.strip(',')
|
||||
sql = "set @@global.gtid_purged='" + gtid_purged + "'"
|
||||
|
||||
|
||||
@@ -579,6 +579,12 @@ def reload():
|
||||
mw.opWeb('start')
|
||||
return 'ok'
|
||||
|
||||
def reload_hook():
|
||||
s = status()
|
||||
if s == 'start':
|
||||
return reload()
|
||||
return 'ok'
|
||||
|
||||
|
||||
def getJsonPath(name):
|
||||
path = getServerDir() + "/waf/" + name + ".json"
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"site_cb": {
|
||||
"title":"网站统计",
|
||||
"name":"op_waf",
|
||||
"add":{"func":"reload"},
|
||||
"update":{"func":"reload"},
|
||||
"delete":{"func":"reload"}
|
||||
"add":{"func":"reload_hook"},
|
||||
"update":{"func":"reload_hook"},
|
||||
"delete":{"func":"reload_hook"}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -87,7 +87,7 @@ Install_App(){
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
HTTP_PREFIX="https://"
|
||||
if [ ! -z "$cn" ];then
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
# download GeoLite Data
|
||||
|
||||
@@ -1614,8 +1614,9 @@ function wafSite(){
|
||||
<label class="btswitch-btn" for="closeget_'+ i + '" onclick="setSiteObjState(\'' + k + '\',\'open\')"></label>\
|
||||
</div>\
|
||||
</td>\
|
||||
<td class="text-right"><a onclick="wafLogs(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a></td>\
|
||||
<td class="text-right"><a onclick="wafLogs(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> </td>\
|
||||
</tr>';
|
||||
//| <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a>
|
||||
});
|
||||
|
||||
var con = '<div class="lib-box">\
|
||||
|
||||
@@ -18,7 +18,7 @@ LOCAL_ADDR=common
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
|
||||
LOCAL_ADDR=cn
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
if [ ! -d ${SERVER_ROOT}/icu ];then
|
||||
|
||||
@@ -20,7 +20,7 @@ LOCAL_ADDR=common
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
|
||||
LOCAL_ADDR=cn
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
if [ ! -d ${SERVER_ROOT}/libiconv ];then
|
||||
|
||||
@@ -20,7 +20,7 @@ LOCAL_ADDR=common
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
|
||||
LOCAL_ADDR=cn
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
# HTTP_PREFIX="https://"
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ SOURCE_ROOT=$rootPath/source/lib
|
||||
HTTP_PREFIX="https://"
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
which onig-config
|
||||
|
||||
@@ -19,7 +19,7 @@ LOCAL_ADDR=common
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
|
||||
LOCAL_ADDR=cn
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
if [ ! -d ${SERVER_ROOT}/openssl10 ];then
|
||||
|
||||
@@ -20,7 +20,7 @@ LOCAL_ADDR=common
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
|
||||
LOCAL_ADDR=cn
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
# HTTP_PREFIX="https://"
|
||||
|
||||
|
||||
@@ -84,7 +84,8 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
resetPluginWinWidth(700);
|
||||
resetPluginWinWidth(800);
|
||||
resetPluginWinHeight(400);
|
||||
// $.getScript("/plugins/file?name=rsyncd&f=js/base64.js", function() {
|
||||
// console.log('base64 load');
|
||||
// });
|
||||
|
||||
@@ -42,11 +42,15 @@ def send_msg(bot, tag='ad', trigger_time=300):
|
||||
# 信号只在一个周期内执行一次|end
|
||||
|
||||
# https://t.me/gjgzs2022 | 22/m | @GJ_gzs
|
||||
# https://zhaoziyuan.pw/ | web | 15/m | 2m | next,3/15 | @baleite
|
||||
# 腾云机场 |9/m
|
||||
# https://zhaoziyuan1.cc | web | 15/m | 2m | next,5/15 | @baleite
|
||||
# 综合包网/NG接口开户 | 28/m | 3m | next,4/28 | @aabbcx888
|
||||
# 实名认证/过人脸🕵️♀️各种账号处理✅ | 30/m| next,6/30 | @nngzs
|
||||
# 海外服务器 高防CDN 解决移动屏蔽 | 19/m | next,4/19 | @YYCDNFW
|
||||
keyboard = [
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text="海外服务器 高防CDN 解决移动屏蔽", url='https://t.me/kltfuwuqi')
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text="👑 综合包网/NG接口开户", url='https://t.me/NG_Tony')
|
||||
|
||||
@@ -51,11 +51,15 @@ def send_msg(bot, tag='ad', trigger_time=300):
|
||||
# 信号只在一个周期内执行一次|end
|
||||
|
||||
# https://t.me/gjgzs2022 | 22/m | @GJ_gzs
|
||||
# https://zhaoziyuan.pw/ | web | 15/m | 2m | next,3/15 | @baleite
|
||||
# 腾云机场 |9/m
|
||||
# https://zhaoziyuan1.cc | web | 15/m | 2m | next,5/15 | @baleite
|
||||
# 综合包网/NG接口开户 | 28/m | 3m | next,4/28 | @aabbcx888
|
||||
# 实名认证/过人脸🕵️♀️各种账号处理✅ | 30/m| next,6/30 | @nngzs
|
||||
# 海外服务器 高防CDN 解决移动屏蔽 | 19/m | next,4/19 | @YYCDNFW
|
||||
keyboard = [
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text="海外服务器 高防CDN 解决移动屏蔽", url='https://t.me/kltfuwuqi')
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text="🚀 综合包网/NG接口开户", url='https://t.me/NG_Tony')
|
||||
|
||||
+2
-1
@@ -21,7 +21,7 @@ configparser==5.2.0
|
||||
python-engineio==4.3.2
|
||||
python-socketio>=4.2.0
|
||||
flask-socketio==5.2.0
|
||||
flask_sockets==0.2.1
|
||||
flask-sockets==0.2.1
|
||||
zmq==0.0.0
|
||||
paramiko>=2.8.0
|
||||
pymongo
|
||||
@@ -31,6 +31,7 @@ pillow
|
||||
Jinja2>=2.11.2
|
||||
PyMySQL==1.0.2
|
||||
whitenoise==5.3.0
|
||||
pyotp
|
||||
pytz
|
||||
pyTelegramBotAPI
|
||||
telebot
|
||||
+41
-15
@@ -187,8 +187,7 @@ def requestAfter(response):
|
||||
|
||||
def isLogined():
|
||||
if 'login' in session and 'username' in session and session['login'] == True:
|
||||
userInfo = mw.M('users').where(
|
||||
"id=?", (1,)).field('id,username,password').find()
|
||||
userInfo = mw.M('users').where("id=?", (1,)).field('id,username,password').find()
|
||||
# print(userInfo)
|
||||
if userInfo['username'] != session['username']:
|
||||
return False
|
||||
@@ -312,6 +311,34 @@ def checkLogin():
|
||||
return "false"
|
||||
|
||||
|
||||
@app.route("/verify_login", methods=['POST'])
|
||||
def verifyLogin():
|
||||
username = request.form.get('username', '').strip()
|
||||
password = request.form.get('password', '').strip()
|
||||
password = mw.md5(password)
|
||||
|
||||
userInfo = mw.M('users').where("id=?", (1,)).field('id,username,password').find()
|
||||
if userInfo['username'] != username or userInfo['password'] != password:
|
||||
return mw.returnJson(-1, "密码错误?")
|
||||
|
||||
auth = request.form.get('auth', '').strip()
|
||||
|
||||
import pyotp
|
||||
auth_file = 'data/auth_secret.pl'
|
||||
if os.path.exists(auth_file):
|
||||
content = mw.readFile(auth_file)
|
||||
sec = mw.deDoubleCrypt('mdserver-web', content)
|
||||
totp = pyotp.TOTP(sec)
|
||||
if totp.verify(auth):
|
||||
userInfo = mw.M('users').where("id=?", (1,)).field('id,username,password').find()
|
||||
session['login'] = True
|
||||
session['username'] = userInfo['username']
|
||||
session['overdue'] = int(time.time()) + 7 * 24 * 60 * 60
|
||||
return mw.returnJson(1, '二次验证成功!')
|
||||
|
||||
return mw.returnJson(-1, '二次验证失败!')
|
||||
|
||||
|
||||
@app.route("/do_login", methods=['POST'])
|
||||
def doLogin():
|
||||
login_cache_count = 5
|
||||
@@ -343,13 +370,8 @@ def doLogin():
|
||||
mw.writeLog('用户登录', code_msg)
|
||||
return mw.returnJson(False, code_msg)
|
||||
|
||||
userInfo = mw.M('users').where(
|
||||
"id=?", (1,)).field('id,username,password').find()
|
||||
|
||||
# print(userInfo)
|
||||
# print(password)
|
||||
userInfo = mw.M('users').where("id=?", (1,)).field('id,username,password').find()
|
||||
password = mw.md5(password)
|
||||
# print('md5-pass', password)
|
||||
|
||||
if userInfo['username'] != username or userInfo['password'] != password:
|
||||
msg = "<a style='color: red'>密码错误</a>,帐号:{1},密码:{2},登录IP:{3}", ((
|
||||
@@ -367,17 +389,23 @@ def doLogin():
|
||||
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.returnJson(False, mw.getInfo("用户名或密码错误,您还可以尝试[{1}]次!", (str(login_cache_count - login_cache_limit))))
|
||||
return mw.returnJson(-1, mw.getInfo("用户名或密码错误,您还可以尝试[{1}]次!", (str(login_cache_count - login_cache_limit))))
|
||||
|
||||
|
||||
|
||||
cache.delete('login_cache_limit')
|
||||
# 二次验证密钥
|
||||
auth_secret = 'data/auth_secret.pl'
|
||||
if os.path.exists(auth_secret):
|
||||
return mw.returnJson(2, '绑定二次验证了...')
|
||||
|
||||
session['login'] = True
|
||||
session['username'] = userInfo['username']
|
||||
session['overdue'] = int(time.time()) + 7 * 24 * 60 * 60
|
||||
# session['overdue'] = int(time.time()) + 7
|
||||
|
||||
# fix 跳转时,数据消失,可能是跨域问题
|
||||
# mw.writeFile('data/api_login.txt', userInfo['username'])
|
||||
return mw.returnJson(True, '登录成功,正在跳转...')
|
||||
return mw.returnJson(1, '登录成功,正在跳转...')
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
@@ -419,8 +447,7 @@ def login_temp_user(token):
|
||||
return '连续10次验证失败,禁止1小时'
|
||||
|
||||
stime = int(time.time())
|
||||
data = mw.M('temp_login').where('state=? and expire>?',
|
||||
(0, stime)).field('id,token,salt,expire,addtime').find()
|
||||
data = mw.M('temp_login').where('state=? and expire>?',(0, stime)).field('id,token,salt,expire,addtime').find()
|
||||
if not data:
|
||||
setErrorNum(skey)
|
||||
return '验证失败!'
|
||||
@@ -434,8 +461,7 @@ def login_temp_user(token):
|
||||
setErrorNum(skey)
|
||||
return '验证失败!'
|
||||
|
||||
userInfo = mw.M('users').where(
|
||||
"id=?", (1,)).field('id,username').find()
|
||||
userInfo = mw.M('users').where("id=?", (1,)).field('id,username').find()
|
||||
session['login'] = True
|
||||
session['username'] = userInfo['username']
|
||||
session['tmp_login'] = True
|
||||
|
||||
@@ -1002,7 +1002,7 @@ function setTempAccess(){
|
||||
shift: 0,
|
||||
type: 1,
|
||||
content: "<div class=\"login_view_table pd20\">\
|
||||
<button class=\"btn btn-success btn-sm create_temp_login\" >临时访问授权</button>\
|
||||
<button class=\"btn btn-success btn-sm create_temp_login\">临时访问授权</button>\
|
||||
<div class=\"divtable mt10\">\
|
||||
<table class=\"table table-hover\">\
|
||||
<thead>\
|
||||
@@ -1062,6 +1062,64 @@ function setTempAccess(){
|
||||
});
|
||||
}
|
||||
|
||||
//二次验证
|
||||
function setAuthBind(){
|
||||
$.post('/config/get_auth_secret', {}, function(rdata){
|
||||
console.log(rdata);
|
||||
var tip = layer.open({
|
||||
area: ['500px', '355px'],
|
||||
title: '二次验证设置',
|
||||
closeBtn:1,
|
||||
shift: 0,
|
||||
type: 1,
|
||||
content: '<div class="bt-form pd20">\
|
||||
<div class="line">\
|
||||
<span class="tname">绑定密钥</span>\
|
||||
<div class="info-r">\
|
||||
<input class="bt-input-text mr5" name="secret" type="text" style="width: 310px;" disabled>\
|
||||
<button class="btn btn-success btn-xs reset_secret" style="margin-left: -50px;">重置</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="line">\
|
||||
<span class="tname" style="width: 90px; overflow: initial; height: 20px; line-height: 20px;">二维码</span>\
|
||||
<div class="info-r"><div class="qrcode"></div></div>\
|
||||
</div>\
|
||||
<ul class="help-info-text c7">\
|
||||
</ul>\
|
||||
</div>',
|
||||
success:function(layero,index){
|
||||
|
||||
$('input[name="secret"]').val(rdata.data['secret']);
|
||||
$('.qrcode').qrcode({ text: rdata.data['url']});
|
||||
|
||||
$('.reset_secret').click(function(){
|
||||
layer.confirm('您确定要重置当前密钥吗?<br/><span style="color: red; ">重置密钥后,已关联密钥产品,将失效,请重新添加新密钥至产品。</span>',{title:'重置密钥',closeBtn:2,icon:13,cancel:function(){
|
||||
}}, function() {
|
||||
$.post('/config/get_auth_secret', {'reset':"1"},function(rdata){
|
||||
showMsg("接口密钥已生成,重置密钥后,已关联密钥产品,将失效,请重新添加新密钥至产品。", function(){
|
||||
$('input[name="secret"]').val(rdata.data['secret']);
|
||||
$('.qrcode').html('').qrcode({ text: rdata.data['url']});
|
||||
} ,{icon:1}, 2000);
|
||||
},'json');
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
function setAuthSecretApi(){
|
||||
var cfg_panel_auth = $('#cfg_panel_auth').prop("checked");
|
||||
$.post('/config/set_auth_secret', {'op_type':"2"},function(rdata){
|
||||
showMsg(rdata.msg, function(){
|
||||
if (rdata.data == 1){
|
||||
setAuthBind();
|
||||
}
|
||||
} ,{icon:rdata.status?1:2}, 1000);
|
||||
},'json');
|
||||
}
|
||||
|
||||
function setBasicAuthTip(callback){
|
||||
var tip = layer.open({
|
||||
area: ['500px', '385px'],
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -128,7 +128,7 @@
|
||||
|
||||
<p class="mtb15">
|
||||
<span class="set-tit text-right" title="API接口" style="float: left;">API接口</span>
|
||||
<input class="btswitch btswitch-ios" id="cfg_panel_api" type="checkbox" {{data['api_token']}}/>
|
||||
<input class="btswitch btswitch-ios" id="cfg_panel_api" type="checkbox" {{data['api_token']}}/>
|
||||
<label class="btswitch-btn ml5" for="cfg_panel_api" style="float: left;margin-top:4px;" onclick="setPanelApi()"></label>
|
||||
<button ype="button" class="btn btn-default btn-xs panel_api_btn" style="vertical-align: middle; margin-left: 10px" onclick="showPanelApi();">API接口配置</button>
|
||||
<span class="set-info c7">提供面板API接口访问的支持</span>
|
||||
@@ -146,6 +146,14 @@
|
||||
<button type="button" class="btn btn-success btn-sm ml5" onclick="setTempAccess()">临时访问授权管理</button>
|
||||
<span class="set-info c7">为非管理员临时提供面板访问权限</span>
|
||||
</p>
|
||||
|
||||
<p class="mtb15">
|
||||
<span class="set-tit text-right" title="二次验证" style="float: left;">二次验证</span>
|
||||
<input class="btswitch btswitch-ios" id="cfg_panel_auth" type="checkbox" {{data['auth_secret']}}/>
|
||||
<label class="btswitch-btn ml5" for="cfg_panel_auth" style="float: left;margin-top:4px;" onclick="setAuthSecretApi()"></label>
|
||||
<button type="button" class="btn btn-default btn-xs panel_api_btn" style="vertical-align: middle; margin-left: 10px" onclick="setAuthBind();">绑定设置</button>
|
||||
<span class="set-info c7">二次验证,加强安全登录</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
|
||||
|
||||
<script src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
|
||||
<script src="/static/js/jquery-qrcode-0.18.0.min.js?v={{config.version}}"></script>
|
||||
<script src="/static/js/xm-select.js"></script>
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<link rel="icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
<title>{{data['title']}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/layer/skin/default/layer.css?v={{config.version}}">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/site.css?v={{config.version}}">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/login.css?v={{config.version}}">
|
||||
<style type="text/css">
|
||||
@@ -29,6 +30,7 @@
|
||||
.bg_img.pc:hover{
|
||||
background-position: -60px -60px;
|
||||
}
|
||||
|
||||
.qrCode{
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
@@ -70,9 +72,11 @@
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.list_scan .weChatSamll img{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.list_scan .weChatSamll em{
|
||||
position: absolute;
|
||||
border: 7px solid #ececec;
|
||||
@@ -83,6 +87,7 @@
|
||||
bottom: -14px;
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.tips{
|
||||
width: 115px;
|
||||
position: absolute;
|
||||
@@ -94,6 +99,7 @@
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.tips em{
|
||||
position: absolute;
|
||||
border: 6px solid #dff0d8;
|
||||
@@ -104,6 +110,7 @@
|
||||
top: 8px;
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.tips img{
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
@@ -115,6 +122,10 @@
|
||||
margin-top: 15px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.layui-layer .layui-layer-btn{
|
||||
width: 235px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -123,11 +134,14 @@
|
||||
<div class="account">
|
||||
<form class="loginform" method="post" action="/login" onsubmit="return false;">
|
||||
<div class="rlogo">{{data['title']}}</div>
|
||||
<div class="line"><input class="inputtxt" value="" name="username" datatype="*" nullmsg="请填写账户" errormsg="请填写账户" placeholder="账户" type="text"><div class="Validform_checktip"></div></div>
|
||||
<div class="line">
|
||||
<input class="inputtxt" value="" name="username" datatype="*" nullmsg="请填写账户" errormsg="请填写账户" placeholder="账户" type="text">
|
||||
<div class="Validform_checktip"></div>
|
||||
</div>
|
||||
<div class="line"><input class="inputtxt" name="password" value="" datatype="*" nullmsg="请填写密码" errormsg="请填写密码" placeholder="密码" type="password">
|
||||
<div class="Validform_checktip"></div>
|
||||
</div>
|
||||
<div style="color: red;position: relative;top: -14px;" id="errorStr"></div>
|
||||
<div style="color: red;position: relative;top: -14px;" id="error"></div>
|
||||
<div class="line yzm" style="top: -5px;{% if not session['code'] %}display:none;{% endif %}">
|
||||
<input type="text" class="inputtxt" name="code" nullmsg="请填写4位验证码" errormsg="验证码" datatype="*" placeholder="验证码">
|
||||
<div class="Validform_checktip"></div>
|
||||
@@ -150,6 +164,7 @@
|
||||
$(function(){
|
||||
wreset();
|
||||
})
|
||||
|
||||
window.onresize=function(){
|
||||
wreset();
|
||||
}
|
||||
@@ -188,19 +203,21 @@ $('#login-button').click(function(){
|
||||
}
|
||||
|
||||
var data = 'username='+username+'&password='+password+'&code='+code;
|
||||
var loadT = layer.msg("正在登录中",{icon:16,time:0,shade: [0.3, '#000']});
|
||||
var loadT = layer.msg("正在登录中...",{icon:16,time:0,shade: [0.3, '#000']});
|
||||
$.post('/do_login',data,function(rdata){
|
||||
console.log(rdata);
|
||||
layer.close(loadT);
|
||||
if(!rdata.status){
|
||||
if(status < 0){
|
||||
if(username == 'admin' && rdata.msg.indexOf('用户名') != -1){
|
||||
rdata.msg += ', <br>获取默认用户和密码命令: mw default';
|
||||
}
|
||||
$("#errorStr").html(rdata.msg);
|
||||
$("#error").html(rdata.msg);
|
||||
$("input[name='password']").val('');
|
||||
num = rdata.msg.substring(rdata.msg.indexOf('[')+1,rdata.msg.indexOf(']'))
|
||||
if(num < 5){
|
||||
$('#mw_yzm').html('<img width="100" height="40" class="passcode" onClick="this.src=this.src.split(\'?\')[0] + \'?\'+new Date().getTime()" src="/code" style="border: 1px solid #ccc; float: right;" title="" >');
|
||||
$(".login").css("height","332px");
|
||||
var code_html = '<img width="100" height="40" class="passcode" onClick="this.src=this.src.split(\'?\')[0] + \'?\'+new Date().getTime()" src="/code" style="border: 1px solid #ccc; float: right;">';
|
||||
$('#mw_yzm').html(code_html);
|
||||
// $(".login").css("height","332px");
|
||||
$("input[name='code']").val('');
|
||||
$(".passcode").click();
|
||||
}
|
||||
@@ -209,6 +226,26 @@ $('#login-button').click(function(){
|
||||
layer.msg(rdata.msg,{icon:2,time:5000});
|
||||
return;
|
||||
}
|
||||
|
||||
if (rdata.status == 2){
|
||||
layer.prompt({
|
||||
formType: 3,
|
||||
value: '',
|
||||
title: '二次验证',
|
||||
}, function(value, index, elem){
|
||||
$.post('/verify_login',{'auth':value,'username':username,'password':password},function(vdata){
|
||||
if (vdata.status < 0){
|
||||
layer.msg(vdata.msg,{icon:2,time:5000});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.close(index);
|
||||
window.location.href = '/';
|
||||
},'json');
|
||||
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg(rdata.msg,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
window.location.href = '/';
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ fi
|
||||
# ping -c 1 github.com > /dev/null 2>&1
|
||||
# if [ "$?" != "0" ];then
|
||||
# LOCAL_ADDR=cn
|
||||
# HTTP_PREFIX="https://ghproxy.com/"
|
||||
# HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
# fi
|
||||
|
||||
HTTP_PREFIX="https://"
|
||||
@@ -72,7 +72,7 @@ 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://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
echo "local:${LOCAL_ADDR}"
|
||||
|
||||
@@ -67,7 +67,7 @@ fi
|
||||
# ping -c 1 github.com > /dev/null 2>&1
|
||||
# if [ "$?" != "0" ];then
|
||||
# LOCAL_ADDR=cn
|
||||
# HTTP_PREFIX="https://ghproxy.com/"
|
||||
# HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
# fi
|
||||
|
||||
HTTP_PREFIX="https://"
|
||||
@@ -75,7 +75,7 @@ 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://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
echo "local:${LOCAL_ADDR}"
|
||||
|
||||
+2
-2
@@ -62,14 +62,14 @@ fi
|
||||
# ping -c 1 github.com > /dev/null 2>&1
|
||||
# if [ "$?" != "0" ];then
|
||||
# LOCAL_ADDR=cn
|
||||
# HTTP_PREFIX="https://ghproxy.com/"
|
||||
# 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://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
PIPSRC="https://pypi.python.org/simple"
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ 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://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
echo "local:${LOCAL_ADDR}"
|
||||
|
||||
|
||||
@@ -61,14 +61,14 @@ fi
|
||||
# ping -c 1 github.com > /dev/null 2>&1
|
||||
# if [ "$?" != "0" ];then
|
||||
# LOCAL_ADDR=cn
|
||||
# HTTP_PREFIX="https://ghproxy.com/"
|
||||
# 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://ghproxy.com/"
|
||||
HTTP_PREFIX="https://mirror.ghproxy.com/"
|
||||
fi
|
||||
|
||||
echo "local:${LOCAL_ADDR}"
|
||||
|
||||
@@ -61,6 +61,7 @@ def mwcli(mw_input=0):
|
||||
print("(22) 开启IPV6支持")
|
||||
print("(23) 关闭IPV6支持")
|
||||
print("(24) 开启防火墙SSH端口")
|
||||
print("(25) 关闭二次验证")
|
||||
print("(100) 开启PHP52显示")
|
||||
print("(101) 关闭PHP52显示")
|
||||
print("(200) 切换Linux系统软件源")
|
||||
@@ -74,7 +75,7 @@ def mwcli(mw_input=0):
|
||||
except:
|
||||
mw_input = 0
|
||||
|
||||
nums = [1, 2, 3, 4, 5, 10, 11, 12, 13, 20, 21, 22, 23, 24, 100, 101, 200, 201]
|
||||
nums = [1, 2, 3, 4, 5, 10, 11, 12, 13, 20, 21, 22, 23, 24, 25, 100, 101, 200, 201]
|
||||
if not mw_input in nums:
|
||||
print(raw_tip)
|
||||
print("已取消!")
|
||||
@@ -145,6 +146,13 @@ def mwcli(mw_input=0):
|
||||
elif mw_input == 24:
|
||||
open_ssh_port()
|
||||
print("|-已开启!")
|
||||
elif mw_input == 25:
|
||||
auth_secret = 'data/auth_secret.pl'
|
||||
if os.path.exists(auth_secret):
|
||||
os.remove(auth_secret)
|
||||
print("|-关闭二次验证成功!")
|
||||
else:
|
||||
print("|-二次验证已关闭!")
|
||||
elif mw_input == 100:
|
||||
php_conf = 'plugins/php/info.json'
|
||||
if os.path.exists(php_conf):
|
||||
@@ -169,7 +177,7 @@ def mwcli(mw_input=0):
|
||||
|
||||
def open_ssh_port():
|
||||
import firewall_api
|
||||
find_ssh_port_cmd = "cat /etc/ssh/sshd_config | grep '^Port \d*' | tail -1"
|
||||
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 == '':
|
||||
|
||||
Reference in New Issue
Block a user