pull/632/head
Mr Chen 6 months ago
parent 1826adf50e
commit d4cfd90ccd
  1. 3
      class/core/crontab_api.py
  2. 1
      data/control.conf
  3. 1
      data/default_new.pl
  4. 1
      data/recycle_bin.pl
  5. 24
      data/sql/default.sql
  6. 1
      new_cli.sh
  7. 32
      panel_task.py
  8. 4
      panel_tools.py
  9. 28
      web/admin/__init__.py
  10. 5
      web/admin/common.py
  11. 60
      web/admin/crontab/__init__.py
  12. 234
      web/admin/dashboard/__init__.py
  13. 81
      web/admin/dashboard/dashboard.py
  14. 189
      web/admin/dashboard/login.py
  15. 27
      web/admin/logs/__init__.py
  16. 40
      web/admin/setting/setting.py
  17. 35
      web/admin/setup/option.py
  18. 22
      web/admin/setup/user.py
  19. 24
      web/admin/site/__init__.py
  20. 16
      web/admin/system/system.py
  21. 3
      web/admin/task/__init__.py
  22. 4
      web/admin/user_login_check.py
  23. 52
      web/core/db.py
  24. 5
      web/static/app/crontab.js
  25. 1
      web/thisdb/__init__.py
  26. 43
      web/thisdb/crontab.py
  27. 16
      web/thisdb/init.py
  28. 29
      web/thisdb/logs.py
  29. 17
      web/thisdb/option.py
  30. 35
      web/thisdb/sites.py
  31. 35
      web/thisdb/tasks.py
  32. 33
      web/thisdb/temp_login.py
  33. 68
      web/thisdb/user.py
  34. 419
      web/utils/crontab.py
  35. 51
      web/utils/plugin.py

@ -40,8 +40,7 @@ class crontab_api:
startPage = (int(p) - 1) * psize
pageInfo = str(startPage) + ',' + str(psize)
_list = mw.M('crontab').where('', ()).field(
self.field).limit(pageInfo).order('id desc').select()
_list = mw.M('crontab').where('', ()).field(self.field).limit(pageInfo).order('id desc').select()
data = []
for i in range(len(_list)):

@ -33,8 +33,9 @@ CREATE TABLE IF NOT EXISTS `crontab` (
`sname` TEXT,
`sbody` TEXT,
'stype' TEXT,
`urladdress` TEXT
`add_time` TEXT
`url_address` TEXT,
`add_time` TEXT,
`update_time` TEXT
);
CREATE TABLE IF NOT EXISTS `firewall` (
@ -60,7 +61,6 @@ CREATE TABLE IF NOT EXISTS `logs` (
`uid` INTEGER DEFAULT '1',
`add_time` TEXT
);
ALTER TABLE `logs` ADD COLUMN `uid` INTEGER DEFAULT '1';
CREATE TABLE IF NOT EXISTS `sites` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
@ -73,12 +73,10 @@ CREATE TABLE IF NOT EXISTS `sites` (
`edate` TEXT,
`ssl_effective_date` TEXT,
`ssl_expiration_date` TEXT,
`add_time` TEXT
`add_time` TEXT,
`update_time` TEXT
);
ALTER TABLE `sites` ADD COLUMN `ssl_effective_date` TEXT DEFAULT '';
ALTER TABLE `sites` ADD COLUMN `ssl_expiration_date` TEXT DEFAULT '';
CREATE TABLE IF NOT EXISTS `site_types` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT
@ -94,18 +92,16 @@ CREATE TABLE IF NOT EXISTS `domain` (
CREATE TABLE IF NOT EXISTS `users` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`username` TEXT,
`name` TEXT,
`password` TEXT,
`login_ip` TEXT,
`login_time` TEXT,
`phone` TEXT,
`email` TEXT
`email` TEXT,
`add_time` INTEGER,
`update_time` INTEGER
);
INSERT INTO `users` (`id`, `username`, `password`, `login_ip`, `login_time`, `phone`, `email`) VALUES
(1, 'admin', '21232f297a57a5a743894a0e4a801fc3', '192.168.0.10', '2022-02-02 00:00:00', 0, 'midoks@163.com');
CREATE TABLE IF NOT EXISTS `tasks` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT,
@ -145,3 +141,5 @@ CREATE TABLE IF NOT EXISTS `option` (
`type` TEXT,
`value` TEXT
);
CREATE UNIQUE INDEX name_idx ON option(name);

@ -64,7 +64,6 @@ mw_start_debug(){
}
mw_start_panel(){
python3 panel_task.py >> $DIR/logs/panel_task.log 2>&1 &
cd ${DIR}/web && gunicorn -b :7200 -w 1 app:app
}

@ -41,26 +41,12 @@ def execShell(cmdstring, cwd=None, timeout=None, shell=True):
cmd = cmdstring + ' > ' + g_log_file + ' 2>&1'
return mw.execShell(cmd)
def service_cmd(method):
cmd = '/etc/init.d/mw'
if os.path.exists(cmd):
execShell(cmd + ' ' + method)
return
cmd = mw.getPanelDir() + '/scripts/init.d/mw'
if os.path.exists(cmd):
print(cmd + ' ' + method)
data = execShell(cmd + ' ' + method)
print(data)
return
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)
@ -68,7 +54,6 @@ def restartMw():
mw.execShell(cmd)
def downloadFile(url, filename):
# 下载文件
try:
@ -115,23 +100,23 @@ def writeLogs(data):
def runPanelTask():
try:
bash_list = model.getTaskList(status=-1)
bash_list = thisdb.getTaskList(status=-1)
for task in bash_list:
model.setTaskStatus(task['id'], 0)
thisdb.setTaskStatus(task['id'], 0)
run_list = model.getTaskList(status=0)
run_list = thisdb.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)
thisdb.setTaskData(run_task['id'], start=start)
thisdb.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)
thisdb.setTaskData(run_task['id'], end=end)
thisdb.setTaskStatus(run_task['id'], 1)
except Exception as e:
print(str(e))
@ -371,6 +356,5 @@ def run():
startPanelTask()
if __name__ == "__main__":
with app.app_context():
run()
run()

@ -190,7 +190,7 @@ def mwcli(mw_input=0):
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显示成功!")
mw.echoInfo("执行PHP52显示成功!")
elif mw_input == 101:
php_conf = 'plugins/php/info.json'
if os.path.exists(php_conf):
@ -198,7 +198,7 @@ def mwcli(mw_input=0):
cont = re.sub("\"52\",", "", cont)
cont = re.sub("\"5.2.17\",", cont)
mw.writeFile(php_conf, cont)
print("|-执行PHP52隐藏成功!")
mw.echoInfo("执行PHP52隐藏成功!")
elif mw_input == 200:
os.system(INIT_CMD + " mirror")
elif mw_input == 201:

@ -31,8 +31,9 @@ from flask_migrate import Migrate
from flask_caching import Cache
from werkzeug.local import LocalProxy
from admin import model
# from admin import model
from admin import setup
import thisdb
from admin.model import db as sys_db
@ -68,12 +69,13 @@ 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_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)
# sys_db.init_app(app)
# Migrate(app, sys_db)
# 检查数据库是否存在。如果没有就创建它。
@ -84,15 +86,15 @@ if not os.path.isfile(config.SQLITE_PATH):
# 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()
# with app.app_context():
# if setup_db_required:
# sys_db.create_all()
if setup_db_required:
# 初始化用户信息
thisdb.initPanelData()
setup.init_admin_user()
setup.init_option()
setup.init_cmd()
setup.init_db_system()

@ -10,13 +10,14 @@
import time
from admin import model
# from admin import model
from admin import session
import thisdb
def isLogined():
if 'login' in session and session['login'] == True and 'username' in session:
username = session['username']
info = model.getUserByName(username)
info = thisdb.getUserByName(username)
if info is None:
return False

@ -13,7 +13,10 @@ from flask import Blueprint, render_template
from flask import request
from admin.user_login_check import panel_login_required
from admin.model import Crontab
from utils.crontab import crontab as MwCrontab
import core.mw as mw
import thisdb
blueprint = Blueprint('crontab', __name__, url_prefix='/crontab', template_folder='../../templates/default')
@blueprint.route('/index', endpoint='index')
@ -24,26 +27,51 @@ def index():
@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)
page = request.args.get('p', '1').strip()
limit = request.args.get('limit', '10').strip()
return MwCrontab.instance().getCrontabList(page=int(page),size=int(limit))
# 插件列表
@blueprint.route('/logs', endpoint='logs', methods=['GET','POST'])
def logs(self):
sid = request.form.get('id', '')
echo = mw.M('crontab').where("id=?", (sid,)).field('echo').find()
logFile = mw.getServerDir() + '/cron/' + echo['echo'] + '.log'
if not os.path.exists(logFile):
return mw.returnData(False, '当前日志为空!')
log = mw.getLastLine(logFile, 500)
return mw.returnData(True, log)
return []
# 获取计划任务
@blueprint.route('/del', endpoint='del', methods=['GET','POST'])
def crontab_del():
task_id = request.form.get('id', '')
return MwCrontab.instance().delete(task_id)
# 获取计划任务
@blueprint.route('/get_crond_find', endpoint='get_crond_find', methods=['GET','POST'])
def get_crond_find():
sid = request.form.get('id', '')
data = MwCrontab.instance().getCrondFind(sid)
return data
# 添加计划任务
@blueprint.route('/add', endpoint='add', methods=['GET','POST'])
@panel_login_required
def add():
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 []
request_data = {}
request_data['name'] = request.form.get('name', '')
request_data['type'] = request.form.get('type', '')
request_data['week'] = request.form.get('week', '')
request_data['where1'] = request.form.get('where1', '')
request_data['hour'] = request.form.get('hour', '')
request_data['minute'] = request.form.get('minute', '')
request_data['save'] = request.form.get('save', '')
request_data['backup_to'] = request.form.get('backupTo', '')
request_data['stype'] = request.form.get('sType', '')
request_data['sname'] = request.form.get('sName', '')
request_data['sbody'] = request.form.get('sBody', '')
request_data['url_address'] = request.form.get('urladdress', '')
return MwCrontab.instance().add(request_data)

@ -8,236 +8,6 @@
# 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')
# 安全路径
@blueprint.route('/<path>',endpoint='admin_safe_path',methods=['GET'])
def admin_safe_path(path):
db_path = model.getOption('admin_path')
if isLogined():
return redirect('/')
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))
# 仅针对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.returnData(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)
# ---------------------------------------------------------------------------------
# 定义登录入口相关方法
# ---------------------------------------------------------------------------------
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, '登录成功,正在跳转...')
from .dashboard import *
from .login import *

@ -0,0 +1,81 @@
# 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
import thisdb
blueprint = Blueprint('dashboard', __name__, url_prefix='/', template_folder='../../templates')
@blueprint.route('/')
@panel_login_required
def index():
return render_template('default/index.html')
# 安全路径
@blueprint.route('/<path>',endpoint='admin_safe_path',methods=['GET'])
def admin_safe_path(path):
db_path = thisdb.getOption('admin_path')
if isLogined():
return redirect('/')
print(db_path,path)
if db_path == path:
return render_template('default/login.html')
unauthorized_status = thisdb.getOption('unauthorized_status')
if unauthorized_status == '0':
return render_template('default/path.html')
return Response(status=int(unauthorized_status))
# 仅针对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.returnData(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)

@ -0,0 +1,189 @@
# 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
import thisdb
from .dashboard import blueprint
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 = 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()
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 = thisdb.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, '登录成功,正在跳转...')

@ -14,11 +14,9 @@ from flask import request
from admin.user_login_check import panel_login_required
from admin import model
from admin.model import db, Logs
import core.mw as mw
import utils.adult_log as adult_log
import thisdb
# 日志页面
blueprint = Blueprint('logs', __name__, url_prefix='/logs', template_folder='../../templates')
@ -36,33 +34,18 @@ def get_log_list():
size = request.form.get('limit', '10').strip()
search = request.form.get('search', '').strip()
count = Logs.query.filter_by().count()
if search != '':
pagination = Logs.query.filter_by(Logs.type.like(search) or Logs.log.like(search)).paginate(page=int(p), per_page=int(size))
else:
pagination = Logs.query.filter_by().order_by(Logs.id.desc()).paginate(page=int(p), per_page=int(size))
rows = []
for item in pagination.items:
t = {}
t['id'] = item.id
t['type'] = item.type
t['log'] = item.log
t['uid'] = item.uid
t['add_time'] = item.add_time
rows.append(t)
info = thisdb.getLogsList(page=int(p),size=int(size), search=search)
data = {}
data['data'] = rows
data['page'] = mw.getPage({'count':count,'tojs':'getLogs','p':p})
data['data'] = info['list']
data['page'] = mw.getPage({'count':info['count'],'tojs':'getLogs','p':p,'row':size})
return data
# 日志清空
@blueprint.route('/del_panel_logs', endpoint='del_panel_logs', methods=['POST'])
@panel_login_required
def del_panel_logs():
model.clearLog()
# mw.M('logs').dbPos(mw.getPanelDataDir(),'panel').where('id>?', (0,)).delete()
thisdb.clearLog()
mw.writeLog('面板设置', '面板操作日志已清空!')
return mw.returnData(True, '面板操作日志已清空!')

@ -16,10 +16,12 @@ 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 thisdb
import utils.config as utils_config
@ -41,9 +43,9 @@ def get_panel_list():
@panel_login_required
def set_webname():
webname = request.form.get('webname', '')
src_webname = model.getOption('title')
src_webname = thisdb.getOption('title')
if webname != src_webname:
model.setOption('title', webname)
thisdb.setOption('title', webname)
return mw.returnData(True, '面板别名保存成功!')
# 设置服务器IP
@ -51,9 +53,9 @@ def set_webname():
@panel_login_required
def set_ip():
host_ip = request.form.get('host_ip', '')
src_host_ip = model.getOption('server_ip')
src_host_ip = thisdb.getOption('server_ip')
if host_ip != src_host_ip:
model.setOption('server_ip', host_ip)
thisdb.setOption('server_ip', host_ip)
return mw.returnData(True, 'IP保存成功!')
# 默认备份目录
@ -61,9 +63,9 @@ def set_ip():
@panel_login_required
def set_backup_dir():
backup_path = request.form.get('backup_path', '')
src_backup_path = model.getOption('backup_path')
src_backup_path = thisdb.getOption('backup_path')
if backup_path != src_backup_path:
model.setOption('backup_path', backup_path)
thisdb.setOption('backup_path', backup_path)
return mw.returnData(True, '修改默认备份目录成功!')
# 默认站点目录
@ -71,9 +73,9 @@ def set_backup_dir():
@panel_login_required
def set_www_dir():
sites_path = request.form.get('sites_path', '')
src_sites_path = model.getOption('sites_path')
src_sites_path = thisdb.getOption('sites_path')
if sites_path != src_sites_path:
model.setOption('sites_path', sites_path)
thisdb.setOption('sites_path', sites_path)
return mw.returnData(True, '修改默认建站目录成功!')
@ -102,9 +104,9 @@ def set_admin_path():
if not re.match(r"^/[\w]+$", admin_path):
return mw.returnData(False, '入口地址格式不正确,示例: /mw_rand')
src_admin_path = model.getOption('admin_path')
src_admin_path = thisdb.getOption('admin_path')
if admin_path != src_admin_path:
model.setOption('admin_path', admin_path[1:])
thisdb.setOption('admin_path', admin_path[1:])
return mw.returnData(True, '修改成功!')
@ -125,7 +127,7 @@ def set_basic_auth():
is_open = False
if basic_open == 'false':
model.setOption('basic_auth', json.dumps({'open':False}))
thisdb.setOption('basic_auth', json.dumps({'open':False}))
mw.writeLog('面板设置', '设置BasicAuth状态为: %s' % is_open)
return mw.returnData(True, '删除BasicAuth成功!')
@ -139,7 +141,7 @@ def set_basic_auth():
data['basic_pwd'] = mw.md5(basic_pwd + salt)
data['open'] = is_open
model.setOption('basic_auth', json.dumps(data))
thisdb.setOption('basic_auth', json.dumps(data))
mw.writeLog('面板设置', '设置BasicAuth状态为: %s' % is_open)
return mw.returnData(True, '设置成功!')
@ -158,7 +160,7 @@ def set_status_code():
return mw.returnData(False, '状态码范围错误!')
info = utils_config.getUnauthStatus(code=str(status_code))
model.setOption('unauthorized_status', str(status_code))
thisdb.setOption('unauthorized_status', str(status_code))
mw.writeLog('面板设置', '将未授权响应状态码设置为:{0}:{1}'.format(status_code,info['text']))
return mw.returnData(True, '设置成功!')
@ -166,11 +168,11 @@ def set_status_code():
@blueprint.route('/open_debug', endpoint='open_debug', methods=['POST'])
@panel_login_required
def open_debug():
debug = model.getOption('debug',default='close')
debug = thisdb.getOption('debug',default='close')
if debug == 'open':
model.setOption('debug','close')
thisdb.setOption('debug','close')
return mw.returnData(True, '开发模式关闭!')
model.setOption('debug','open')
thisdb.setOption('debug','open')
return mw.returnData(True, '开发模式开启!')
@ -178,11 +180,11 @@ def open_debug():
@blueprint.route('/close_panel', endpoint='close_panel', methods=['POST'])
@panel_login_required
def close_panel():
admin_close = model.getOption('admin_close',default='no')
admin_close = thisdb.getOption('admin_close',default='no')
if admin_close == 'no':
model.setOption('admin_close','yes')
thisdb.setOption('admin_close','yes')
return mw.returnData(True, '开启面板成功!')
model.setOption('admin_close','no')
thisdb.setOption('admin_close','no')
return mw.returnData(True, '关闭面板成功!')
# 设置IPV6状态

@ -12,50 +12,47 @@ import json
from flask import request
from admin import model
from admin.model import db, Users
import core.mw as mw
import thisdb
def init_option():
model.setOption('title', '后羿面板')
model.setOption('recycle_bin', 'open')
model.setOption('template', 'default')
thisdb.setOption('title', '后羿面板')
thisdb.setOption('recycle_bin', 'open')
thisdb.setOption('template', 'default')
# 后台面板是否关闭
model.setOption('admin_close', 'no')
thisdb.setOption('admin_close', 'no')
# 未认证状态码
model.setOption('unauthorized_status', '0')
thisdb.setOption('unauthorized_status', '0')
# 调式模式,默认关闭
model.setOption('debug', 'close')
thisdb.setOption('debug', 'close')
# basic auth 配置
model.setOption('basic_auth', json.dumps({'open':False}))
thisdb.setOption('basic_auth', json.dumps({'open':False}))
# 开启后台任务
# model.setOption('run_bg_task', 'close')
# 首页展示初始化
model.setOption('display_index', '[]')
thisdb.setOption('display_index', '[]')
# 监控默认配置
model.setOption('monitor_status', 'open', type='monitor')
model.setOption('monitor_day', '30', type='monitor')
model.setOption('monitor_only_netio', 'open', type='monitor')
thisdb.setOption('monitor_status', 'open', type='monitor')
thisdb.setOption('monitor_day', '30', type='monitor')
thisdb.setOption('monitor_only_netio', 'open', type='monitor')
# 初始化安全路径
model.setOption('admin_path', mw.getRandomString(8))
thisdb.setOption('admin_path', mw.getRandomString(8))
ip = mw.getLocalIp()
model.setOption('server_ip', ip)
thisdb.setOption('server_ip', ip)
# 默认备份目录
model.setOption('backup_path', mw.getFatherDir()+'/backup')
thisdb.setOption('backup_path', mw.getFatherDir()+'/backup')
# 默认站点目录
model.setOption('site_path', mw.getFatherDir()+'/wwwroot')
thisdb.setOption('site_path', mw.getFatherDir()+'/wwwroot')
return True

@ -14,28 +14,10 @@ from admin import model
from admin.model import db, Users
import core.mw as mw
import thisdb
# 初始化用户信息
def init_admin_user():
data = Users.query.filter_by(id=1).first()
if not data:
name = mw.getRandomString(8).lower()
password = mw.getRandomString(8).lower()
file_pass_pl = mw.getPanelDataDir() + '/default.pl'
mw.writeFile(file_pass_pl, password)
insert_time = mw.formatDate()
login_ip = '127.0.0.1'
add_user = Users(
name=name,
password=mw.md5(password),
login_ip=login_ip,
login_time=insert_time,
phone='',
email='',
add_time=insert_time,
update_time=insert_time)
db.session.add(add_user)
db.session.commit()
db.session.close()
thisdb.initAdminUser()
return True

@ -19,6 +19,7 @@ from admin.user_login_check import panel_login_required
from utils.plugin import plugin as MwPlugin
import utils.site as site
import core.mw as mw
import thisdb
blueprint = Blueprint('site', __name__, url_prefix='/site', template_folder='../../templates/default')
@blueprint.route('/index', endpoint='index')
@ -34,28 +35,11 @@ def list():
type_id = request.form.get('type_id', '0').strip()
search = request.form.get('search', '').strip()
count = Sites.query.count()
pagination = Sites.query.paginate(page=int(p), per_page=int(limit))
site_list = []
for item in pagination.items:
t = {}
t['id'] = item.id
t['name'] = item.name
t['path'] = item.path
t['index'] = item.index
t['ps'] = item.ps
t['edate'] = item.edate
t['type_id'] = item.type_id
t['status'] = item.status
t['add_time'] = item.add_time
t['update_time'] = item.update_time
site_list.append(t)
info = thisdb.getSitesList(page=int(p),size=int(limit),type_id=int(type_id), search=search)
data = {}
data['data'] = site_list
data['page'] = mw.getPage({'count':count,'tojs':'getWeb','p':p, 'row':limit})
data['data'] = info['list']
data['page'] = mw.getPage({'count':info['count'],'tojs':'getWeb','p':p, 'row':limit})
return data
@blueprint.route('/get_site_types', endpoint='get_site_types',methods=['POST'])

@ -16,9 +16,9 @@ from flask import request
from admin.user_login_check import panel_login_required
from utils.system import monitor
import admin.model.option as option
import core.mw as mw
import utils.system as sys
import thisdb
@ -112,19 +112,19 @@ def set_control():
day = request.form.get('day', '')
if stype == '0':
option.setOption('monitor_status', 'close', type='monitor')
thisdb.setOption('monitor_status', 'close', type='monitor')
return mw.returnData(True, "设置成功!")
elif stype == '1':
_day = int(day)
if _day < 1:
return mw.returnData(False, "设置失败!")
option.setOption('monitor_day', day, type='monitor')
thisdb.setOption('monitor_day', day, type='monitor')
return mw.returnData(True, "设置成功!")
elif stype == '2':
option.setOption('monitor_only_netio', 'close', type='monitor')
thisdb.setOption('monitor_only_netio', 'close', type='monitor')
return mw.returnData(True, "设置成功!")
elif stype == '3':
option.setOption('monitor_only_netio', 'open', type='monitor')
thisdb.setOption('monitor_only_netio', 'open', type='monitor')
return mw.returnData(True, "设置成功!")
elif stype == 'del':
if not mw.isRestart():
@ -132,9 +132,9 @@ def set_control():
monitor.instance().clearDbFile()
return mw.returnData(True, "清空监控记录成功!")
else:
monitor_status = option.getOption('monitor_status', default='open', type='monitor')
monitor_day = option.getOption('monitor_day', default='30', type='monitor')
monitor_only_netio = option.getOption('monitor_only_netio', default='open', type='monitor')
monitor_status = thisdb.getOption('monitor_status', default='open', type='monitor')
monitor_day = thisdb.getOption('monitor_day', default='30', type='monitor')
monitor_only_netio = thisdb.getOption('monitor_only_netio', default='open', type='monitor')
data = {}
data['day'] = monitor_day
if monitor_status == 'open':

@ -18,6 +18,7 @@ from admin.user_login_check import panel_login_required
import core.mw as mw
import utils.task as MwTasks
import thisdb
blueprint = Blueprint('task', __name__, url_prefix='/task', template_folder='../../templates/default')
@ -25,7 +26,7 @@ blueprint = Blueprint('task', __name__, url_prefix='/task', template_folder='../
@blueprint.route('/count', endpoint='task_count')
@panel_login_required
def task_count():
return str(model.getTaskUnexecutedCount())
return str(thisdb.getTaskUnexecutedCount())
@blueprint.route('/list', endpoint='list', methods=['POST'])

@ -14,17 +14,17 @@ from flask import Response
from functools import wraps
from admin import model
from admin import session
from admin.common import isLogined
import thisdb
def panel_login_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not isLogined():
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))

@ -120,6 +120,21 @@ class Sql():
self.__OPT_FIELD = field
return self
def getDbField(self,name):
sql = "PRAGMA table_info(%s)" % name
result = self.__DB_CONN.execute(sql)
data = result.fetchall()
fields = []
for i in data:
fields.append(i[1])
return fields
def getDbFieldString(self,name):
fields = self.getDbField(name)
return ','.join(fields)
def select(self):
# 查询数据集
self.__getConn()
@ -130,25 +145,40 @@ class Sql():
# print(self.__OPT_PARAM)
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
data = result.fetchall()
if len(data) == 0:
return data
# 构造字曲系列
if self.__OPT_FIELD != "*":
field = self.__OPT_FIELD.split(',')
tmp = []
for row in data:
i = 0
tmp1 = {}
t = {}
for key in field:
tmp1[key] = row[i]
t[key] = row[i]
i += 1
tmp.append(tmp1)
del(tmp1)
tmp.append(t)
del(t)
data = tmp
del(tmp)
else:
# 将元组转换成列表
tmp = map(list, data)
field = self.getDbField(self.__DB_TABLE)
tmp = []
for row in data:
i = 0
t = {}
for key in field:
t[key] = row[i]
i += 1
tmp.append(t)
del(t)
data = tmp
del(tmp)
# 将元组转换成列表
# tmp = map(list, data)
# data = tmp
# del(tmp)
self.__close()
return data
except Exception as ex:
@ -162,7 +192,8 @@ class Sql():
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
if os.path.exists('data/debug.pl'):
debug = getPanelDir()+'/data/debug.pl'
if os.path.exists(debug):
print(sql, self.__OPT_PARAM)
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
data = result.fetchall()
@ -199,7 +230,7 @@ class Sql():
result = self.field(keyName).select()
if len(result) == 1:
return result[0][keyName]
return result
return None
def setField(self, keyName, keyValue):
# 更新指定字段
@ -210,7 +241,7 @@ class Sql():
result = self.limit("1").select()
if len(result) == 1:
return result[0]
return result
return None
def count(self):
# 取行数
@ -237,7 +268,8 @@ class Sql():
self.__DB_CONN.commit()
return last_id
except Exception as ex:
return "error: " + str(ex)
print(str(ex))
return 0
# 插入数据
def insert(self, pdata):

@ -83,6 +83,7 @@ function getBackupName(hook_data, name){
function getCronData(page){
var load = layer.msg(lan.public.the,{icon:16,time:0,shade: [0.3, '#000']});
$.post("/crontab/list?p="+page,'', function(rdata){
console.log(rdata);
layer.close(load);
var cbody = "";
if(rdata == ""){
@ -115,7 +116,7 @@ function getCronData(page){
<td>"+rdata.data[i].cycle+"</td>\
<td>"+cron_save +"</td>\
<td>"+cron_backupto+"</td>\
<td>"+rdata.data[i].addtime+"</td>\
<td>"+rdata.data[i].add_time+"</td>\
<td>\
<a href=\"javascript:startTask("+rdata.data[i].id+");\" class='btlink'>执行</a> | \
<a href=\"javascript:editTaskInfo('"+rdata.data[i].id+"');\" class='btlink'>编辑</a> | \
@ -341,7 +342,7 @@ function planAdd(){
$("#cronConfig input[name='sName']").val(sName);
layer.msg('正在添加,请稍候...!',{icon:16,time:0,shade: [0.3, '#000']});
var data = $("#cronConfig").serialize() + '&sBody='+sBody + '&urladdress=' + urladdress;
var data = $("#cronConfig").serialize() + '&sBody='+sBody;
// console.log(data);
$.post('/crontab/add',data,function(rdata){
if(!rdata.status) {

@ -14,3 +14,4 @@ from .user import *
from .sites import *
from .tasks import *
from .logs import *
from .crontab import *

@ -0,0 +1,43 @@
# 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 core.mw as mw
__field = 'id,name,type,where1,where_hour,where_minute,echo,status,save,backup_to,stype,sname,sbody,url_address,add_time,update_time'
def addCrontab(data):
now_time = mw.formatDate()
data['add_time'] = now_time
data['update_time'] = now_time
return mw.M('crontab').insert(data)
def getCrond(id):
return mw.M('crontab').where('id=?', (id,)).field(__field).find()
def deleteCronById(id):
mw.M('crontab').where("id=?", (id,)).delete()
return True
def getCrontabList(
page:int | None = 1,
size:int | None = 10,
):
start = (int(page) - 1) * size
limit = str(start) + ',' + str(size)
cron_list = mw.M('crontab').field(__field).limit(limit).order('id desc').select()
count = mw.M('crontab').count()
data = {}
data['count'] = count
data['list'] = cron_list
return data

@ -8,6 +8,20 @@
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import core.mw as mw
def initPanelData():
pass
_dbfile = mw.getPanelDataDir() + '/panel.db'
if os.path.exists(_dbfile):
return True
sql_file = mw.getPanelDataDir() + '/sql/default.sql'
sql = mw.M().dbPos(mw.getPanelDataDir(),'panel')
csql = mw.readFile(sql_file)
csql_list = csql.split(';')
for index in range(len(csql_list)):
print(index)
sql.execute(csql_list[index], ())
return True

@ -8,6 +8,7 @@
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import json
import core.mw as mw
@ -32,4 +33,30 @@ def addLog(type, log,
'add_time':add_time,
}
mw.M('logs').insert(insert_data)
return True
return True
def getLogsList(
page:int | None = 1,
size:int | None = 10,
search: str | None = ''
):
sql_where = ''
if search != '' :
sql_where = " type like '%" + search + "%' or log like '%" + search + "%' "
field = 'id,type,log,uid,add_time'
dbM = dbC = mw.M('logs').field(field)
if sql_where != '':
count = mw.M('logs').field(field).where(sql_where).count()
else:
count = mw.M('logs').field(field).count()
start = (int(page) - 1) * (int(size))
limit = str(start) + ',' +str(size)
logs_list = mw.M('logs').field(field).limit(limit).order('id desc').select()
data = {}
data['list'] = logs_list
data['count'] = count
return data

@ -23,8 +23,7 @@ def getOption(name,
:default -> str 默认值 (可选)
'''
data = mw.M('option').field('name').where('name=? and type=?',(name, type,)).getField('value')
if len(data) == 0:
if data is None:
return default
return data
@ -40,7 +39,7 @@ def getOptionByJson(name,
:default -> str 默认值 (可选)
'''
data = mw.M('option').field('name').where('name=? and type=?',(name, type,)).getField('value')
if len(data) == 0:
if data is None:
return default
if data is not None:
return json.loads(data)
@ -54,5 +53,15 @@ def setOption(name, value,
:value -> object值 (必填)
:type -> str 类型 (可选|默认common)
'''
mw.M('option').field('name').where('name=? and type=?',(name, type,)).setField('value', value)
data = mw.M('option').field('name,type,value').where('name=? and type=?',(name, type,)).find()
if data is not None:
mw.M('option').field('name').where('name=? and type=?',(name, type,)).setField('value', value)
return True
add_option = {
'name':name,
'type':type,
'value':value
}
mw.M('option').insert(add_option)
return True

@ -11,5 +11,38 @@
import core.mw as mw
def getSitesCount():
return mw.M('sites').count()
return mw.M('sites').count()
def getSitesList(
page:int | None = 1,
size:int | None = 10,
type_id:int | None = 0,
search: str | None = ''
):
sql_where = ''
if search != '' :
sql_where = " name like '%" + search + "%' or ps like '%" + search + "%' "
if type_id != '' and int(type_id) >= 0 and search != '' :
sql_where = sql_where + " and type_id=" + str(type_id) + ""
if type_id != '' and int(type_id) >= 0:
sql_where = " type_id=" + str(type_id)
dbM = dbC = mw.M('sites').field('id,name,path,status,ps,edate,type_id,add_time,update_time')
if sql_where != '':
count = dbC.where(sql_where).count()
else:
count = dbC.count()
start = (int(page) - 1) * (int(size))
limit = str(start) + ',' +str(size)
site_list = dbM.limit(limit).order('id desc').select()
data = {}
data['list'] = site_list
data['count'] = count
return data

@ -10,6 +10,10 @@
import core.mw as mw
# 未执行任务总数
def getTaskUnexecutedCount() -> int:
return mw.M('tasks').where('status!=?',(1,)).count()
def addTask(
name: str | None = '常用任务',
cmd: str | None = None,
@ -36,4 +40,35 @@ def addTask(
'add_time':add_time,
}
mw.M('tasks').insert(insert_data)
return True
def getTaskList(
status: int | None = 1,
page: int | None = 1,
size: int | None = 10,
):
start = (page - 1) * size
limit = str(start) + ',' + str(size)
field = 'id,name,type,start,end,status,add_time'
data = mw.M('tasks').where('', ()).field(field).limit(limit).order('id asc').select()
return data
def setTaskStatus(id,
status: int | None = 0
):
mw.M('tasks').where('id=?',(id,)).update({'status':status})
return True
def setTaskData(id,
start: int | None = None,
end: int | None = None,
):
if start is not None:
mw.M('tasks').where('id=?',(id,)).update({'start':start})
if end is not None:
mw.M('tasks').where('id=?',(id,)).update({'end':end})
return True

@ -0,0 +1,33 @@
# 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.model import db, TempLogin
import core.mw as mw
def getTempLoginByToken(token,
) -> None:
'''
获取用户信息通过用户名
'''
field = 'id,addtime,expire,login_time,login_addr,state,add_time'
data = mw.M('temp_login').where('token=?', (token,)).field(field).order('id asc').select()
return data
def clearTempLogin()->bool:
'''
清空过期数据
'''
now_time = int(time.time())
mw.M('temp_login').where('expire<?', (now_time)).delete()
return True

@ -10,25 +10,49 @@
import core.mw as mw
# 初始化用户信息
def initAdminUser():
data = mw.M('users').field('id').where('id=?', (1,)).find()
if data is None:
name = mw.getRandomString(8).lower()
password = mw.getRandomString(8).lower()
insert_time = mw.formatDate()
login_ip = '127.0.0.1'
add_user = {
'name':name,
'password':mw.md5(password),
'login_ip':login_ip,
'login_time':insert_time,
'phone':'',
'email':'',
'add_time':insert_time,
'update_time':insert_time
}
file_pass_pl = mw.getPanelDataDir() + '/default.pl'
mw.writeFile(file_pass_pl, password)
mw.M('users').insert(add_user)
return True
def getUserByName(name,
) -> None:
'''
获取用户信息通过用户名
'''
users_field = 'id,name,password,login_ip,login_time,phone,email,add_time,update_time'
item = mw.M('users').field(users_field).where('name=?', (name,)).select()
if len(item) == 0:
data = mw.M('users').field(users_field).where('name=?', (name,)).find()
if data is None:
return None
row = {}
row['id'] = item[0]['id']
row['name'] = item[0]['name']
row['password'] = item[0]['password']
row['login_ip'] = item[0]['login_ip']
row['login_time'] = item[0]['login_time']
row['phone'] = item[0]['phone']
row['email'] = item[0]['email']
row['add_time'] = item[0]['add_time']
row['update_time'] = item[0]['update_time']
row['id'] = data['id']
row['name'] = data['name']
row['password'] = data['password']
row['login_ip'] = data['login_ip']
row['login_time'] = data['login_time']
row['phone'] = data['phone']
row['email'] = data['email']
row['add_time'] = data['add_time']
row['update_time'] = data['update_time']
return row
def getUserById(id,
@ -37,19 +61,19 @@ def getUserById(id,
获取用户信息通过用户名
'''
users_field = 'id,name,password,login_ip,login_time,phone,email,add_time,update_time'
item = mw.M('users').field(users_field).where('id=?', (1,)).select()
if len(item) == 0:
data = mw.M('users').field(users_field).where('id=?', (1,)).find()
if data is None:
return None
row = {}
row['id'] = item[0]['id']
row['name'] = item[0]['name']
row['password'] = item[0]['password']
row['login_ip'] = item[0]['login_ip']
row['login_time'] = item[0]['login_time']
row['phone'] = item[0]['phone']
row['email'] = item[0]['email']
row['add_time'] = item[0]['add_time']
row['update_time'] = item[0]['update_time']
row['id'] = data['id']
row['name'] = data['name']
row['password'] = data['password']
row['login_ip'] = data['login_ip']
row['login_time'] = data['login_time']
row['phone'] = data['phone']
row['email'] = data['email']
row['add_time'] = data['add_time']
row['update_time'] = data['update_time']
return row

@ -8,4 +8,423 @@
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import sys
import time
import json
import threading
import multiprocessing
from admin import model
import core.mw as mw
import thisdb
class crontab(object):
# lock
_instance_lock = threading.Lock()
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(crontab, "_instance"):
with crontab._instance_lock:
if not hasattr(crontab, "_instance"):
crontab._instance = crontab(*args, **kwargs)
return crontab._instance
# 获取指定任务数据
def getCrondFind(self, cron_id):
return thisdb.getCrond(cron_id)
def add(self, data):
if len(data['name']) < 1:
return mw.returnData(False, '任务名称不能为空!')
is_check_pass, msg = self.cronCheck(data)
if not is_check_pass:
return mw.returnData(is_check_pass, msg)
cmd, title = self.getCrondCycle(data)
cron_path = mw.getServerDir() + '/cron'
cron_name = self.getShell(data)
cmd += ' ' + cron_path + '/' + cron_name + ' >> ' + cron_path + '/' + cron_name + '.log 2>&1'
if not mw.isAppleSystem():
data = self.writeShell(cmd)
if not data['status']:
return data
self.crondReload()
add_dbdata = {}
add_dbdata['name'] = data['name']
add_dbdata['type'] = data['type']
add_dbdata['where1'] = data['where1']
add_dbdata['where_hour'] = data['hour']
add_dbdata['where_minute'] = data['minute']
add_dbdata['save'] = data['save']
add_dbdata['backup_to'] = data['backup_to']
add_dbdata['sname'] = data['sname']
add_dbdata['sbody'] = data['sbody']
add_dbdata['stype'] = data['stype']
add_dbdata['echo'] = cron_name
add_dbdata['url_address'] = data['url_address']
tid = thisdb.addCrontab(add_dbdata)
if tid > 0:
return mw.returnData(True, '添加成功')
return mw.returnData(False, '添加失败')
def delete(self, tid):
data = thisdb.getCrond(tid)
if not self.removeForCrond(data['echo']):
return mw.returnData(False, '无法写入文件,请检查是否开启了系统加固功能!')
cron_path = mw.getServerDir() + '/cron'
cron_file = cron_path + '/' + data['echo']
if os.path.exists(cron_file):
os.remove(cron_file)
cron_file = cron_path + '/' + data['echo'] + '.log'
if os.path.exists(cron_file):
os.remove(cron_file)
thisdb.deleteCronById(tid)
msg = mw.getInfo('删除计划任务[{1}]成功!', (data['name'],))
mw.writeLog('计划任务', msg)
return mw.returnData(True, msg)
def getCrontabHuman(self, data):
rdata = []
for i in range(len(data)):
t = data[i]
if t['type'] == "day":
t['type'] = '每天'
t['cycle'] = mw.getInfo('每天, {1}{2}分 执行', (str(t['where_hour']), str(t['where_minute'])))
elif t['type'] == "day-n":
t['type'] = mw.getInfo('{1}', (str(t['where1']),))
t['cycle'] = mw.getInfo('每隔{1}天, {2}{3}分 执行', (str(t['where1']), str(t['where_hour']), str(t['where_minute'])))
elif t['type'] == "hour":
t['type'] = '每小时'
t['cycle'] = mw.getInfo('每小时, 第{1}分钟 执行', (str(t['where_minute']),))
elif t['type'] == "hour-n":
t['type'] = mw.getInfo('{1}小时', (str(t['where1']),))
t['cycle'] = mw.getInfo('{1}小时, 第{2}分钟 执行', (str(t['where1']), str(t['where_minute'])))
elif t['type'] == "minute-n":
t['type'] = mw.getInfo('{1}分钟', (str(t['where1']),))
t['cycle'] = mw.getInfo('每隔{1}分钟执行', (str(t['where1']),))
elif t['type'] == "week":
t['type'] = '每周'
if not t['where1']:
t['where1'] = '0'
t['cycle'] = mw.getInfo('每周{1}, {2}{3}分执行', (self.toWeek(int(t['where1'])), str(t['where_hour']), str(t['where_minute'])))
elif t['type'] == "month":
t['type'] = '每月'
t['cycle'] = mw.getInfo('每月, {1}{2}{3}分执行', (str(t['where1']), str(t['where_hour']), str(t['where_minute'])))
rdata.append(t)
return rdata
# 从crond删除
def removeForCrond(self, echo):
if mw.isAppleSystem():
return True
u_file = '/var/spool/cron/crontabs/root'
if not os.path.exists(u_file):
file = '/var/spool/cron/root'
if not os.path.exists(file):
return False
else:
file = u_file
conf = mw.readFile(file)
rep = ".+" + str(echo) + ".+\n"
conf = re.sub(rep, "", conf)
if not mw.writeFile(file, conf):
return False
self.crondReload()
return True
def getCrontabList(self,
page:int | None = 1,
size:int | None = 10
):
info = thisdb.getCrontabList(page=int(page),size=int(size))
rdata = {}
rdata['data'] = self.getCrontabHuman(info['list'])
rdata['page'] = mw.getPage({'count':info['count'],'tojs':'getCronData','p':page,'row':size})
return rdata
def getCrondCycle(self, params):
cron_cmd = ''
title = ''
if params['type'] == "day":
cron_cmd = self.getDay(params)
title = '每天'
elif params['type'] == "day-n":
cron_cmd = self.getDay_N(params)
title = mw.getInfo('{1}', (params['where1'],))
elif params['type'] == "hour":
cron_cmd = self.getHour(params)
title = '每小时'
elif params['type'] == "hour-n":
cron_cmd = self.getHour_N(params)
title = '每小时'
elif params['type'] == "minute-n":
cron_cmd = self.minute_N(params)
elif params['type'] == "week":
params['where1'] = params['week']
cron_cmd = self.week(params)
elif params['type'] == "month":
cron_cmd = self.month(params)
return cron_cmd, title
# 转换大写星期
def toWeek(self, num):
wheres = {
0: '',
1: '',
2: '',
3: '',
4: '',
5: '',
6: ''
}
try:
return wheres[num]
except:
return ''
# 取任务构造Day
def getDay(self, param):
cmd = "{0} {1} * * * ".format(param['minute'], param['hour'])
return cmd
# 取任务构造Day_n
def getDay_N(self, param):
cmd = "{0} {1} */{2} * * ".format(param['minute'], param['hour'], param['where1'])
return cmd
# 取任务构造Hour
def getHour(self, param):
cmd = "{0} * * * * ".format(param['minute'])
return cmd
# 取任务构造Hour-N
def getHour_N(self, param):
cmd = "{0} */{1} * * * ".format(param['minute'], param['where1'])
return cmd
# 取任务构造Minute-N
def minute_N(self, param):
cmd = "*/{0} * * * * ".format(param['where1'])
return cmd
# 取任务构造week
def week(self, param):
cmd = "{0} {1} * * {2}".format(param['minute'], param['hour'], param['week'])
return cmd
# 取任务构造Month
def month(self, param):
cmd = "{0} {1} {2} * * ".format(param['minute'], param['hour'], param['where1'])
return cmd
# 参数校验
def cronCheck(self, params):
if params['stype'] == 'site' or params['stype'] == 'database' or params['stype'].find('database_') > -1 or params['stype'] == 'logs' or params['stype'] == 'path':
if params['save'] == '':
return False, '保留份数不能为空!'
if params['type'] == 'day':
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'day-n':
if params['where1'] == '':
return False, '天不能为空!'
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'hour':
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'hour-n':
if params['where1'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'minute-n':
if params['where1'] == '':
return False, '分钟不能为空!'
if params['type'] == 'week':
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'month':
if params['where1'] == '':
return False, '日不能为空!'
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
return True, 'OK'
# 取执行脚本
def getShell(self, param):
# try:
stype = param['stype']
if stype == 'toFile':
shell = param.sFile
else:
head = "#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n"
start_head = '''
SCRIPT_RUN_TIME="0s"
MW_ToSeconds()
{
SEC=$1
if [ $SEC -lt 60 ]; then
SCRIPT_RUN_TIME="${SEC}s"
elif [ $SEC -ge 60 ] && [ $SEC -lt 3600 ];then
SCRIPT_RUN_TIME="$(( SEC / 60 ))m$(( SEC % 60 ))s"
elif [ $SEC -ge 3600 ]; then
SCRIPT_RUN_TIME="$(( SEC / 3600 ))h$(( (SEC % 3600) / 60 ))m$(( (SEC % 3600) % 60 ))s"
fi
}
START_MW_SHELL_TIME=`date +%s`
'''
source_bin_activate = '''
export LANG=en_US.UTF-8
MW_PATH=%s/bin/activate
if [ -f $MW_PATH ];then
source $MW_PATH
fi''' % (mw.getPanelDir(),)
head = head + start_head + source_bin_activate + "\n"
log = '.log'
#所有
if param['sname'] == 'ALL':
log = ''
script_dir = mw.getPanelDir() + "/scripts"
source_stype = 'database'
if stype.find('database_') > -1:
plugin_name = stype.replace('database_', '')
script_dir = mw.getPanelDir() + "/plugins/" + plugin_name + "/scripts"
source_stype = stype
stype = 'database'
wheres = {
'path': head + "python3 " + script_dir + "/backup.py path " + param['sname'] + " " + str(param['save']),
'site': head + "python3 " + script_dir + "/backup.py site " + param['sname'] + " " + str(param['save']),
'database': head + "python3 " + script_dir + "/backup.py database " + param['sname'] + " " + str(param['save']),
'logs': head + "python3 " + script_dir + "/logs_backup.py " + param['sname'] + log + " " + str(param['save']),
'rememory': head + "/bin/bash " + script_dir + '/rememory.sh'
}
if param['backup_to'] != 'localhost':
cfile = mw.getPluginDir() + "/" + \
param['backup_to'] + "/index.py"
wheres['path'] = head + "python3 " + cfile + \
" path " + param['sname'] + " " + str(param['save'])
wheres['site'] = head + "python3 " + cfile + \
" site " + param['sname'] + " " + str(param['save'])
wheres['database'] = head + "python3 " + cfile + " " + \
source_stype + " " + \
param['sname'] + " " + str(param['save'])
try:
shell = wheres[stype]
except:
if stype == 'toUrl':
shell = head + "curl -sS --connect-timeout 10 -m 60 '" + \
param['urladdress'] + "'"
else:
shell = head + param['sbody'].replace("\r\n", "\n")
shell += '''
echo "----------------------------------------------------------------------------"
endDate=`date +"%Y-%m-%d %H:%M:%S"`
END_MW_SHELL_TIME=`date +"%s"`
((SHELL_COS_TIME=($END_MW_SHELL_TIME-$START_MW_SHELL_TIME)))
MW_ToSeconds $SHELL_COS_TIME
echo "★[$endDate] Successful | Script Run [$SCRIPT_RUN_TIME] "
echo "----------------------------------------------------------------------------"
'''
cron_path = mw.getServerDir() + '/cron'
if not os.path.exists(cron_path):
mw.execShell('mkdir -p ' + cron_path)
if not 'echo' in param:
cron_name = mw.md5(mw.md5(str(time.time()) + '_mw'))
else:
cron_name = param['echo']
file = cron_path + '/' + cron_name
mw.writeFile(file, self.checkScript(shell))
mw.execShell('chmod 750 ' + file)
return cron_name
# 检查脚本
def checkScript(self, shell):
keys = ['shutdown', 'init 0', 'mkfs', 'passwd',
'chpasswd', '--stdin', 'mkfs.ext', 'mke2fs']
for key in keys:
shell = shell.replace(key, '[***]')
return shell
# 将Shell脚本写到文件
def writeShell(self, config):
file = '/var/spool/cron/crontabs/root'
current_os = mw.getOs()
if current_os == 'darwin':
file = '/etc/crontab'
elif current_os.startswith("freebsd"):
file = '/var/cron/tabs/root'
if not os.path.exists(file):
file = '/var/spool/cron/root'
if not os.path.exists(file):
mw.writeFile(file, '')
conf = mw.readFile(file)
conf += str(config) + "\n"
if mw.writeFile(file, conf):
if not os.path.exists(file):
mw.execShell("chmod 600 '" + file +"' && chown root.root " + file)
else:
mw.execShell("chmod 600 '" + file +"' && chown root.crontab " + file)
return mw.returnData(True, 'ok')
return mw.returnData(False, '文件写入失败,请检查是否开启系统加固功能!')
# 重载配置
def crondReload(self):
if mw.isAppleSystem():
if os.path.exists('/etc/crontab'):
pass
else:
if os.path.exists('/etc/init.d/crond'):
mw.execShell('/etc/init.d/crond reload')
elif os.path.exists('/etc/init.d/cron'):
mw.execShell('service cron restart')
else:
mw.execShell("systemctl reload crond")

@ -17,7 +17,6 @@ import multiprocessing
from admin import model
import core.mw as mw
import admin.model.option as option
import thisdb
class pg_thread(threading.Thread):
@ -108,7 +107,7 @@ class plugin(object):
self.__index_data = json.loads(mw.readFile(self.__index))
def getIndexList(self):
indexList = option.getOptionByJson('display_index')
indexList = thisdb.getOptionByJson('display_index')
plist = []
for i in indexList:
tmp = i.split('-')
@ -152,30 +151,30 @@ class plugin(object):
def addIndex(self, name, version):
vname = name + '-' + version
indexList = option.getOptionByJson('display_index')
indexList = thisdb.getOptionByJson('display_index',default=[])
if vname in indexList:
return mw.returnData(False, '请不要重复添加!')
if len(indexList) > 12:
return mw.returnData(False, '首页最多只能显示12个软件!')
indexList.append(vname)
option.setOption('display_index', json.dumps(indexList))
thisdb.setOption('display_index', json.dumps(indexList))
return mw.returnData(True, '添加成功!')
def removeIndex(self, name, version):
vname = name + '-' + version
indexList = option.getOptionByJson('display_index')
indexList = thisdb.getOptionByJson('display_index')
if not vname in indexList:
return mw.returnData(True, '删除成功!!')
indexList.remove(vname)
print(indexList)
option.setOption('display_index', json.dumps(indexList))
thisdb.setOption('display_index', json.dumps(indexList))
return mw.returnData(True, '删除成功!')
def hookInstallOption(self, hook_name, info):
hn_name = 'hook_'+hook_name
src_data = option.getOptionByJson(hn_name,type='hook',default=[])
src_data = thisdb.getOptionByJson(hn_name,type='hook',default=[])
isNeedAdd = True
for x in range(len(src_data)):
if src_data[x]['title'] == info['title'] and src_data[x]['name'] == info['name']:
@ -184,17 +183,17 @@ class plugin(object):
if isNeedAdd:
src_data.append(info)
option.setOption(hn_name, json.dumps(src_data), type='hook')
thisdb.setOption(hn_name, json.dumps(src_data), type='hook')
return True
def hookUninstallOption(self, hook_name, info):
hn_name = 'hook_'+hook_name
src_data = option.getOptionByJson(hn_name,type='hook',default=[])
src_data = thisdb.getOptionByJson(hn_name,type='hook',default=[])
for idx in range(len(src_data)):
if src_data[idx]['name'] == info['name']:
src_data.remove(src_data[idx])
break
option.setOption(hn_name, json.dumps(src_data), type='hook')
thisdb.setOption(hn_name, json.dumps(src_data), type='hook')
return True
def hookInstall(self, info):
@ -316,7 +315,7 @@ class plugin(object):
return ''
def checkIndexList(self, name, version):
indexList = option.getOptionByJson('display_index')
indexList = thisdb.getOptionByJson('display_index',default=[])
for i in indexList:
t = i.split('-')
if t[0] == name:
@ -426,15 +425,28 @@ class plugin(object):
return pInfo
def makeCoexistData(self, data):
plugins_t = []
plugins = []
if type(data['versions']) == list and 'coexist' in data and data['coexist']:
data_t = self.makeCoexist(data)
for index in range(len(data_t)):
plugins_t.append(data_t[index])
plugins.append(data_t[index])
else:
pg = self.getPluginInfo(data)
plugins_t.append(pg)
return plugins_t
plugins.append(pg)
return plugins
def makeCoexistDataInstalled(self, data):
plugins = []
if type(data['versions']) == list and 'coexist' in data and data['coexist']:
data_t = self.makeCoexist(data)
for index in range(len(data_t)):
if data_t[index]['setup']:
plugins.append(data_t[index])
else:
pg = self.getPluginInfo(data)
if pg['setup']:
plugins.append(pg)
return plugins
# 对多版本共存进行处理
def makeCoexistList(self, data,
@ -449,12 +461,11 @@ class plugin(object):
if plugin_type == None or plugin_type == '0':
return self.makeCoexistData(data)
# 已经安装
if plugin_type == '-1':
return self.makeCoexistData(data)
if str(plugin_type) == '-1':
return self.makeCoexistDataInstalled(data)
return plugins_t
def getPluginList(self, name,
keyword: str | None = None,
type: str | None = None,

Loading…
Cancel
Save