diff --git a/plugins/xui/conf/mt.toml b/plugins/xui/conf/mt.toml new file mode 100644 index 000000000..495d45a3e --- /dev/null +++ b/plugins/xui/conf/mt.toml @@ -0,0 +1,23 @@ +debug = false + +secret = "{$SECRET}" +bind-to = "0.0.0.0:{$PORT}" + +concurrency = 256 +prefer-ip = "prefer-ipv4" +domain-fronting-port = 443 +tolerate-time-skewness = "10s" + +[network] +doh-ip = "9.9.9.9" + +[network.timeout] +tcp = "5s" +http = "10s" +idle = "1m" + +[defense.anti-replay] +enabled = true +max-size = "1mib" +error-rate = 0.001 + diff --git a/plugins/xui/ico.png b/plugins/xui/ico.png new file mode 100644 index 000000000..b7f2362c5 Binary files /dev/null and b/plugins/xui/ico.png differ diff --git a/plugins/xui/index.html b/plugins/xui/index.html new file mode 100755 index 000000000..9d1fe8f8a --- /dev/null +++ b/plugins/xui/index.html @@ -0,0 +1,23 @@ +
+
+
+

服务

+

自启动

+

常用功能

+

配置修改

+

配置文件

+
+
+
+
+
+
+ \ No newline at end of file diff --git a/plugins/xui/index.py b/plugins/xui/index.py new file mode 100755 index 000000000..15e476d70 --- /dev/null +++ b/plugins/xui/index.py @@ -0,0 +1,257 @@ +# coding:utf-8 + +import sys +import io +import os +import time +import re + +web_dir = os.getcwd() + "/web" +if os.path.exists(web_dir): + sys.path.append(web_dir) + os.chdir(web_dir) + +import core.mw as mw + +app_debug = False +if mw.isAppleSystem(): + app_debug = True + + +def getPluginName(): + return 'xui' + + +def getPluginDir(): + return mw.getPluginDir() + '/' + getPluginName() + + +def getServerDir(): + return mw.getServerDir() + '/' + getPluginName() + + +def getServiceTpl(): + path = getPluginDir() + "/init.d/" + getPluginName() + ".service.tpl" + return path + + +def getConfEnvTpl(): + path = getPluginDir() + "/conf/mt.toml" + return path + + +def getConfEnv(): + path = getServerDir() + "/mt.toml" + return path + + +def getArgs(): + args = sys.argv[2:] + tmp = {} + args_len = len(args) + + if args_len == 1: + t = args[0].strip('{').strip('}') + t = t.split(':') + tmp[t[0]] = t[1] + elif args_len > 1: + for i in range(len(args)): + t = args[i].split(':') + tmp[t[0]] = t[1] + + return tmp + +def status(): + cmd = "ps -ef|grep mtproxy| grep mtg |grep -v grep | grep -v python | awk '{print $2}'" + data = mw.execShell(cmd) + if data[0] == '': + return 'stop' + return 'start' + + +def getServiceFile(): + systemDir = mw.systemdCfgDir() + return systemDir + '/mtproxy.service' + + +def getMtproxyPort(): + return '8349' + + +def __release_port(port): + from collections import namedtuple + try: + from utils.firewall import Firewall as MwFirewall + MwFirewall.instance().addAcceptPort(port, 'mtproxy', 'port') + return port + except Exception as e: + return "Release failed {}".format(e) + +def __delete_port(port): + from collections import namedtuple + try: + from utils.firewall import Firewall as MwFirewall + MwFirewall.instance().delAcceptPortCmd(port, 'tcp') + return port + except Exception as e: + return "Delete failed {}".format(e) + +def openPort(): + port = getMtproxyPort() + for i in [port]: + __release_port(i) + return True + +def delPort(): + port = getMtproxyPort() + for i in [port]: + __delete_port(i) + return True + + +def initDreplace(): + + envTpl = getConfEnvTpl() + dstEnv = getConfEnv() + cmd = getServerDir() + '/mtg/mtg generate-secret `head -c 16 /dev/urandom | xxd -ps`' + secret = mw.execShell(cmd) + if not os.path.exists(dstEnv): + env_content = mw.readFile(envTpl) + env_content = env_content.replace('{$PORT}', getMtproxyPort()) + env_content = env_content.replace('{$SECRET}', secret[0].strip()) + mw.writeFile(dstEnv, env_content) + openPort() + + # systemd + systemDir = mw.systemdCfgDir() + systemService = systemDir + '/mtproxy.service' + systemServiceTpl = getServiceTpl() + if os.path.exists(systemDir) and not os.path.exists(systemService): + service_path = mw.getServerDir() + se_content = mw.readFile(systemServiceTpl) + se_content = se_content.replace('{$SERVER_PATH}', service_path) + mw.writeFile(systemService, se_content) + mw.execShell('systemctl daemon-reload') + + return 'ok' + + +def mtOp(method): + file = initDreplace() + + if not mw.isAppleSystem(): + mw.execShell('systemctl daemon-reload') + data = mw.execShell('systemctl ' + method + ' mtproxy') + if data[1] == '': + return 'ok' + return data[1] + + return 'fail' + + +def start(): + return mtOp('start') + + +def stop(): + return mtOp('stop') + + +def restart(): + return mtOp('restart') + + +def reload(): + return redisOp('reload') + + +def initdStatus(): + if mw.isAppleSystem(): + return "Apple Computer does not support" + + shell_cmd = 'systemctl status mtproxy | grep loaded | grep "enabled;"' + data = mw.execShell(shell_cmd) + if data[0] == '': + return 'fail' + return 'ok' + +def initdInstall(): + if mw.isAppleSystem(): + return "Apple Computer does not support" + mw.execShell('systemctl enable mtproxy') + return 'ok' + + +def initdUinstall(): + if mw.isAppleSystem(): + return "Apple Computer does not support" + mw.execShell('systemctl disable mtproxy') + return 'ok' + +def getMtproxyUrl(): + conf = getConfEnv() + content = mw.readFile(conf) + + + rep = r'bind-to\s*=\s*(.*)' + tmp = re.search(rep, content) + bind_to = tmp.groups()[0].strip() + bind_to = bind_to.strip('"') + + rep = r'secret\s*=\s*(.*)' + tmp = re.search(rep, content) + secret = tmp.groups()[0].strip() + secret = secret.strip('"') + + info = bind_to.split(":") + + ip = mw.getLocalIp() + + url = 'tg://proxy?server={0}&port={1}&secret={2}'.format(ip, info[1], secret) + return mw.returnJson(True, 'ok', url) + +def installPreInspection(): + sys = mw.execShell("cat /etc/*-release | grep PRETTY_NAME |awk -F = '{print $2}' | awk -F '\"' '{print $2}'| awk '{print $1}'") + + if sys[1] != '': + return '不支持该系统' + + sys_id = mw.execShell("cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F '\"' '{print $2}'") + + sysName = sys[0].strip().lower() + sysId = sys_id[0].strip() + + if sysName in ('opensuse'): + return '不支持该系统' + + return 'ok' + + +if __name__ == "__main__": + func = sys.argv[1] + if func == 'status': + print(status()) + elif func == 'start': + print(start()) + elif func == 'stop': + print(stop()) + elif func == 'restart': + print(restart()) + elif func == 'reload': + print(reload()) + elif func == 'initd_status': + print(initdStatus()) + elif func == 'initd_install': + print(initdInstall()) + elif func == 'initd_uninstall': + print(initdUinstall()) + elif func == 'install_pre_inspection': + print(installPreInspection()) + elif func == 'conf': + print(getServiceFile()) + elif func == 'conf_env': + print(getConfEnv()) + elif func == 'url': + print(getMtproxyUrl()) + else: + print('error') diff --git a/plugins/xui/info.json b/plugins/xui/info.json new file mode 100755 index 000000000..4959bfc54 --- /dev/null +++ b/plugins/xui/info.json @@ -0,0 +1,19 @@ +{ + "sort": 7, + "ps": "支持多协议多用户的xray面板", + "install_pre_inspection":true, + "name": "xui", + "title": "xui", + "shell": "install.sh", + "versions":["1.0"], + "updates":["1.0"], + "tip": "soft", + "checks": "server/xui", + "path": "server/xui", + "display": 1, + "author": "FranzKafkaYu", + "date": "2024-12-03", + "home": "https://github.com/FranzKafkaYu/x-ui", + "type": 0, + "pid": "5" +} \ No newline at end of file diff --git a/plugins/xui/init.d/xui.service.tpl b/plugins/xui/init.d/xui.service.tpl new file mode 100644 index 000000000..03ad10760 --- /dev/null +++ b/plugins/xui/init.d/xui.service.tpl @@ -0,0 +1,14 @@ +[Unit] +Description=MTProxy +After=network.target + +[Service] +Type=simple +WorkingDirectory={$SERVER_PATH}/mtproxy +ExecStart={$SERVER_PATH}/mtproxy/mtg/mtg run {$SERVER_PATH}/mtproxy/mt.toml +RestartSec=3 +Restart=on-failure +AmbientCapabilities=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/plugins/xui/install.sh b/plugins/xui/install.sh new file mode 100755 index 000000000..e34900719 --- /dev/null +++ b/plugins/xui/install.sh @@ -0,0 +1,33 @@ +#!/bin/bash +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin +export PATH + +curPath=`pwd` +rootPath=$(dirname "$curPath") +rootPath=$(dirname "$rootPath") +serverPath=$(dirname "$rootPath") + +sysArch=`arch` +sysName=`uname` + + +# cd /www/server/mdserver-web && python3 plugins/mtproxy/index.py url +# cd /www/server/mdserver-web/plugins/xui && /bin/bash install.sh install 1.0 + + +Install_app() +{ + echo '安装完成' +} + +Uninstall_app() +{ + echo '卸载完成' +} + +action=$1 +if [ "${1}" == 'install' ];then + Install_app $2 +else + Uninstall_app $2 +fi diff --git a/plugins/xui/js/xui.js b/plugins/xui/js/xui.js new file mode 100644 index 000000000..748e2db60 --- /dev/null +++ b/plugins/xui/js/xui.js @@ -0,0 +1,61 @@ +function mtPost(method, version, args,callback){ + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + + var req_data = {}; + req_data['name'] = 'mtproxy'; + req_data['func'] = method; + req_data['version'] = version; + + if (typeof(args) == 'string'){ + req_data['args'] = JSON.stringify(toArrayObject(args)); + } else { + req_data['args'] = JSON.stringify(args); + } + + $.post('/plugins/run', req_data, function(data) { + layer.close(loadT); + if (!data.status){ + //错误展示10S + layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']}); + return; + } + + if(typeof(callback) == 'function'){ + callback(data); + } + },'json'); +} + +function mtCommonFunc(){ + var con = '

\ + \ +

'; + + $(".soft-man-con").html(con); + + $('#mtproxy_url').click(function(){ + mtPost('url', '', {}, function(rdata){ + var data = $.parseJSON(rdata.data); + + layer.open({ + title: "mtproxy代理信息", + area: ['600px', '180px'], + type:1, + closeBtn: 1, + shadeClose: false, + btn:["复制","取消"], + content: '
\ +
\ +
'+data.data+'
\ +
\ +
', + success:function(){ + copyText(data.data); + }, + yes:function(){ + copyText(data.data); + } + }); + }); + }); +} \ No newline at end of file