From bcfdd2216138268a7cd54a86bebc28ed9a1e5f15 Mon Sep 17 00:00:00 2001 From: Mr Chen Date: Wed, 6 Nov 2024 02:08:35 +0800 Subject: [PATCH] update --- new_cli.sh | 8 ++- panel_tools.py | 7 +- web/admin/dashboard/login.py | 46 ++++++++++--- web/admin/setting/secondary_verifiy.py | 44 +++++++++---- web/admin/setup/option.py | 3 + web/admin/site/__init__.py | 45 ++++++++++++- web/core/db.py | 2 + web/core/mw.py | 13 ++++ web/static/app/config.js | 4 +- web/templates/default/login.html | 2 +- web/templates/default/setting.html | 6 +- web/thisdb/user.py | 15 +++-- web/utils/config.py | 4 ++ web/utils/site.py | 89 +++++++++++++++----------- web/utils/system/main.py | 9 +-- 15 files changed, 216 insertions(+), 81 deletions(-) diff --git a/new_cli.sh b/new_cli.sh index 4d6a96388..77c21ddf6 100755 --- a/new_cli.sh +++ b/new_cli.sh @@ -51,7 +51,7 @@ mw_start_debug(){ fi python3 panel_task.py >> $DIR/logs/panel_task.log 2>&1 & - port=7200 + port=7200 if [ -f /www/server/mdserver-web/data/port.pl ];then port=$(cat /www/server/mdserver-web/data/port.pl) fi @@ -64,7 +64,11 @@ mw_start_debug(){ } mw_start_panel(){ - cd ${DIR}/web && gunicorn -b :7200 -w 1 app:app + port=7200 + if [ -f ${DIR}/data/port.pl ];then + port=$(cat ${DIR}/data/port.pl) + fi + cd ${DIR}/web && gunicorn -b :${port} -w 1 app:app } mw_start_bgtask(){ diff --git a/panel_tools.py b/panel_tools.py index 45af39793..cd2e3734f 100755 --- a/panel_tools.py +++ b/panel_tools.py @@ -158,9 +158,10 @@ def mwcli(mw_input=0): open_ssh_port() print("|-已开启!") elif mw_input == 26: - auth_secret = 'data/auth_secret.pl' - if os.path.exists(auth_secret): - os.remove(auth_secret) + two_step_verification = thisdb.getOptionByJson('two_step_verification', default={'open':False}) + if two_step_verification['open']: + two_step_verification['open'] = False + thisdb.setOption('two_step_verification', json.dumps(two_step_verification)) print("|-关闭二次验证成功!") else: print("|-二次验证已关闭!") diff --git a/web/admin/dashboard/login.py b/web/admin/dashboard/login.py index 7f1abe8eb..746560ce2 100644 --- a/web/admin/dashboard/login.py +++ b/web/admin/dashboard/login.py @@ -20,8 +20,6 @@ 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 import thisdb @@ -63,7 +61,7 @@ def login_temp_user(token): stime = int(time.time()) - tmp_data = model.getTempLoginByToken(token) + tmp_data = thisdb.getTempLoginByToken(token) if not tmp_data: setErrorNum(skey) return '验证失败!' @@ -73,12 +71,10 @@ def login_temp_user(token): return "过期" user_data = thisdb.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() + mw.M('temp_login').where('id=?',(tmp_data['id'],)).update({"login_time": stime, 'state': 1, 'login_addr': login_addr}) session['login'] = True session['username'] = user_data['name'] @@ -105,11 +101,11 @@ def login(): session['login'] = False session['overdue'] = 0 - db_path = model.getOption('admin_path') + db_path = thisdb.getOption('admin_path') if db_path == '': return render_template('default/login.html') else: - unauthorized_status = model.getOption('unauthorized_status') + unauthorized_status = thisdb.getOption('unauthorized_status') if unauthorized_status == '0': return render_template('default/path.html') return Response(status=int(unauthorized_status)) @@ -134,6 +130,32 @@ def check_login(): return mw.returnData(True,'已登录') return mw.returnData(False,'未登录') +@blueprint.route("/verify_login", methods=['POST']) +def verifyLogin(): + import pyotp + + username = request.form.get('username', '').strip() + password = request.form.get('password', '').strip() + password = mw.md5(password) + + info = thisdb.getUserByRoot() + if info['name'] != username or info['password'] != password: + return mw.returnJson(-1, "密码错误?") + + auth = request.form.get('auth', '').strip() + two_step_verification = thisdb.getOptionByJson('two_step_verification', default={'open':False}) + if two_step_verification['open']: + sec = mw.deDoubleCrypt('mdserver-web', two_step_verification['secret']) + totp = pyotp.TOTP(sec) + if totp.verify(auth): + session['login'] = True + session['username'] = info['name'] + session['overdue'] = int(time.time()) + 7 * 24 * 60 * 60 + + thisdb.updateUserLoginTime() + return mw.returnData(1, '二次验证成功!') + return mw.returnData(-1, '二次验证失败!') + # 执行登录操作 @blueprint.route('/do_login', endpoint='do_login', methods=['POST']) def do_login(): @@ -181,9 +203,15 @@ def do_login(): mw.writeLog('用户登录', mw.getInfo(msg)) return mw.returnData(-1, mw.getInfo("用户名或密码错误,您还可以尝试[{1}]次!", (str(login_cache_count - login_cache_limit)))) + cache.delete('login_cache_limit') + # 二步验证密钥 + two_step_verification = thisdb.getOptionByJson('two_step_verification', default={'open':False}) + if two_step_verification['open']: + return mw.returnData(2, '需要两步验证!') session['login'] = True session['username'] = info['name'] session['overdue'] = int(time.time()) + 7 * 24 * 60 * 60 - + + thisdb.updateUserLoginTime() return mw.returnJson(1, '登录成功,正在跳转...') diff --git a/web/admin/setting/secondary_verifiy.py b/web/admin/setting/secondary_verifiy.py index 562383706..2e170bf56 100644 --- a/web/admin/setting/secondary_verifiy.py +++ b/web/admin/setting/secondary_verifiy.py @@ -25,30 +25,48 @@ import core.mw as mw import utils.config as utils_config from .setting import blueprint +import thisdb - +# 获取二次验证信息 @blueprint.route('/get_auth_secret', endpoint='get_auth_secret', methods=['POST']) @panel_login_required def get_auth_secret(): - reset = request.form.get('reset', '') - __file = mw.getCommonFile() - import pyotp - auth = __file['auth_secret'] + + reset = request.form.get('reset', '') tag = 'mdserver-web' - if os.path.exists(auth) and reset != '1': - content = mw.readFile(auth) - sec = mw.deDoubleCrypt(tag,content) + two_step_verification = thisdb.getOptionByJson('two_step_verification', default={'open':False}) + + if 'secret' in two_step_verification and reset != '1': + secret = mw.deDoubleCrypt(tag, two_step_verification['secret']) else: - sec = pyotp.random_base32() - crypt_data = mw.enDoubleCrypt(tag, sec) - mw.writeFile(auth, crypt_data) + secret = pyotp.random_base32() + crypt_data = mw.enDoubleCrypt(tag, secret) + two_step_verification['secret'] = crypt_data + thisdb.setOption('two_step_verification', json.dumps(two_step_verification)) ip = mw.getHostAddr() - url = pyotp.totp.TOTP(sec).provisioning_uri(name=ip, issuer_name=tag) + url = pyotp.totp.TOTP(secret).provisioning_uri(name=ip, issuer_name=tag) rdata = {} - rdata['secret'] = sec + rdata['secret'] = secret rdata['url'] = url return mw.returnData(True, '设置成功!', rdata) + + +# 设置二次验证,加强安全登录 +@blueprint.route('/set_auth_secret', endpoint='set_auth_secret', methods=['POST']) +@panel_login_required +def set_auth_secret(): + two_step_verification = thisdb.getOptionByJson('two_step_verification', default={'open':False}) + if two_step_verification['open']: + two_step_verification['open'] = False + thisdb.setOption('two_step_verification', json.dumps(two_step_verification)) + return mw.returnData(True, '关闭成功!', 0) + else: + two_step_verification['open'] = True + thisdb.setOption('two_step_verification', json.dumps(two_step_verification)) + return mw.returnData(True, '开启成功!', 1) + + \ No newline at end of file diff --git a/web/admin/setup/option.py b/web/admin/setup/option.py index da08bedd0..9a433961e 100644 --- a/web/admin/setup/option.py +++ b/web/admin/setup/option.py @@ -32,6 +32,9 @@ def init_option(): # basic auth 配置 thisdb.setOption('basic_auth', json.dumps({'open':False})) + # 二步验证|默认关闭 + thisdb.setOption('two_step_verification', json.dumps({'open':False})) + # 开启后台任务 # model.setOption('run_bg_task', 'close') diff --git a/web/admin/site/__init__.py b/web/admin/site/__init__.py index 6036672f2..3bdf5979d 100644 --- a/web/admin/site/__init__.py +++ b/web/admin/site/__init__.py @@ -26,7 +26,7 @@ blueprint = Blueprint('site', __name__, url_prefix='/site', template_folder='../ def index(): return render_template('site.html') -# 插件列表 +# 站点列表 @blueprint.route('/list', endpoint='list', methods=['GET','POST']) @panel_login_required def list(): @@ -42,11 +42,54 @@ def list(): data['page'] = mw.getPage({'count':info['count'],'tojs':'getWeb','p':p, 'row':limit}) return data +#添加站点 +@blueprint.route('/add', endpoint='add',methods=['POST']) +@panel_login_required +def add(): + webname = request.form.get('webinfo', '') + ps = request.form.get('ps', '') + path = request.form.get('path', '') + version = request.form.get('version', '') + port = request.form.get('port', '') + return [] + +# 获取站点类型 @blueprint.route('/get_site_types', endpoint='get_site_types',methods=['POST']) @panel_login_required def get_site_types(): return [] +# 获取站点根目录 +@blueprint.route('/get_root_dir', endpoint='get_root_dir',methods=['POST']) +@panel_login_required +def get_root_dir(): + data = {} + data['dir'] = mw.getWwwDir() + return data + +# 检查OpenResty安装/启动状态 +@blueprint.route('/check_web_status', endpoint='check_web_status',methods=['POST']) +@panel_login_required +def check_web_status(): + ''' + 创建站点检查web服务 + ''' + if not mw.isInstalledWeb(): + return mw.returnJson(False, '请安装并启动OpenResty服务!') + + # 这个快点 + pid = mw.getServerDir() + '/openresty/nginx/logs/nginx.pid' + if not os.path.exists(pid): + return mw.returnData(False, '请启动OpenResty服务!') + return mw.returnData(True, 'OK') + +# 获取PHP版本 +@blueprint.route('/get_php_version', endpoint='get_php_version',methods=['POST']) +@panel_login_required +def get_php_version(): + return site.getPhpVersion() + + @blueprint.route('/get_cli_php_version', endpoint='get_cli_php_version',methods=['POST']) @panel_login_required def get_cli_php_version(): diff --git a/web/core/db.py b/web/core/db.py index 27b97ae9e..6550f77c8 100755 --- a/web/core/db.py +++ b/web/core/db.py @@ -39,6 +39,8 @@ class Sql(): __OPT_FIELD = "*" # field条件 __OPT_PARAM = () # where值 + __debug = False + def __init__(self): self.__DB_FILE = getPanelDir()+'/data/panel.db' diff --git a/web/core/mw.py b/web/core/mw.py index 8ec077999..603456371 100644 --- a/web/core/mw.py +++ b/web/core/mw.py @@ -909,6 +909,19 @@ def panelCmd(method): # ------------------------------ panel end ----------------------------- # ------------------------------ openresty start ----------------------------- + +def checkWebConfig(): + op_dir = getServerDir() + '/openresty/nginx' + # "ulimit -n 10240 && " + + cmd = op_dir + "/sbin/nginx -t -c " + op_dir + "/conf/nginx.conf" + result = execShell(cmd) + searchStr = 'test is successful' + if result[1].find(searchStr) == -1: + msg = getInfo('配置文件错误: {1}', (result[1],)) + writeLog("软件管理", msg) + return result[1] + return True + def restartWeb(): return opWeb("reload") diff --git a/web/static/app/config.js b/web/static/app/config.js index 066a16dbe..542437619 100755 --- a/web/static/app/config.js +++ b/web/static/app/config.js @@ -1236,13 +1236,13 @@ function setTempAccess(){ }); } -//二次验证 +//二步验证 function setAuthBind(){ $.post('/setting/get_auth_secret', {}, function(rdata){ console.log(rdata); var tip = layer.open({ area: ['500px', '355px'], - title: '二次验证设置', + title: '二步验证设置', closeBtn:1, shift: 0, type: 1, diff --git a/web/templates/default/login.html b/web/templates/default/login.html index fb471f309..c361e6c3c 100755 --- a/web/templates/default/login.html +++ b/web/templates/default/login.html @@ -231,7 +231,7 @@ $('#login-button').click(function(){ layer.prompt({ formType: 3, value: '', - title: '二次验证', + title: '二步验证', }, function(value, index, elem){ $.post('/verify_login',{'auth':value,'username':username,'password':password},function(vdata){ if (vdata.status < 0){ diff --git a/web/templates/default/setting.html b/web/templates/default/setting.html index c001f7375..588d1eeb0 100755 --- a/web/templates/default/setting.html +++ b/web/templates/default/setting.html @@ -149,11 +149,11 @@

- 二次验证 - + 二步验证 + - 二次验证,加强安全登录 + 二步验证,加强安全登录

diff --git a/web/thisdb/user.py b/web/thisdb/user.py index 519a3476c..ac94b222b 100644 --- a/web/thisdb/user.py +++ b/web/thisdb/user.py @@ -10,9 +10,11 @@ import core.mw as mw +__field = 'id,name,password,login_ip,login_time,phone,email,add_time,update_time' + # 初始化用户信息 def initAdminUser(): - data = mw.M('users').field('id').where('id=?', (1,)).find() + data = mw.M('users').field(__field).where('id=?', (1,)).find() if data is None: name = mw.getRandomString(8).lower() password = mw.getRandomString(8).lower() @@ -39,8 +41,7 @@ def getUserByName(name, ''' 获取用户信息通过用户名 ''' - users_field = 'id,name,password,login_ip,login_time,phone,email,add_time,update_time' - data = mw.M('users').field(users_field).where('name=?', (name,)).find() + data = mw.M('users').field(__field).where('name=?', (name,)).find() if data is None: return None row = {} @@ -60,8 +61,7 @@ def getUserById(id, ''' 获取用户信息通过用户名 ''' - users_field = 'id,name,password,login_ip,login_time,phone,email,add_time,update_time' - data = mw.M('users').field(users_field).where('id=?', (1,)).find() + data = mw.M('users').field(__field).where('id=?', (1,)).find() if data is None: return None row = {} @@ -83,6 +83,11 @@ def getUserByRoot() -> None: ''' return getUserById(1) +def updateUserLoginTime(): + now_time = mw.formatDate() + mw.M('users').field(__field).where('id=?', (1,)).update({'login_time',now_time}) + return True + def setUserByRoot( name: str | None = None, password: str | None = None, diff --git a/web/utils/config.py b/web/utils/config.py index 878dc74d3..89ffabb85 100644 --- a/web/utils/config.py +++ b/web/utils/config.py @@ -62,10 +62,14 @@ def getGlobalVar(): else: data['ipv6'] = '' + # 获取ROOT用户名 + data['username'] = mw.M('users').where("id=?", (1,)).getField('name') + # 获取未认证状态信息 unauthorized_status = thisdb.getOption('unauthorized_status', default='0') data['unauthorized_status'] = getUnauthStatus(code=unauthorized_status) data['basic_auth'] = thisdb.getOptionByJson('basic_auth', default={'open':False}) + data['two_step_verification'] = thisdb.getOptionByJson('two_step_verification', default={'open':False}) # 服务器时间 sformat = 'date +"%Y-%m-%d %H:%M:%S %Z %z"' diff --git a/web/utils/site.py b/web/utils/site.py index a9a5b0c24..0d76ec0ff 100644 --- a/web/utils/site.py +++ b/web/utils/site.py @@ -18,43 +18,56 @@ from admin import model import core.mw as mw -def getPhpVersion(): - phpVersions = ('00', '52', '53', '54', '55', - '56', '70', '71', '72', '73', - '74', '80', '81', '82', '83', - '84') - data = [] - for val in phpVersions: - tmp = {} - if val == '00': - tmp['version'] = '00' - tmp['name'] = '纯静态' - data.append(tmp) - # 标准判断 - checkPath = mw.getServerDir() + '/php/' + val + '/bin/php' - if os.path.exists(checkPath): - tmp['version'] = val - tmp['name'] = 'PHP-' + val - data.append(tmp) +class sites(object): + # lock + _instance_lock = threading.Lock() + + @classmethod + def instance(cls, *args, **kwargs): + if not hasattr(sites, "_instance"): + with sites._instance_lock: + if not hasattr(sites, "_instance"): + sites._instance = sites(*args, **kwargs) + return sites._instance + + + def getPhpVersion(self): + phpVersions = ('00', '52', '53', '54', '55', + '56', '70', '71', '72', '73', + '74', '80', '81', '82', '83', + '84') + data = [] + for val in phpVersions: + tmp = {} + if val == '00': + tmp['version'] = '00' + tmp['name'] = '纯静态' + data.append(tmp) - # 其他PHP安装类型 - conf_dir = mw.getServerDir() + "/web_conf/php/conf" - conf_list = os.listdir(conf_dir) - l = len(conf_list) - rep = r"enable-php-(.*?)\.conf" - for name in conf_list: - tmp = {} - try: - matchVer = re.search(rep, name).groups()[0] - except Exception as e: - continue - - if matchVer in phpVersions: - continue - - tmp['version'] = matchVer - tmp['name'] = 'PHP-' + matchVer - data.append(tmp) - - return data \ No newline at end of file + # 标准判断 + checkPath = mw.getServerDir() + '/php/' + val + '/bin/php' + if os.path.exists(checkPath): + tmp['version'] = val + tmp['name'] = 'PHP-' + val + data.append(tmp) + + # 其他PHP安装类型 + conf_dir = mw.getServerDir() + "/web_conf/php/conf" + conf_list = os.listdir(conf_dir) + l = len(conf_list) + rep = r"enable-php-(.*?)\.conf" + for name in conf_list: + tmp = {} + try: + matchVer = re.search(rep, name).groups()[0] + except Exception as e: + continue + + if matchVer in phpVersions: + continue + + tmp['version'] = matchVer + tmp['name'] = 'PHP-' + matchVer + data.append(tmp) + return data \ No newline at end of file diff --git a/web/utils/system/main.py b/web/utils/system/main.py index f2a29203b..8ace24d77 100644 --- a/web/utils/system/main.py +++ b/web/utils/system/main.py @@ -105,12 +105,13 @@ def getSystemVersion(): def getBootTime(): # 取系统启动时间 - uptime = mw.readFile('/proc/uptime') - if uptime == False: + if os.path.exists('/proc/uptime'): + uptime = mw.readFile('/proc/uptime') + run_time = uptime.split()[0] + else: start_time = psutil.boot_time() run_time = time.time() - start_time - else: - run_time = uptime.split()[0] + tStr = float(run_time) min = tStr / 60 hours = min / 60