From 11f42d5d2c845f47a8617b137053bc7f5bc5581a Mon Sep 17 00:00:00 2001 From: Mr Chen Date: Fri, 1 Nov 2024 01:22:56 +0800 Subject: [PATCH] update --- web/admin/dashboard/__init__.py | 70 ++++++++++++++++++++++++++ web/admin/firewall/__init__.py | 14 +++++- web/admin/model/__init__.py | 4 +- web/admin/model/temp_login.py | 44 ++++++++++++++++ web/admin/model/user.py | 30 +++++++++++ web/admin/setting/__init__.py | 3 ++ web/admin/setting/main.py | 6 +-- web/admin/setting/secondary_verifiy.py | 54 ++++++++++++++++++++ web/admin/setting/temp_login.py | 62 ++++++++++++++++++++--- web/admin/setting/timezone.py | 60 ++++++++++++++++++++++ web/admin/system/__init__.py | 1 + web/core/mw.py | 37 ++++++++++++++ web/static/app/config.js | 7 +-- web/utils/firewall.py | 19 ++++++- web/utils/mwplugin.py | 8 +-- 15 files changed, 393 insertions(+), 26 deletions(-) create mode 100644 web/admin/model/temp_login.py create mode 100644 web/admin/setting/secondary_verifiy.py create mode 100644 web/admin/setting/timezone.py diff --git a/web/admin/dashboard/__init__.py b/web/admin/dashboard/__init__.py index a31a3dc33..0bf9fdee3 100644 --- a/web/admin/dashboard/__init__.py +++ b/web/admin/dashboard/__init__.py @@ -13,6 +13,7 @@ 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 @@ -20,6 +21,8 @@ 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 @@ -77,9 +80,76 @@ def admin_safe_path(path): # 定义登录入口相关方法 # --------------------------------------------------------------------------------- +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() diff --git a/web/admin/firewall/__init__.py b/web/admin/firewall/__init__.py index c8dbf3728..182390ce4 100644 --- a/web/admin/firewall/__init__.py +++ b/web/admin/firewall/__init__.py @@ -50,7 +50,7 @@ def get_list(): data = {} data['data'] = rows - data['page'] = mw.getPage({'count':count,'tojs':'getLogs','p':p}) + data['page'] = mw.getPage({'count':count,'tojs':'getLogs','p':p,'row':limit}) return data # 获取站点日志目录 @@ -60,7 +60,7 @@ 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(): @@ -68,6 +68,16 @@ def get_ssh_info(): 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() + + + + diff --git a/web/admin/model/__init__.py b/web/admin/model/__init__.py index faed1ea66..45762ecbd 100644 --- a/web/admin/model/__init__.py +++ b/web/admin/model/__init__.py @@ -21,5 +21,7 @@ from .task import addTask from .task import getTaskCount,getTaskUnexecutedCount,getTaskList,getTaskFirstByRun from .task import setTaskStatus,setTaskData -from .user import getUserByName,isLoginCheck +from .user import getUserByName,getUserById,isLoginCheck + +from .temp_login import getTempLoginByToken,clearTempLogin diff --git a/web/admin/model/temp_login.py b/web/admin/model/temp_login.py new file mode 100644 index 000000000..ac60f45c4 --- /dev/null +++ b/web/admin/model/temp_login.py @@ -0,0 +1,44 @@ +# coding:utf-8 + +# --------------------------------------------------------------------------------- +# MW-Linux面板 +# --------------------------------------------------------------------------------- +# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved. +# --------------------------------------------------------------------------------- +# Author: midoks +# --------------------------------------------------------------------------------- + +import time + +from admin.model import db, TempLogin + +import core.mw as mw + +def getTempLoginByToken(token, +) -> None: + ''' + 获取用户信息通过用户名 + ''' + item = TempLogin.query.filter(TempLogin.token==token).first() + if item is None: + return None + row = {} + row['id'] = item.id + row['token'] = item.token + row['salt'] = item.salt + row['state'] = item.state + row['login_time'] = item.login_time + row['login_addr'] = item.login_addr + row['logout_time'] = item.logout_time + row['expire'] = item.expire + row['add_time'] = item.add_time + return row + +def clearTempLogin()->bool: + ''' + 清空过期数据 + ''' + now_time = int(time.time()) + TempLogin.query.filter(TempLogin.expire bool: if info['password'] == mw.md5(password): return True return False + + +def getUserById(id, +) -> None: + ''' + 获取用户信息通过用户名 + ''' + item = Users.query.filter(Users.id==id).first() + if item is None: + return None + row = {} + row['id'] = item.id + row['name'] = item.name + row['password'] = item.password + row['login_ip'] = item.login_ip + row['login_time'] = item.login_time + row['phone'] = item.phone + row['email'] = item.email + row['add_time'] = item.add_time + row['update_time'] = item.update_time + return row + +def isLoginCheck(username, password) -> bool: + info = getUserByName(data['username']) + if info is None: + return False + + if info['password'] == mw.md5(password): + return True + return False diff --git a/web/admin/setting/__init__.py b/web/admin/setting/__init__.py index 25d4d3a78..d94faf268 100644 --- a/web/admin/setting/__init__.py +++ b/web/admin/setting/__init__.py @@ -10,6 +10,9 @@ from .main import * from .temp_login import * +from .timezone import * +from .secondary_verifiy import * + diff --git a/web/admin/setting/main.py b/web/admin/setting/main.py index 4b53d8604..0e3b1a26b 100644 --- a/web/admin/setting/main.py +++ b/web/admin/setting/main.py @@ -142,7 +142,7 @@ def set_basic_auth(): return mw.returnData(True, '设置成功!') -# 默认站点目录 +# 设置站点状态 @blueprint.route('/set_status_code', endpoint='set_status_code', methods=['POST']) @panel_login_required def set_status_code(): @@ -159,9 +159,7 @@ def set_status_code(): model.setOption('unauthorized_status', str(status_code)) mw.writeLog('面板设置', '将未授权响应状态码设置为:{0}:{1}'.format(status_code,info['text'])) return mw.returnData(True, '设置成功!') - - - + \ No newline at end of file diff --git a/web/admin/setting/secondary_verifiy.py b/web/admin/setting/secondary_verifiy.py new file mode 100644 index 000000000..466eb948b --- /dev/null +++ b/web/admin/setting/secondary_verifiy.py @@ -0,0 +1,54 @@ +# coding:utf-8 + +# --------------------------------------------------------------------------------- +# MW-Linux面板 +# --------------------------------------------------------------------------------- +# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved. +# --------------------------------------------------------------------------------- +# Author: midoks +# --------------------------------------------------------------------------------- + +import re +import json +import os +import time + +from flask import Blueprint, render_template +from flask import request + +from admin import model +from admin import session +from admin.model import db,TempLogin +from admin.user_login_check import panel_login_required + +import core.mw as mw +import utils.config as utils_config + +from .main import blueprint + + +@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'] + 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=tag) + + rdata = {} + rdata['secret'] = sec + rdata['url'] = url + return mw.returnData(True, '设置成功!', rdata) + \ No newline at end of file diff --git a/web/admin/setting/temp_login.py b/web/admin/setting/temp_login.py index b50714e62..f7e9e9a27 100644 --- a/web/admin/setting/temp_login.py +++ b/web/admin/setting/temp_login.py @@ -17,6 +17,7 @@ from flask import Blueprint, render_template from flask import request from admin import model +from admin import session from admin.model import db,TempLogin from admin.user_login_check import panel_login_required @@ -26,14 +27,40 @@ import utils.config as utils_config from .main import blueprint +@blueprint.route('/get_temp_login', endpoint='get_temp_login', methods=['POST']) +@panel_login_required +def get_temp_login(): + limit = request.form.get('limit', '5').strip() + p = request.form.get('page', '1').strip() + tojs = request.form.get('tojs', '').strip() + + count = TempLogin.query.filter_by().count() + pagination = TempLogin.query.filter_by().order_by(TempLogin.expire.desc()).paginate(page=int(p), per_page=int(limit)) + + rows = [] + for item in pagination.items: + t = {} + t['id'] = item.id + t['salt'] = item.salt + t['state'] = item.state + t['expire'] = item.expire + t['login_time'] = item.login_time + t['login_addr'] = item.login_addr + t['add_time'] = item.add_time + rows.append(t) + + data = {} + data['data'] = rows + data['page'] = mw.getPage({'count':count,'tojs':'setTempAccessReq','p':p,'row':limit}) + return data + @blueprint.route('/set_temp_login', endpoint='set_temp_login', methods=['POST']) @panel_login_required def set_temp_login(): # if 'tmp_login_expire' in session: # return mw.returnData(False, '没有权限') start_time = int(time.time()) - # mw.M('temp_login').where( - # 'state=? and expire>?', (0, start_time)).delete() + model.clearTempLogin() token = mw.getRandomString(48) @@ -52,14 +79,33 @@ def set_temp_login(): r = db.session.add(add_tl) db.session.commit() + if r is None: + mw.writeLog('面板设置', '生成临时连接,过期时间:{}'.format(mw.formatDate(times=expire))) + return {'status': True, 'msg': "临时连接已生成", 'token': make_token, 'expire': expire} + return mw.returnData(False, '连接生成失败') - # if not mw.M('temp_login').count(): - # pdata['id'] = 101 +@blueprint.route('/remove_temp_login', endpoint='remove_temp_login', methods=['POST']) +@panel_login_required +def remove_temp_login(): + tl_id = request.form.get('id', '10').strip() - # if mw.M('temp_login').insert(pdata): - # mw.writeLog('面板设置', '生成临时连接,过期时间:{}'.format(mw.formatDate(times=pdata['expire']))) - # return mw.getJson({'status': True, 'msg': "临时连接已生成", 'token': token, 'expire': pdata['expire']}) - return mw.returnData(False, '连接生成失败') + r = TempLogin.query.filter(TempLogin.id == tl_id).delete() + db.session.commit() + if r > 0: + mw.writeLog('面板设置', '删除临时登录连接') + return mw.returnData(True, '删除成功') + return mw.returnData(False, '删除失败') + + +@blueprint.route('/get_temp_login_logs', endpoint='get_temp_login_logs', methods=['POST']) +@panel_login_required +def get_temp_login_logs(): + if 'tmp_login_expire' in session: + return mw.returnData(False, '没有权限') + return mw.returnData(False, 'ok', []) + + + diff --git a/web/admin/setting/timezone.py b/web/admin/setting/timezone.py new file mode 100644 index 000000000..c2514d535 --- /dev/null +++ b/web/admin/setting/timezone.py @@ -0,0 +1,60 @@ +# coding:utf-8 + +# --------------------------------------------------------------------------------- +# MW-Linux面板 +# --------------------------------------------------------------------------------- +# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved. +# --------------------------------------------------------------------------------- +# Author: midoks +# --------------------------------------------------------------------------------- + +import re +import json +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.config as utils_config + +from .main import blueprint + +# 时区相关 +@blueprint.route('/get_timezone_list', endpoint='get_timezone_list', methods=['POST']) +@panel_login_required +def get_timezone_list(): + import pytz + # 获取时区列表 + # pytz.all_timezones | 所有 + # pytz.common_timezones + return pytz.all_timezones + +@blueprint.route('/sync_date', endpoint='sync_date', methods=['POST']) +@panel_login_required +def sync_date(): + if mw.isAppleSystem(): + return mw.returnData(True, '开发系统不必同步时间!') + data = mw.execShell('ntpdate -s time.nist.gov') + if data[0] == '': + return mw.returnData(True, '同步成功!') + return mw.returnData(False, '同步失败:' + data[0]) + +@blueprint.route('/set_timezone', endpoint='set_timezone', methods=['POST']) +@panel_login_required +def set_timezone(): + # 设置时区列表 + timezone = request.form.get('timezone', '').strip() + cmd = 'timedatectl set-timezone "'+timezone+'"' + mw.execShell(cmd) + return mw.returnData(True, '设置成功!') + + + + + + + \ No newline at end of file diff --git a/web/admin/system/__init__.py b/web/admin/system/__init__.py index 0f5779504..840978ec2 100644 --- a/web/admin/system/__init__.py +++ b/web/admin/system/__init__.py @@ -123,6 +123,7 @@ def set_control(): if _day < 1: return mw.returnData(False, "设置失败!") option.setOption('monitor_day', day, type='monitor') + return mw.returnData(True, "设置成功!") elif stype == '2': option.setOption('monitor_only_netio', 'close', type='monitor') return mw.returnData(True, "设置成功!") diff --git a/web/core/mw.py b/web/core/mw.py index 7bc3e0db4..e3f8c195f 100644 --- a/web/core/mw.py +++ b/web/core/mw.py @@ -576,6 +576,43 @@ def M(table): sql = db.Sql() return sql.table(table) + +def enDoubleCrypt(key, strings): + # 加密字符串 + try: + import base64 + _key = md5(key).encode('utf-8') + _key = base64.urlsafe_b64encode(_key) + + if type(strings) != bytes: + strings = strings.encode('utf-8') + import cryptography + from cryptography.fernet import Fernet + f = Fernet(_key) + result = f.encrypt(strings) + return result.decode('utf-8') + except: + writeFileLog(getTracebackInfo()) + return strings + + +def deDoubleCrypt(key, strings): + # 解密字符串 + try: + import base64 + _key = md5(key).encode('utf-8') + _key = base64.urlsafe_b64encode(_key) + + if type(strings) != bytes: + strings = strings.encode('utf-8') + from cryptography.fernet import Fernet + f = Fernet(_key) + result = f.decrypt(strings).decode('utf-8') + return result + except: + writeFileLog(getTracebackInfo()) + return strings + # ------------------------------ openresty start ----------------------------- def restartWeb(): diff --git a/web/static/app/config.js b/web/static/app/config.js index 078a8c393..066a16dbe 100755 --- a/web/static/app/config.js +++ b/web/static/app/config.js @@ -452,7 +452,7 @@ function setTimezone(){ ", success:function(){ var tbody = ''; - $.post('/config/get_timezone_list', {}, function (rdata) { + $.post('/setting/get_timezone_list', {}, function (rdata) { for (var i = 0; i < rdata.length; i++) { if (rdata[i] == 'Asia/Shanghai'){ @@ -1060,6 +1060,7 @@ function setTempAccessReq(page){ } $.post('/setting/get_temp_login', {page:page}, function(rdata){ + console.log(rdata); if ( typeof(rdata.status) !='undefined' && !rdata.status){ showMsg(rdata.msg,function(){ layer.closeAll(); @@ -1165,7 +1166,7 @@ function setStatusCode(o){ function setTempAccess(){ layer.open({ - area: ['700px', '250px'], + area: ['700px', '380px'], title: '临时授权管理', closeBtn:1, shift: 0, @@ -1268,7 +1269,7 @@ function setAuthBind(){ $('.reset_secret').click(function(){ layer.confirm('您确定要重置当前密钥吗?
重置密钥后,已关联密钥产品,将失效,请重新添加新密钥至产品。',{title:'重置密钥',closeBtn:2,icon:13,cancel:function(){ }}, function() { - $.post('/config/get_auth_secret', {'reset':"1"},function(rdata){ + $.post('/setting/get_auth_secret', {'reset':"1"},function(rdata){ showMsg("接口密钥已生成,重置密钥后,已关联密钥产品,将失效,请重新添加新密钥至产品。", function(){ $('input[name="secret"]').val(rdata.data['secret']); $('.qrcode').html('').qrcode({ text: rdata.data['url']}); diff --git a/web/utils/firewall.py b/web/utils/firewall.py index 84eea6e4e..086f14d78 100644 --- a/web/utils/firewall.py +++ b/web/utils/firewall.py @@ -117,4 +117,21 @@ class Firewall(object): data['firewall_status'] = False else: data['firewall_status'] = self.getFwStatus() - return mw.getJson(data) \ No newline at end of file + return mw.getJson(data) + + def setPing(self): + if mw.isAppleSystem(): + return mw.returnData(True, '开发机不能操作!') + + status = request.form.get('status') + filename = '/etc/sysctl.conf' + conf = mw.readFile(filename) + if conf.find('net.ipv4.icmp_echo') != -1: + rep = r"net\.ipv4\.icmp_echo.*" + conf = re.sub(rep, 'net.ipv4.icmp_echo_ignore_all=' + status, conf) + else: + conf += "\nnet.ipv4.icmp_echo_ignore_all=" + status + + mw.writeFile(filename, conf) + mw.execShell('sysctl -p') + return mw.returnData(True, '设置成功!') \ No newline at end of file diff --git a/web/utils/mwplugin.py b/web/utils/mwplugin.py index cc81d9f37..6a2ff736b 100644 --- a/web/utils/mwplugin.py +++ b/web/utils/mwplugin.py @@ -549,13 +549,7 @@ class MwPlugin(object): data = self.getAllPluginList(type,keyword, page, size) rdata['data'] = data[0] - - args = {} - args['count'] = data[1] - args['p'] = page - args['tojs'] = 'getSList' - args['row'] = size - rdata['list'] = mw.getPage(args) + rdata['list'] = mw.getPage({'count':data[1],'p':page,'tojs':'getSList','row':size}) return rdata # shell/bash方式调用