pull/628/head
Mr Chen 7 months ago
parent dc1458fb2a
commit 94d45b1b07
  1. 1
      .gitignore
  2. 1
      class/core/system_api.py
  3. 2
      plugins/gitea/index.py
  4. 37
      web/admin/__init__.py
  5. 29
      web/admin/dashboard/__init__.py
  6. 19
      web/admin/logs/__init__.py
  7. 91
      web/admin/model/__init__.py
  8. 9
      web/admin/plugins/__init__.py
  9. 11
      web/admin/setup/__init__.py
  10. 39
      web/admin/setup/user.py
  11. 2
      web/admin/submodules.py
  12. 58
      web/admin/system/__init__.py
  13. 3
      web/admin/user_login_check.py
  14. 3
      web/branding.py
  15. 85
      web/core/mw.py
  16. 29
      web/setting.py
  17. 8
      web/templates/default/login.html
  18. 13
      web/utils/__init__.py
  19. 40
      web/utils/mwplugin.py
  20. 292
      web/utils/system/__init__.py
  21. 143
      web/utils/vilidate.py

1
.gitignore vendored

@ -185,3 +185,4 @@ plugins/goedge-node
plugins/goedge-happy
plugins/dztasks
data/default_new.pl

@ -717,7 +717,6 @@ class system_api:
self.cache[iokey] = {'info':diskio_group,'time':mtime}
except Exception as e:
# print(mw.getTracebackInfo())
pass
return diskInfo

@ -220,7 +220,7 @@ def getDbConfValue():
rep_scope = r"\[database\](.*?)\["
tmp = re.findall(rep_scope, content, re.S)
rep = '(\w*)\s*=\s*(.*)'
rep = '(\\w*)\\s*=\\s*(.*)'
tmp = re.findall(rep, tmp[0])
r = {}
for x in range(len(tmp)):

@ -8,7 +8,11 @@
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import sys
import uuid
import logging
from datetime import timedelta
from flask import Flask
from flask_socketio import SocketIO, emit, send
@ -20,6 +24,7 @@ from flask_migrate import Migrate
from werkzeug.local import LocalProxy
from admin.model import db as sys_db
from admin import setup
import core.mw as mw
import setting
@ -33,25 +38,46 @@ socketio = SocketIO(manage_session=False, async_mode='threading',
app = Flask(__name__, template_folder='templates/default')
# app.debug = True
# 静态文件配置
from whitenoise import WhiteNoise
app.wsgi_app = WhiteNoise(app.wsgi_app, root="../web/static/", prefix="static/", max_age=604800)
# session配置
app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:]
# app.config['sessions'] = dict()
app.config['SESSION_PERMANENT'] = True
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'MW_:'
app.config['SESSION_COOKIE_NAME'] = "MW_VER_1"
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=31)
# db的配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+root_dir+'/example.log' # 使用 SQLite 数据库
app.config['SQLALCHEMY_DATABASE_URI'] = mw.getSqitePrefix()+setting.SQLITE_PATH # 使用 SQLite 数据库
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 初始化db
sys_db.init_app(app)
Migrate(app, sys_db)
# 检查数据库是否存在。如果没有就创建它。
setup_db_required = False
if not os.path.isfile(setting.SQLITE_PATH):
setup_db_required = True
# with app.app_context():
# sys_db.create_all()
with app.app_context():
if setup_db_required:
sys_db.create_all()
# 初始化用户信息
with app.app_context():
setup.init_admin_user()
# print(mw.getRunDir())
# print(app.config['SQLALCHEMY_DATABASE_URI'])
# 加载模块
@ -61,6 +87,9 @@ for module in get_submodules():
if app.blueprints.get(module.name) is None:
app.register_blueprint(module)
@app.before_request
def requestCheck():
print("hh")
@app.after_request
def requestAfter(response):
@ -127,6 +156,8 @@ def inject_global_variables():
# return jsonify(result)
# Log the startup
app.logger.info('########################################################')
app.logger.info('Starting %s v%s...', setting.APP_NAME, setting.APP_VERSION)

@ -10,13 +10,38 @@
from flask import Blueprint, render_template
from flask import request,g
blueprint = Blueprint('dashboard', __name__, url_prefix='/', template_folder='../../templates/default')
import core.mw as mw
blueprint = Blueprint('dashboard', __name__, url_prefix='/', template_folder='../../templates')
@blueprint.route('/')
def index():
return render_template('index.html', data = {})
return render_template('default/index.html', data = {})
# ---------------------------------------------------------------------------------
# 定义登录入口相关方法
# ---------------------------------------------------------------------------------
@blueprint.route('/login')
def login():
return render_template('default/login.html', data = {})
# 检查是否登录
@blueprint.route('/check_login',methods=['GET','POST'])
def check_login():
return "0"
# 执行登录操作
@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()
print(g)
print(username, password, code )
return mw.returnData(False, '面板已经关闭!')

@ -11,7 +11,22 @@
from flask import Blueprint, render_template
blueprint = Blueprint('logs', __name__, url_prefix='/logs', template_folder='../../templates/default')
from admin.user_login_check import panel_login_required
blueprint = Blueprint('logs', __name__, url_prefix='/logs', template_folder='../../templates')
@blueprint.route('/index', endpoint='index')
def index():
return render_template('logs.html', data={})
return render_template('default/logs.html', data={})
# 日志列表
@blueprint.route('/get_log_list', endpoint='get_log_list', methods=['POST'])
@panel_login_required
def get_log_list():
return []
# 审计日志列表
@blueprint.route('/get_audit_logs_files', endpoint='get_audit_logs_files', methods=['POST'])
@panel_login_required
def get_audit_logs_files():
return []

@ -42,11 +42,12 @@ class Option(db.Model):
__tablename__ = 'option'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
name = db.Column(db.String(128), unique=True, nullable=False, comment="配置名称")
type = db.Column(db.String(50), unique=False, nullable=False, default='common',comment="计划类型:common/hook/web")
value = db.Column(db.TEXT, unique=False, nullable=False, comment="内容")
class User(db.Model):
class Users(db.Model):
"""定义登录用户"""
__tablename__ = 'user'
__tablename__ = 'users'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
name = db.Column(db.String(128), unique=True, nullable=False, comment="用户名")
password = db.Column(db.String(128), unique=False, nullable=False, comment="密码")
@ -54,6 +55,8 @@ class User(db.Model):
login_time = db.Column(db.String(128), unique=False, nullable=True, comment="登录时间")
phone = db.Column(db.String(20), unique=False, nullable=False,comment="手机")
email = db.Column(db.String(320), nullable=False, comment="邮件")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
update_time = db.Column(db.TEXT, nullable=False, comment="更新时间")
class Crontab(db.Model):
"""定义计划任务"""
@ -73,7 +76,7 @@ class Crontab(db.Model):
save = db.Column(db.Integer, unique=False, nullable=True, default=3,comment="备份数量")
status = db.Column(db.Integer, unique=False, nullable=True, default=1, comment="状态")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
update_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
update_time = db.Column(db.TEXT, nullable=False, comment="更新时间")
class Logs(db.Model):
"""定义日志"""
@ -88,8 +91,8 @@ class Firewall(db.Model):
"""定义防火墙"""
__tablename__ = 'firewall'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
port = db.Column(db.Integer(), unique=True, nullable=False, comment="端口")
protocol = db.Column(db.Integer(), unique=True, nullable=False, comment="协议/tcp/udp")
port = db.Column(db.Integer(), unique=False, nullable=False, comment="端口")
protocol = db.Column(db.Integer(), unique=False, nullable=False, comment="协议/tcp/udp")
ps = db.Column(db.TEXT, unique=False, nullable=False, comment="备注")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
update_time = db.Column(db.TEXT, nullable=False, comment="更新时间")
@ -106,6 +109,84 @@ class Backup(db.Model):
size = db.Column(db.Integer(), unique=False, nullable=False, comment="大小")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
class Sites(db.Model):
"""定义计划任务"""
__tablename__ = 'sites'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
name = db.Column(db.TEXT, unique=False, nullable=False, comment="网站名称")
path = db.Column(db.TEXT, unique=False, nullable=False, comment="网站路径")
index = db.Column(db.TEXT, unique=False, nullable=False, comment="")
ps = db.Column(db.TEXT, unique=False, nullable=False, comment="备注")
edate = db.Column(db.TEXT, unique=False, nullable=False, comment="到期时间")
type_id = db.Column(db.TEXT, unique=False, nullable=False, comment="分类ID")
status = db.Column(db.Integer(), unique=False, nullable=True, default=1, comment="状态")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
update_time = db.Column(db.TEXT, nullable=False, comment="更新时间")
class SiteType(db.Model):
"""定义站点类型"""
__tablename__ = 'site_type'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
name = db.Column(db.TEXT, unique=False, nullable=False, comment="类型名称")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
update_time = db.Column(db.TEXT, nullable=False, comment="更新时间")
class Domain(db.Model):
"""定义站点域名"""
__tablename__ = 'domain'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
pid = db.Column(db.Integer(), unique=False, nullable=False, comment="站点ID")
name = db.Column(db.TEXT, unique=False, nullable=False, comment="域名")
port = db.Column(db.Integer(), unique=False, nullable=False, comment="端口")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
class Binding(db.Model):
"""定义站点绑定"""
__tablename__ = 'binding'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
pid = db.Column(db.Integer(), unique=False, nullable=False, comment="站点ID")
domain = db.Column(db.TEXT, unique=False, nullable=False, comment="域名")
path = db.Column(db.TEXT, unique=False, nullable=False, comment="路径")
port = db.Column(db.Integer(), unique=False, nullable=False, comment="端口")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
class Tasks(db.Model):
"""定义任务"""
__tablename__ = 'tasks'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
name = db.Column(db.TEXT, unique=False, nullable=False, comment="任务名称")
type = db.Column(db.TEXT, unique=False, nullable=False, comment="域名")
execstr = db.Column(db.TEXT, unique=False, nullable=False, comment="返回内容")
start = db.Column(db.Integer(), unique=False, nullable=True, comment="开始执行时间")
end = db.Column(db.Integer(), unique=False, nullable=True, comment="结束执行时间")
status = db.Column(db.Integer(), unique=False, nullable=True, default=1, comment="状态")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
class TempLogin(db.Model):
"""定义临时登录"""
__tablename__ = 'temp_login'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
token = db.Column(db.TEXT, unique=False, nullable=False, comment="token")
salt = db.Column(db.TEXT, unique=False, nullable=False, comment="salt")
state = db.Column(db.Integer(), unique=False, nullable=False, comment="状态")
login_time = db.Column(db.Integer(), unique=False, nullable=True, comment="登录时间")
login_addr = db.Column(db.Integer(), unique=False, nullable=True, comment="登录地址")
logout_time = db.Column(db.Integer(), unique=False, nullable=True, comment="登出时间")
expire = db.Column(db.Integer(), unique=False, nullable=True, comment="过期时间")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")
class Panel(db.Model):
"""定义其他面板"""
__tablename__ = 'panel'
id = db.Column(db.Integer(), primary_key=True,autoincrement=True, comment="ID")
title = db.Column(db.TEXT, unique=False, nullable=False, comment="标题")
url = db.Column(db.TEXT, unique=False, nullable=False, comment="地址")
username = db.Column(db.Integer(), unique=False, nullable=False, comment="用户名")
password = db.Column(db.Integer(), unique=False, nullable=True, comment="密码")
click = db.Column(db.Integer(), unique=False, nullable=True, comment="点击次数")
add_time = db.Column(db.TEXT, nullable=False, comment="添加时间")

@ -28,6 +28,7 @@ def index():
# 初始化检查,首页提示选择安装
@blueprint.route('/init', endpoint='init', methods=['POST'])
@panel_login_required
def init():
plugin_names = {
'openresty': '1.25.3',
@ -38,6 +39,13 @@ def init():
}
return []
# 首页软件展示
@blueprint.route('/index_list', endpoint='index_list', methods=['GET','POST'])
@panel_login_required
def index_list():
pg = MwPlugin.instance()
return pg.getIndexList()
# 插件列表
@blueprint.route('/list', endpoint='list', methods=['GET'])
@panel_login_required
@ -102,7 +110,6 @@ def run():
pg = MwPlugin.instance()
data = pg.run(name, func, version, args, script)
if data[1] == '':
r = mw.returnData(True, "OK", data[0].strip())
else:

@ -0,0 +1,11 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
from .user import *

@ -0,0 +1,39 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
from flask import request
from admin.model import db, Users
import core.mw as mw
# 初始化用户信息
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_new.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()
return True

@ -20,6 +20,7 @@ from .plugins import blueprint as PluginsModule
from .crontab import blueprint as CrontabModule
from .firewall import blueprint as FirewallModule
from .control import blueprint as ControlModule
from .system import blueprint as SystemModule
def get_submodules():
return [
@ -33,5 +34,6 @@ def get_submodules():
CrontabModule,
FirewallModule,
ControlModule,
SystemModule,
ConfigModule,
]

@ -0,0 +1,58 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
from flask import Blueprint, render_template
from flask import request
import core.mw as mw
import utils.system as sys
blueprint = Blueprint('system', __name__, url_prefix='/system', template_folder='../../templates')
# 取系统的统计信息
@blueprint.route('/system_total', endpoint='system_total')
def system_total():
data = sys.getMemInfo()
cpu = sys.getCpuInfo(interval=1)
data['cpuNum'] = cpu[1]
data['cpuRealUsed'] = cpu[0]
data['time'] = sys.getBootTime()
data['system'] = sys.getSystemVersion()
data['version'] = '0.0.1'
return data
# 取系统的网络流量信息
@blueprint.route('/network', endpoint='network')
def network():
stat = {}
stat['cpu'] = sys.getCpuInfo()
stat['load'] = sys.getLoadAverage()
stat['mem'] = sys.getMemInfo()
stat['iostat'] = sys.stats().disk()
stat['network'] = sys.stats().network()
return stat
# 取系统的磁盘信息
@blueprint.route('/disk_info', endpoint='disk_info')
def disk_info():
data = sys.getDiskInfo()
return data
# 升级检测
@blueprint.route('/update_server', endpoint='update_server')
def update_server():
panel_type = request.args.get('type', 'check')
version = request.args.get('version', '')
return mw.returnData(False, '已经是最新,无需更新!')

@ -12,9 +12,8 @@ from functools import wraps
def panel_login_required(func):
print('panel_login_required',func)
@wraps(func)
def wrapper(*args, **kwargs):
print('panel_login_required', args, kwargs)
return func(*args, **kwargs)
return wrapper

@ -14,5 +14,8 @@
APP_NAME = 'mdserver-web'
APP_ICON = 'icon'
APP_LOG_NAME = 'panel'
APP_SQLITE_NAME = 'panel'
# Copyright string for display in the app
APP_COPYRIGHT = 'Copyright (C) 2018-∞ All rights reserved.'

@ -116,11 +116,11 @@ def getUniqueId():
return unique_id
def returnData(status, msg, data=None):
if data == None:
return {'status': status, 'msg': msg}
return {'status': status, 'msg': msg, 'data': data}
def returnJson(status, msg, data=None):
if data == None:
return getJson({'status': status, 'msg': msg})
return getJson({'status': status, 'msg': msg, 'data': data})
def readFile(filename):
@ -163,6 +163,52 @@ def systemdCfgDir():
# local test
return "/tmp"
def formatDate(format="%Y-%m-%d %H:%M:%S", times=None):
# 格式化指定时间戳
if not times:
times = int(time.time())
time_local = time.localtime(times)
return time.strftime(format, time_local)
def strfToTime(sdate):
# 转换时间
import time
return time.strftime('%Y-%m-%d', time.strptime(sdate, '%b %d %H:%M:%S %Y %Z'))
def md5(content):
# 生成MD5
try:
m = hashlib.md5()
m.update(content.encode("utf-8"))
return m.hexdigest()
except Exception as ex:
return False
def getFileMd5(filename):
# 文件的MD5值
if not os.path.isfile(filename):
return False
myhash = hashlib.md5()
f = file(filename, 'rb')
while True:
b = f.read(8096)
if not b:
break
myhash.update(b)
f.close()
return myhash.hexdigest()
def getClientIp():
from flask import request
return request.remote_addr.replace('::ffff:', '')
def getJson(data):
import json
return json.dumps(data)
@ -240,6 +286,41 @@ def getSqitePrefix():
prefix = 'sqlite:////'
return prefix
def getCpuType():
cpuType = ''
if isAppleSystem():
cmd = "system_profiler SPHardwareDataType | grep 'Processor Name' | awk -F ':' '{print $2}'"
cpuinfo = execShell(cmd)
return cpuinfo[0].strip()
current_os = getOs()
if current_os.startswith('freebsd'):
cmd = "sysctl -a | egrep -i 'hw.model' | awk -F ':' '{print $2}'"
cpuinfo = execShell(cmd)
return cpuinfo[0].strip()
# 取CPU类型
cpuinfo = open('/proc/cpuinfo', 'r').read()
rep = "model\\s+name\\s+:\\s+(.+)"
tmp = re.search(rep, cpuinfo, re.I)
if tmp:
cpuType = tmp.groups()[0]
else:
cpuinfo = execShell('LANG="en_US.UTF-8" && lscpu')[0]
rep = "Model\\s+name:\\s+(.+)"
tmp = re.search(rep, cpuinfo, re.I)
if tmp:
cpuType = tmp.groups()[0]
return cpuType
def getInfo(msg, args=()):
# 取提示消息
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i])
return msg
def getLastLine(path, num, p=1):
pyVersion = sys.version_info[0]
try:

@ -18,7 +18,9 @@ import logging
import os
import sys
from branding import APP_NAME, APP_ICON, APP_COPYRIGHT
import core.mw as mw
from branding import APP_NAME, APP_ICON, APP_COPYRIGHT, APP_LOG_NAME, APP_SQLITE_NAME
from version import APP_VERSION, APP_RELEASE, APP_REVISION, APP_SUFFIX
DEBUG = False
@ -28,6 +30,31 @@ CONFIG_DATABASE_CONNECTION_POOL_SIZE = 5
# 允许溢出超过连接池大小的连接数
CONFIG_DATABASE_CONNECTION_MAX_OVERFLOW = 100
# 应用程序日志级别-其中之一:
# CRITICAL 50
# ERROR 40
# WARNING 30
# SQL 25
# INFO 20
# DEBUG 10
# NOTSET 0
CONSOLE_LOG_LEVEL = logging.WARNING
FILE_LOG_LEVEL = logging.WARNING
DATA_DIR = mw.getPanelDataDir()
# 日志文件名。这将进入数据目录,服务器模式下的非Windows平台除外。
LOG_FILE = os.path.join(mw.getMWLogs(), APP_LOG_NAME + '.log')
# 日志旋转设置日志文件将根据LOG_ROTATION_SIZE和LOG_ROTATION_AGE的值进行切换。
# 旋转的文件将以格式命名Y-m-d_H-M-S
LOG_ROTATION_SIZE = 10 # MBs
LOG_ROTATION_AGE = 1440 # minutes
LOG_ROTATION_MAX_LOG_FILES = 90 # 要保留的最大备份数
# 用于存储用户帐户和设置的SQLite数据库的默认路径。
# 此默认设置将文件放置在与此相同的目录中 配置文件,但会生成一个在整个应用程序中使用的绝对路径。
SQLITE_PATH = os.path.join(DATA_DIR, APP_SQLITE_NAME + '.db')
DEFAULT_SERVER = '127.0.0.1'

@ -135,7 +135,7 @@
<form class="loginform" method="post" action="/login" onsubmit="return false;">
<div class="rlogo">{{data['title']}}</div>
<div class="line">
<input class="inputtxt" value="" name="username" datatype="*" nullmsg="请填写账户" errormsg="请填写账户" placeholder="账户" type="text">
<input class="inputtxt" value="" name="username" datatype="*" nullmsg="请填写账户" errormsg="请填写账户" placeholder="账户" type="text" autocomplete="on">
<div class="Validform_checktip"></div>
</div>
<div class="line"><input class="inputtxt" name="password" value="" datatype="*" nullmsg="请填写密码" errormsg="请填写密码" placeholder="密码" type="password">
@ -145,7 +145,7 @@
<div class="line yzm" style="top: -5px;{% if not session['code'] %}display:none;{% endif %}">
<input type="text" class="inputtxt" name="code" nullmsg="请填写4位验证码" errormsg="验证码" datatype="*" placeholder="验证码">
<div class="Validform_checktip"></div>
<div id='mw_yzm'>{% if session['code'] %}<img width="100" height="40" class="passcode" onClick="this.src=this.src.split('?')[0] + '?'+new Date().getTime()" src="/code" style="border: 1px solid #ccc; float: right;" title="" >{% endif %}</div>
<div id='mw_yzm'>{% if session['code'] %}<img width="100" height="40" class="passcode" onclick="this.src=this.src.split('?')[0] + '?'+new Date().getTime()" src="/code" style="border: 1px solid #ccc; float: right;" title="" >{% endif %}</div>
</div>
<div class="login_btn"><input id="login-button" value="登录" type="submit"></div>
<p class="pwinfo" style="display:none"></p>
@ -205,9 +205,9 @@ $('#login-button').click(function(){
var data = 'username='+username+'&password='+password+'&code='+code;
var loadT = layer.msg("正在登录中...",{icon:16,time:0,shade: [0.3, '#000']});
$.post('/do_login',data,function(rdata){
console.log(rdata);
console.log('do_login',rdata);
layer.close(loadT);
if(status < 0){
if(!rdata.status || rdata.status < 0){
if(username == 'admin' && rdata.msg.indexOf('用户名') != -1){
rdata.msg += ', <br>获取默认用户和密码命令: mw default';
}

@ -0,0 +1,13 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
IS_WIN = (os.name == 'nt')

@ -104,6 +104,46 @@ class MwPlugin(object):
mw.writeFile(self.__index, '[]')
self.__index_data = json.loads(mw.readFile(self.__index))
def getIndexList(self):
if not os.path.exists(self.__index):
mw.writeFile(self.__index, '[]')
indexList = json.loads(mw.readFile(self.__index))
plist = []
for i in indexList:
tmp = i.split('-')
tmp_len = len(tmp)
plugin_name = tmp[0]
plugin_ver = tmp[1]
if tmp_len > 2:
tmpArr = tmp[0:tmp_len - 1]
plugin_name = '-'.join(tmpArr)
plugin_ver = tmp[tmp_len - 1]
read_json_file = self.__plugin_dir + '/' + plugin_name + '/info.json'
if os.path.exists(read_json_file):
content = mw.readFile(read_json_file)
try:
data = json.loads(content)
data = self.makeCoexistList(data)
for index in range(len(data)):
if data[index]['coexist']:
if data[index]['versions'] == plugin_ver or plugin_ver in data[index]['versions']:
data[index]['display'] = True
plist.append(data[index])
continue
else:
data[index]['display'] = True
plist.append(data[index])
except Exception as e:
print('getIndexList:', mw.getTracebackInfo())
# 使用gevent模式时,无法使用多进程
# plist = self.checkStatusMProcess(plist)
plist = self.checkStatusMThreads(plist)
return plist
# 插件搜索匹配
def searchKey(self, info,
keyword: str | None = None,

@ -0,0 +1,292 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import sys
import time
import math
import psutil
import core.mw as mw
def getDiskInfo():
# 取磁盘分区信息
temp = mw.execShell("df -h -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
tempInodes = mw.execShell("df -i -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
temp1 = temp.split('\n')
tempInodes1 = tempInodes.split('\n')
diskInfo = []
n = 0
cuts = ['/mnt/cdrom', '/boot', '/boot/efi', '/dev',
'/dev/shm', '/zroot', '/run/lock', '/run', '/run/shm', '/run/user']
for tmp in temp1:
n += 1
inodes = tempInodes1[n - 1].split()
disk = tmp.split()
if len(disk) < 5:
continue
if disk[1].find('M') != -1:
continue
if disk[1].find('K') != -1:
continue
if len(disk[5].split('/')) > 4:
continue
if disk[5] in cuts:
continue
arr = {}
arr['path'] = disk[5]
tmp1 = [disk[1], disk[2], disk[3], disk[4]]
arr['size'] = tmp1
arr['inodes'] = [inodes[1], inodes[2], inodes[3], inodes[4]]
diskInfo.append(arr)
return diskInfo
class stats:
cache = {}
# 磁盘统计
def disk(self):
iokey = 'disk_stat'
diskInfo = {}
diskInfo['ALL'] = {}
diskInfo['ALL']['read_count'] = 0
diskInfo['ALL']['write_count'] = 0
diskInfo['ALL']['read_bytes'] = 0
diskInfo['ALL']['write_bytes'] = 0
diskInfo['ALL']['read_time'] = 0
diskInfo['ALL']['write_time'] = 0
diskInfo['ALL']['read_merged_count'] = 0
diskInfo['ALL']['write_merged_count'] = 0
try:
diskio = None
if iokey in self.cache:
diskio = self.cache[iokey]
mtime = int(time.time())
if not diskio:
diskio = {}
diskio['info'] = None
diskio['time'] = mtime
diskio_cache = diskio['info']
stime = mtime - diskio['time']
if not stime: stime = 1
diskio_group = psutil.disk_io_counters(perdisk=True)
if not diskio_cache:
diskio_cache = diskio_group
for disk_name in diskio_group.keys():
diskInfo[disk_name] = {}
# print('disk_name',disk_name)
# print(diskio_group[disk_name].write_time , diskio_cache[disk_name].write_time)
# print(diskio_group[disk_name].write_count , diskio_cache[disk_name].write_count)
diskInfo[disk_name]['read_count'] = int((diskio_group[disk_name].read_count - diskio_cache[disk_name].read_count) / stime)
diskInfo[disk_name]['write_count'] = int((diskio_group[disk_name].write_count - diskio_cache[disk_name].write_count) / stime)
diskInfo[disk_name]['read_bytes'] = int((diskio_group[disk_name].read_bytes - diskio_cache[disk_name].read_bytes) / stime)
diskInfo[disk_name]['write_bytes'] = int((diskio_group[disk_name].write_bytes - diskio_cache[disk_name].write_bytes) / stime)
diskInfo[disk_name]['read_time'] = int((diskio_group[disk_name].read_time - diskio_cache[disk_name].read_time) / stime)
diskInfo[disk_name]['write_time'] = int((diskio_group[disk_name].write_time - diskio_cache[disk_name].write_time) / stime)
if 'read_merged_count' in diskio_group[disk_name] and 'read_merged_count' in diskio_cache[disk_name]:
diskInfo[disk_name]['read_merged_count'] = int((diskio_group[disk_name].read_merged_count - diskio_cache[disk_name].read_merged_count) / stime)
if 'write_merged_count' in diskio_group[disk_name] and 'write_merged_count' in diskio_cache[disk_name]:
diskInfo[disk_name]['write_merged_count'] = int((diskio_group[disk_name].write_merged_count - diskio_cache[disk_name].write_merged_count) / stime)
diskInfo['ALL']['read_count'] += diskInfo[disk_name]['read_count']
diskInfo['ALL']['write_count'] += diskInfo[disk_name]['write_count']
diskInfo['ALL']['read_bytes'] += diskInfo[disk_name]['read_bytes']
diskInfo['ALL']['write_bytes'] += diskInfo[disk_name]['write_bytes']
if diskInfo['ALL']['read_time'] < diskInfo[disk_name]['read_time']:
diskInfo['ALL']['read_time'] = diskInfo[disk_name]['read_time']
if diskInfo['ALL']['write_time'] < diskInfo[disk_name]['write_time']:
diskInfo['ALL']['write_time'] = diskInfo[disk_name]['write_time']
if 'read_merged_count' in diskInfo[disk_name] and 'read_merged_count' in diskInfo[disk_name]:
diskInfo['ALL']['read_merged_count'] += diskInfo[disk_name]['read_merged_count']
if 'write_merged_count' in diskInfo[disk_name] and 'write_merged_count' in diskInfo[disk_name]:
diskInfo['ALL']['write_merged_count'] += diskInfo[disk_name]['write_merged_count']
self.cache[iokey] = {'info':diskio_group,'time':mtime}
except Exception as e:
pass
return diskInfo
# 网络统计
def network(self):
netInfo = {}
netInfo['ALL'] = {}
netInfo['ALL']['up'] = 0
netInfo['ALL']['down'] = 0
netInfo['ALL']['upTotal'] = 0
netInfo['ALL']['downTotal'] = 0
netInfo['ALL']['upPackets'] = 0
netInfo['ALL']['downPackets'] = 0
mtime = time.time()
iokey = 'net_stat'
netio = None
if iokey in self.cache:
netio = self.cache[iokey]
if not netio:
netio = {}
netio['info'] = None
netio['all_io'] = None
netio['time'] = mtime
stime = mtime - netio['time']
if not stime: stime = 1
# print("new:",stime)
netio_group = psutil.net_io_counters(pernic=True).keys()
netio_cache = netio['info']
allio_cache = netio['all_io']
if not netio_cache:
netio_cache = {}
netio_group_t = {}
for name in netio_group:
netInfo[name] = {}
io_data = psutil.net_io_counters(pernic=True).get(name)
if not name in netio_cache:
netio_cache[name] = io_data
netio_group_t[name] = io_data
netInfo[name]['up'] = round(float((io_data[0] - netio_cache[name][0]) / stime), 2)
netInfo[name]['down'] = round(float((io_data[1] - netio_cache[name][1])/ stime), 2)
netInfo[name]['upTotal'] = io_data[0]
netInfo[name]['downTotal'] = io_data[1]
netInfo[name]['upPackets'] = io_data[2]
netInfo[name]['downPackets'] = io_data[3]
all_io = psutil.net_io_counters()[:4]
if not allio_cache:
allio_cache = all_io
netInfo['ALL']['up'] = round(float((all_io[0] - allio_cache[0]) /stime), 2)
netInfo['ALL']['down'] = round(float((all_io[1] - allio_cache[1]) /stime), 2)
netInfo['ALL']['upTotal'] = all_io[0]
netInfo['ALL']['downTotal'] = all_io[1]
netInfo['ALL']['upPackets'] = all_io[2]
netInfo['ALL']['downPackets'] = all_io[3]
self.cache[iokey] = {'info':netio_group_t,'all_io':all_io,'time':mtime}
return netInfo
def getLoadAverage():
c = os.getloadavg()
data = {}
data['one'] = round(float(c[0]), 2)
data['five'] = round(float(c[1]), 2)
data['fifteen'] = round(float(c[2]), 2)
data['max'] = psutil.cpu_count() * 2
data['limit'] = data['max']
data['safe'] = data['max'] * 0.75
return data
def getSystemVersion():
# 取操作系统版本
current_os = mw.getOs()
# sys_temper = self.getSystemDeviceTemperature()
# print(sys_temper)
# mac
if current_os == 'darwin':
data = mw.execShell('sw_vers')[0]
data_list = data.strip().split("\n")
mac_version = ''
for x in data_list:
xlist = x.split("\t")
mac_version += xlist[len(xlist)-1] + ' '
arch_ver = mw.execShell("arch")
return mac_version + " (" + arch_ver[0].strip() + ")"
# freebsd
if current_os.startswith('freebsd'):
version = mw.execShell(
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
arch_ver = mw.execShell(
"sysctl -a | egrep -i 'hw.machine_arch' | awk -F ':' '{print $2}'")
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
redhat_series = '/etc/redhat-release'
if os.path.exists(redhat_series):
version = mw.readFile('/etc/redhat-release')
version = version.replace('release ', '').strip()
arch_ver = mw.execShell("arch")
return version + " (" + arch_ver[0].strip() + ")"
os_series = '/etc/os-release'
if os.path.exists(os_series):
version = mw.execShell(
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
arch_ver = mw.execShell("arch")
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
def getBootTime():
# 取系统启动时间
uptime = mw.readFile('/proc/uptime')
if uptime == False:
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
days = math.floor(hours / 24)
hours = math.floor(hours - (days * 24))
min = math.floor(min - (days * 60 * 24) - (hours * 60))
return mw.getInfo('已不间断运行: {1}{2}小时{3}分钟', (str(int(days)), str(int(hours)), str(int(min))))
def getCpuInfo(interval=1):
# 取CPU信息
cpuCount = psutil.cpu_count()
cpuLogicalNum = psutil.cpu_count(logical=False)
used = psutil.cpu_percent(interval=interval)
cpuLogicalNum = 0
if os.path.exists('/proc/cpuinfo'):
c_tmp = mw.readFile('/proc/cpuinfo')
d_tmp = re.findall("physical id.+", c_tmp)
cpuLogicalNum = len(set(d_tmp))
used_all = psutil.cpu_percent(percpu=True)
cpu_name = mw.getCpuType() + " * {}".format(cpuLogicalNum)
return used, cpuCount, used_all, cpu_name, cpuCount, cpuLogicalNum
def getMemInfo():
# 取内存信息
mem = psutil.virtual_memory()
if sys.platform == 'darwin':
memInfo = {'memTotal': mem.total}
memInfo['memRealUsed'] = memInfo['memTotal'] * (mem.percent / 100)
else:
memInfo = {
'memTotal': mem.total,
'memFree': mem.free,
'memBuffers': mem.buffers,
'memCached': mem.cached
}
memInfo['memRealUsed'] = memInfo['memTotal'] - memInfo['memFree'] - memInfo['memBuffers'] - memInfo['memCached']
return memInfo

@ -0,0 +1,143 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 验证码操作
# ---------------------------------------------------------------------------------
import random
import math
from PIL import Image, ImageDraw, ImageFont, ImageFilter
class vieCode:
__fontSize = 20 # 字体大小
__width = 120 # 画布宽度
__heigth = 45 # 画布高度
__length = 4 # 验证码长度
__draw = None # 画布
__img = None # 图片资源
__code = None # 验证码字符
__str = None # 自定义验证码字符集
__inCurve = True # 是否画干扰线
__inNoise = True # 是否画干扰点
__type = 2 # 验证码类型 1、纯字母 2、数字字母混合
__fontPatn = 'class/fonts/2.ttf' # 字体
def GetCodeImage(self, size=80, length=4):
'''获取验证码图片
@param int size 验证码大小
@param int length 验证码长度
'''
# 准备基础数据
self.__length = length
self.__fontSize = size
self.__width = self.__fontSize * self.__length
self.__heigth = int(self.__fontSize * 1.5)
# 生成验证码图片
self.__createCode()
self.__createImage()
self.__createNoise()
self.__printString()
self.__cerateFilter()
return self.__img, self.__code
def __cerateFilter(self):
'''模糊处理'''
self.__img = self.__img.filter(ImageFilter.BLUR)
filter = ImageFilter.ModeFilter(8)
self.__img = self.__img.filter(filter)
def __createCode(self):
'''创建验证码字符'''
# 是否自定义字符集合
if not self.__str:
# 源文本
number = "3456789"
srcLetter = "qwertyuipasdfghjkzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
srcUpper = srcLetter.upper()
if self.__type == 1:
self.__str = number
else:
self.__str = srcLetter + srcUpper + number
# 构造验证码
self.__code = random.sample(self.__str, self.__length)
def __createImage(self):
'''创建画布'''
bgColor = (random.randint(200, 255), random.randint(
200, 255), random.randint(200, 255))
self.__img = Image.new('RGB', (self.__width, self.__heigth), bgColor)
self.__draw = ImageDraw.Draw(self.__img)
def __createNoise(self):
'''画干扰点'''
if not self.__inNoise:
return
font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5))
for i in range(5):
# 杂点颜色
noiseColor = (random.randint(150, 200), random.randint(
150, 200), random.randint(150, 200))
putStr = random.sample(self.__str, 2)
for j in range(2):
# 绘杂点
size = (random.randint(-10, self.__width),
random.randint(-10, self.__heigth))
self.__draw.text(size, putStr[j], font=font, fill=noiseColor)
pass
def __createCurve(self):
'''画干扰线'''
if not self.__inCurve:
return
x = y = 0
# 计算曲线系数
a = random.uniform(1, self.__heigth / 2)
b = random.uniform(-self.__width / 4, self.__heigth / 4)
f = random.uniform(-self.__heigth / 4, self.__heigth / 4)
t = random.uniform(self.__heigth, self.__width * 2)
xend = random.randint(self.__width / 2, self.__width * 2)
w = (2 * math.pi) / t
# 画曲线
color = (random.randint(30, 150), random.randint(
30, 150), random.randint(30, 150))
for x in range(xend):
if w != 0:
for k in range(int(self.__heigth / 10)):
y = a * math.sin(w * x + f) + b + self.__heigth / 2
i = int(self.__fontSize / 5)
while i > 0:
px = x + i
py = y + i + k
self.__draw.point((px, py), color)
i -= i
def __printString(self):
'''打印验证码字符串'''
font = ImageFont.truetype(self.__fontPatn, self.__fontSize)
x = 0
# 打印字符到画板
for i in range(self.__length):
# 设置字体随机颜色
color = (random.randint(30, 150), random.randint(
30, 150), random.randint(30, 150))
# 计算座标
x = random.uniform(self.__fontSize * i * 0.95,
self.__fontSize * i * 1.1)
y = self.__fontSize * random.uniform(0.3, 0.5)
# 打印字符
self.__draw.text((x, y), self.__code[i], font=font, fill=color)
Loading…
Cancel
Save