diff --git a/.gitignore b/.gitignore index a18bf53ac..21c659353 100644 --- a/.gitignore +++ b/.gitignore @@ -188,7 +188,6 @@ plugins/tidb plugins/goedge-admin plugins/goedge-node plugins/goedge-happy -plugins/doh /logs /data diff --git a/plugins/doh/config/config.toml b/plugins/doh/config/config.toml new file mode 100644 index 000000000..86d02101d --- /dev/null +++ b/plugins/doh/config/config.toml @@ -0,0 +1,48 @@ +[general] +# 监听地址和端口 +listen_addr = "0.0.0.0:8080" + +# DoH 路径 +path = "/dns-query" + +# TLS 配置(如果需要 HTTPS) +# tls_cert_path = "/etc/doh-proxy/cert.pem" +# tls_key_path = "/etc/doh-proxy/key.pem" + +# 并发请求限制 +max_concurrent_requests = 512 + +# 日志文件 +log_file = "{$SERVER_PATH}/doh-proxy/doh-proxy.log" + +[upstream] +# 上游 DNS 服务器 +upstream_addr = "1.1.1.1:443" +bootstrap_addr = "1.1.1.1:53" + +# 上游 DoH 服务器 URL(如果使用标准的 DoH 端点) +# upstream_url = "https://cloudflare-dns.com/dns-query" + +# 超时设置 +timeout = 10 + +# 重试次数 +tries = 3 + +# 启用 TCP 保活 +tcp_keepalive = 30 + +[cache] +# 缓存设置 +max_entries = 65536 +min_ttl = 60 +max_ttl = 3600 + +[network] +# 网络设置 +tcp_fastopen = true +reuse_port = true + +[log] +# 日志级别:debug, info, warn, error +level = "info" \ No newline at end of file diff --git a/plugins/doh/ico.png b/plugins/doh/ico.png new file mode 100644 index 000000000..2260f976a Binary files /dev/null and b/plugins/doh/ico.png differ diff --git a/plugins/doh/index.html b/plugins/doh/index.html new file mode 100755 index 000000000..491120e44 --- /dev/null +++ b/plugins/doh/index.html @@ -0,0 +1,28 @@ + +
+
+
+

服务

+

自启动

+

手动编辑

+

配置文件

+

使用说明

+
+
+
+
+
+
+ \ No newline at end of file diff --git a/plugins/doh/index.py b/plugins/doh/index.py new file mode 100755 index 000000000..10e915fd8 --- /dev/null +++ b/plugins/doh/index.py @@ -0,0 +1,1154 @@ +# coding: utf-8 + + +import time +import os +import sys +import re +import subprocess + +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 'doh' + + +def getPluginDir(): + return mw.getPluginDir() + '/' + getPluginName() + + +def getServerDir(): + return mw.getServerDir() + '/' + getPluginName() + + +def getInitDFile(): + if app_debug: + return '/tmp/' + getPluginName() + return '/etc/init.d/' + getPluginName() + + +def getArgs(): + args = sys.argv[2:] + tmp = {} + args_len = len(args) + + if args_len == 1: + t = args[0].strip('{').strip('}') + t = t.split(':', 1) + tmp[t[0]] = t[1] + elif args_len > 1: + for i in range(len(args)): + t = args[i].split(':', 1) + tmp[t[0]] = t[1] + + return tmp + + +def checkArgs(data, ck=[]): + for i in range(len(ck)): + if not ck[i] in data: + return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!')) + return (True, mw.returnJson(True, 'ok')) + + +def getInitdConfTpl(): + path = getPluginDir() + "/init.d/gitea.tpl" + return path + + +def getInitdConf(): + path = getServerDir() + "/init.d/doh" + return path + + +def getConf(): + path = getServerDir() + "/custom/conf/app.ini" + + if not os.path.exists(path): + return mw.returnJson(False, "请先安装初始化!
默认地址:http://" + mw.getLocalIp() + ":3000") + return path + + +def getConfTpl(): + path = getPluginDir() + "/conf/app.ini" + return path + + +def status(): + data = mw.execShell( + "ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'") + if data[0] == '': + return 'stop' + return 'start' + + +def getHomeDir(): + if mw.isAppleSystem(): + user = mw.execShell( + "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip() + return '/Users/' + user + else: + return 'www' + + +def getRunUser(): + if mw.isAppleSystem(): + user = mw.execShell( + "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip() + return user + else: + return 'www' + +__SR = '''#!/bin/bash +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin +export PATH +export USER=%s +export HOME=%s && ''' % ( getRunUser(), getHomeDir()) + + +def contentReplace(content): + + service_path = mw.getServerDir() + content = content.replace('{$ROOT_PATH}', mw.getFatherDir()) + content = content.replace('{$SERVER_PATH}', service_path) + content = content.replace('{$RUN_USER}', getRunUser()) + content = content.replace('{$HOME_DIR}', getHomeDir()) + + return content + + +def initDreplace(): + + file_tpl = getInitdConfTpl() + service_path = mw.getServerDir() + + git_dir = mw.getServerDir() + '/git' + if not os.path.exists(git_dir): + mw.execShell('mkdir -p ' + git_dir) + mw.execShell('chown -R www:www ' + git_dir) + + + initD_path = getServerDir() + '/init.d' + if not os.path.exists(initD_path): + os.mkdir(initD_path) + file_bin = initD_path + '/' + getPluginName() + + if not os.path.exists(file_bin): + content = mw.readFile(file_tpl) + content = contentReplace(content) + mw.writeFile(file_bin, content) + mw.execShell('chmod +x ' + file_bin) + + # systemd + systemDir = mw.systemdCfgDir() + systemService = systemDir + '/doh.service' + systemServiceTpl = getPluginDir() + '/init.d/doh.service.tpl' + 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') + + log_path = getServerDir() + '/log' + if not os.path.exists(log_path): + os.mkdir(log_path) + + return file_bin + + +def getRootUrl(): + content = mw.readFile(getConf()) + rep = r'ROOT_URL\s*=\s*(.*)' + tmp = re.search(rep, content) + if tmp: + return tmp.groups()[0] + + rep = r'EXTERNAL_URL\s*=\s*(.*)' + tmp = re.search(rep, content) + if tmp: + return tmp.groups()[0] + return '' + + +def getSshPort(): + content = mw.readFile(getConf()) + rep = r'SSH_PORT\s*=\s*(.*)' + tmp = re.search(rep, content) + if not tmp: + return '' + return tmp.groups()[0] + + +def getHttpPort(): + content = mw.readFile(getConf()) + rep = r'HTTP_PORT\s*=\s*(.*)' + tmp = re.search(rep, content) + if not tmp: + return '' + return tmp.groups()[0] + + +def getRootPath(): + content = mw.readFile(getConf()) + rep = r'ROOT\s*=\s*(.*)' + tmp = re.search(rep, content) + if not tmp: + return '' + return tmp.groups()[0] + + +def getDbConfValue(): + conf = getConf() + if not os.path.exists(conf): + return {} + + content = mw.readFile(conf) + rep_scope = r"\[database\](.*?)\[" + tmp = re.findall(rep_scope, content, re.S) + + rep = '(\\w*)\\s*=\\s*(.*)' + tmp = re.findall(rep, tmp[0]) + r = {} + for x in range(len(tmp)): + k = tmp[x][0] + v = tmp[x][1] + r[k] = v + return r + + +def pMysqlDb(conf): + host = conf['HOST'].split(':') + # pymysql + db = mw.getMyORM() + # MySQLdb | + # db = mw.getMyORMDb() + + db.setPort(int(host[1])) + db.setUser(conf['USER']) + + if 'PASSWD' in conf: + db.setPwd(conf['PASSWD']) + else: + db.setPwd(conf['PASSWORD']) + + db.setDbName(conf['NAME']) + # db.setSocket(getSocketFile()) + db.setCharset("utf8") + return db + + +def pSqliteDb(conf): + # print(conf) + import db + psDb = db.Sql() + + # 默认 + gsdir = getServerDir() + '/data' + dbname = 'gitea' + if conf['PATH'][0] == '/': + # 绝对路径 + pass + else: + path = conf['PATH'].split('/') + gsdir = getServerDir() + '/' + path[0] + dbname = path[1].split('.')[0] + + # print(gsdir, dbname) + psDb.dbPos(gsdir, dbname) + return psDb + + +def getGiteaDbType(conf): + + if 'DB_TYPE' in conf: + return conf['DB_TYPE'] + + if 'TYPE' in conf: + return conf['TYPE'] + + return 'NONE' + + +def pQuery(sql): + conf = getDbConfValue() + gtype = getGiteaDbType(conf) + if gtype == 'sqlite3': + db = pSqliteDb(conf) + data = db.query(sql, []).fetchall() + return data + elif gtype == 'mysql': + db = pMysqlDb(conf) + return db.query(sql) + + print("仅支持mysql|sqlite3配置") + exit(0) + + +def isSqlError(mysqlMsg): + # 检测数据库执行错误 + _mysqlMsg = str(mysqlMsg) + # print _mysqlMsg + if "MySQLdb" in _mysqlMsg: + return mw.returnData(False, 'MySQLdb组件缺失!
进入SSH命令行输入: pip install mysql-python') + if "2002," in _mysqlMsg: + return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!') + if "using password:" in _mysqlMsg: + return mw.returnData(False, '数据库管理密码错误!') + if "Connection refused" in _mysqlMsg: + return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!') + if "1133," in _mysqlMsg: + return mw.returnData(False, '数据库用户不存在!') + if "1007," in _mysqlMsg: + return mw.returnData(False, '数据库已经存在!') + if "1044," in _mysqlMsg: + return mw.returnData(False, mysqlMsg[1]) + if "2003," in _mysqlMsg: + return mw.returnData(False, "Can't connect to MySQL server on '127.0.0.1' (61)") + return mw.returnData(True, 'OK') + + +def appOp(method): + file = initDreplace() + + if not mw.isAppleSystem(): + data = mw.execShell('systemctl ' + method + ' ' + getPluginName()) + if data[1] == '': + return 'ok' + return 'fail' + + data = mw.execShell(__SR + file + ' ' + method) + if data[1] == '': + return 'ok' + return data[0] + + +def start(): + return appOp('start') + + +def stop(): + return appOp('stop') + + +def restart(): + return appOp('restart') + + +def reload(): + return appOp('reload') + + +def initdStatus(): + if mw.isAppleSystem(): + return "Apple Computer does not support" + + shell_cmd = 'systemctl status ' + getPluginName() + ' | 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 ' + getPluginName()) + return 'ok' + + +def initdUinstall(): + if mw.isAppleSystem(): + return "Apple Computer does not support" + + mw.execShell('systemctl disable ' + getPluginName()) + return 'ok' + + +def runLog(): + log_path = getServerDir() + '/log/gitea.log' + return log_path + + +def postReceiveLog(): + log_path = getServerDir() + '/log/hooks/post-receive.log' + return log_path + + +def getGogsConf(): + conf = getConf() + if not os.path.exists(conf): + return mw.returnJson(False, "请先安装初始化!
默认地址:http://" + mw.getLocalIp() + ":3000") + + gets = [ + {'name': 'DOMAIN', 'type': -1, 'ps': '服务器域名'}, + {'name': 'ROOT_URL', 'type': -1, 'ps': '公开的完整URL路径'}, + {'name': 'HTTP_ADDR', 'type': -1, 'ps': '应用HTTP监听地址'}, + {'name': 'HTTP_PORT', 'type': -1, 'ps': '应用 HTTP 监听端口号'}, + + {'name': 'START_SSH_SERVER', 'type': 2, 'ps': '启动内置SSH服务器'}, + {'name': 'SSH_PORT', 'type': -1, 'ps': 'SSH 端口号'}, + + {'name': 'REQUIRE_SIGNIN_VIEW', 'type': 2, 'ps': '强制登录浏览'}, + {'name': 'ENABLE_CAPTCHA', 'type': 2, 'ps': '启用验证码服务'}, + {'name': 'DISABLE_REGISTRATION', 'type': 2, 'ps': '禁止注册,只能由管理员创建帐号'}, + {'name': 'ENABLE_NOTIFY_MAIL', 'type': 2, 'ps': '是否开启邮件通知'}, + + {'name': 'FORCE_PRIVATE', 'type': 2, 'ps': '强制要求所有新建的仓库都是私有'}, + + {'name': 'SHOW_FOOTER_BRANDING', 'type': 2, 'ps': 'Gogs推广信息'}, + {'name': 'SHOW_FOOTER_VERSION', 'type': 2, 'ps': 'Gogs版本信息'}, + {'name': 'SHOW_FOOTER_TEMPLATE_LOAD_TIME', 'type': 2, 'ps': 'Gogs模板加载时间'}, + ] + conf = mw.readFile(conf) + result = [] + + for g in gets: + rep = g['name'] + '\\s*=\\s*(.*)' + tmp = re.search(rep, conf) + if not tmp: + continue + g['value'] = tmp.groups()[0] + result.append(g) + return mw.returnJson(True, 'OK', result) + + +def submitGogsConf(): + gets = ['DOMAIN', + 'ROOT_URL', + 'HTTP_ADDR', + 'HTTP_PORT', + 'START_SSH_SERVER', + 'SSH_PORT', + 'REQUIRE_SIGNIN_VIEW', + 'FORCE_PRIVATE', + 'ENABLE_CAPTCHA', + 'DISABLE_REGISTRATION', + 'ENABLE_NOTIFY_MAIL', + 'SHOW_FOOTER_BRANDING', + 'SHOW_FOOTER_VERSION', + 'SHOW_FOOTER_TEMPLATE_LOAD_TIME'] + args = getArgs() + filename = getConf() + conf = mw.readFile(filename) + for g in gets: + if g in args: + rep = g + '\\s*=\\s*(.*)' + val = g + ' = ' + args[g] + conf = re.sub(rep, val, conf) + mw.writeFile(filename, conf) + restart() + return mw.returnJson(True, '设置成功') + + +def gogsEditTpl(): + data = {} + data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl' + data['commit'] = getPluginDir() + '/hook/commit.tpl' + return mw.getJson(data) + + +def userList(): + + conf = getConf() + if not os.path.exists(conf): + return mw.returnJson(False, "请先安装初始化!
默认地址:http://" + mw.getLocalIp() + ":3000") + + conf = getDbConfValue() + gtype = getGiteaDbType(conf) + if gtype != 'mysql': + return mw.returnJson(False, "仅支持mysql数据操作!") + + import math + args = getArgs() + + data = checkArgs(args, ['page', 'page_size']) + if not data[0]: + return data[1] + + page = int(args['page']) + page_size = int(args['page_size']) + search = '' + if 'search' in args: + search = args['search'] + + user_where1 = '' + user_where2 = '' + if search != '': + user_where1 = ' where name like "%' + search + '%"' + user_where2 = ' where name like "%' + search + '%"' + + data = {} + + data['root_url'] = getRootUrl() + + start = (page - 1) * page_size + list_count = pQuery('select count(id) as num from user' + user_where1) + count = list_count[0]["num"] + list_data = pQuery( + 'select id,name,email from user ' + user_where2 + ' order by id desc limit ' + str(start) + ',' + str(page_size)) + data['list'] = mw.getPage({'count': count, 'p': page, + 'row': page_size, 'tojs': 'gogsUserList'}) + data['page'] = page + data['page_size'] = page_size + data['page_count'] = int(math.ceil(count / page_size)) + data['data'] = list_data + return mw.returnJson(True, 'OK', data) + + +def checkRepoListIsHasScript(data): + path = getRootPath() + for x in range(len(data)): + name = data[x]['name'] + '/' + data[x]['repo'] + '.git' + path_tmp = path + '/' + name + '/custom_hooks/commit' + if os.path.exists(path_tmp): + data[x]['has_hook'] = True + else: + data[x]['has_hook'] = False + return data + + +def repoList(): + + conf = getConf() + if not os.path.exists(conf): + return mw.returnJson(False, "请先安装初始化!
默认地址:http://" + mw.getLocalIp() + ":3000") + + conf = getDbConfValue() + gtype = getGiteaDbType(conf) + if gtype != 'mysql': + return mw.returnJson(False, "仅支持mysql数据操作!") + + import math + args = getArgs() + + data = checkArgs(args, ['page', 'page_size']) + if not data[0]: + return data[1] + + page = int(args['page']) + page_size = int(args['page_size']) + search = '' + if 'search' in args: + search = args['search'] + + data = {} + + data['root_url'] = getRootUrl() + + repo_where1 = '' + repo_where2 = '' + if search != '': + repo_where1 = ' where name like "%' + search + '%"' + repo_where2 = ' where r.name like "%' + search + '%"' + + start = (page - 1) * page_size + list_count = pQuery( + 'select count(id) as num from repository' + repo_where1) + count = list_count[0]["num"] + sql = 'select r.id,r.owner_id,r.name as repo, u.name from repository r left join user u on r.owner_id=u.id ' + repo_where2 + ' order by r.id desc limit ' + \ + str(start) + ',' + str(page_size) + # print(sql) + list_data = pQuery(sql) + # print(list_data) + list_data = checkRepoListIsHasScript(list_data) + + data['list'] = mw.getPage({'count': count, 'p': page, + 'row': page_size, 'tojs': 'gogsRepoListPage'}) + data['page'] = page + data['page_size'] = page_size + data['page_count'] = int(math.ceil(count / page_size)) + data['data'] = list_data + return mw.returnJson(True, 'OK', data) + + +def getAllUserProject(user, search=''): + path = getRootPath() + '/' + user + dlist = [] + if os.path.exists(path): + for filename in os.listdir(path): + tmp = {} + filePath = path + '/' + filename + if os.path.isdir(filePath): + if search == '': + tmp['name'] = filename.replace('.git', '') + dlist.append(tmp) + else: + if filename.find(search) != -1: + tmp['name'] = filename.replace('.git', '') + dlist.append(tmp) + return dlist + + +def checkProjectListIsHasScript(user, data): + path = getRootPath() + '/' + user + for x in range(len(data)): + name = data[x]['name'] + '.git' + path_tmp = path + '/' + name + '/hooks/post-receive.d/post-receive' + if os.path.exists(path_tmp): + data[x]['has_hook'] = True + else: + data[x]['has_hook'] = False + return data + + +def userProjectList(): + import math + args = getArgs() + # print args + + page = 1 + page_size = 5 + search = '' + + if not 'name' in args: + return mw.returnJson(False, '缺少参数name') + if 'page' in args: + page = int(args['page']) + + if 'page_size' in args: + page_size = int(args['page_size']) + + if 'search' in args: + search = args['search'] + + data = {} + + ulist = getAllUserProject(args['name']) + dlist_sum = len(ulist) + + start = (page - 1) * page_size + ret_data = ulist[start:start + page_size] + ret_data = checkProjectListIsHasScript(args['name'], ret_data) + + data['root_url'] = getRootUrl() + data['data'] = ret_data + data['args'] = args + data['list'] = mw.getPage( + {'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectListPost'}) + + return mw.returnJson(True, 'OK', data) + + +def projectScriptEdit(): + args = getArgs() + + if not 'user' in args: + return mw.returnJson(True, 'username missing') + + if not 'name' in args: + return mw.returnJson(True, 'project name missing') + + user = args['user'] + name = args['name'] + '.git' + post_receive = getRootPath() + '/' + user + '/' + name + \ + '/custom_hooks/commit' + if os.path.exists(post_receive): + return mw.returnJson(True, 'OK', {'path': post_receive}) + else: + return mw.returnJson(False, 'file does not exist') + + +def projectScriptLoad(): + args = getArgs() + data = checkArgs(args, ['user', 'name']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + + path = getRootPath() + '/' + user + '/' + name + post_receive_tpl = getPluginDir() + '/hook/post-receive.tpl' + post_receive = path + '/hooks/post-receive.d/post-receive' + + if not os.path.exists(path + '/custom_hooks'): + mw.execShell('mkdir -p ' + path + '/custom_hooks') + mw.execShell('chown -R www:www ' + path + '/custom_hooks') + + pct_content = mw.readFile(post_receive_tpl) + pct_content = pct_content.replace('{$PATH}', path + '/custom_hooks') + mw.writeFile(post_receive, pct_content) + mw.execShell('chmod 777 ' + post_receive) + mw.execShell('chown -R www:www ' + post_receive) + + commit_tpl = getPluginDir() + '/hook/commit.tpl' + commit = path + '/custom_hooks/commit' + + codeDir = mw.getFatherDir() + '/git' + + cc_content = mw.readFile(commit_tpl) + + gitPath = getRootPath() + cc_content = cc_content.replace('{$GITROOTURL}', gitPath) + cc_content = cc_content.replace('{$CODE_DIR}', codeDir) + cc_content = cc_content.replace('{$USERNAME}', user) + cc_content = cc_content.replace('{$PROJECT}', args['name']) + cc_content = cc_content.replace('{$WEB_ROOT}', mw.getWwwDir()) + mw.writeFile(commit, cc_content) + mw.execShell('chmod 777 ' + commit) + mw.execShell('chown -R www:www ' + commit) + + return 'ok' + + +def projectScriptUnload(): + args = getArgs() + data = checkArgs(args, ['user', 'name']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + + post_receive = getRootPath() + '/' + user + '/' + name + \ + '/hooks/post-receive.d/post-receive' + mw.execShell('rm -f ' + post_receive) + + commit = getRootPath() + '/' + user + '/' + name + \ + '/custom_hooks/commit' + mw.execShell('rm -f ' + commit) + return 'ok' + + +def projectScriptDebug(): + args = getArgs() + data = checkArgs(args, ['user', 'name']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + commit_log = getRootPath() + '/' + user + '/' + name + \ + '/custom_hooks/sh.log' + + data = {} + if os.path.exists(commit_log): + data['status'] = True + data['path'] = commit_log + else: + data['status'] = False + data['msg'] = '没有日志文件' + + return mw.getJson(data) + + +def projectScriptRun(): + args = getArgs() + data = checkArgs(args, ['user', 'name']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + + path = getRootPath() + '/' + user + '/' + name + commit_sh = path + '/custom_hooks/commit' + commit_log = path + '/custom_hooks/sh.log' + script_run = 'sh -x ' + commit_sh + ' 2>' + commit_log + + if not os.path.exists(commit_sh): + return mw.returnJson(False, '脚本文件不存在!') + + repo_dir = mw.getServerDir()+'/git/'+ args['name'] + + # mw.execShell(script_run) + subprocess.Popen(script_run, stdout=subprocess.PIPE, shell=True, + bufsize=4096, stderr=subprocess.PIPE) + subprocess.Popen('chown -R www:www ' + repo_dir, stdout=subprocess.PIPE, shell=True, + bufsize=4096, stderr=subprocess.PIPE) + return mw.returnJson(True, '脚本文件执行成功,观察日志!') + + +def projectScriptSelf(): + args = getArgs() + data = checkArgs(args, ['user', 'name']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + + custom_hooks = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks' + + self_path = custom_hooks + '/self' + if not os.path.exists(self_path): + os.mkdir(self_path) + mw.execShell("chown -R www:www " + self_path) + + self_logs_path = custom_hooks + '/self_logs' + if not os.path.exists(self_logs_path): + os.mkdir(self_logs_path) + mw.execShell("chown -R www:www " + self_logs_path) + + self_hook_file = custom_hooks + '/self_hook.sh' + self_hook_exist = False + if os.path.exists(self_hook_file): + self_hook_exist = True + + dlist = [] + if os.path.exists(self_path): + for filename in os.listdir(self_path): + tmp = {} + filePath = self_path + '/' + filename + if os.path.isfile(filePath): + tmp['path'] = filePath + tmp['name'] = os.path.basename(filePath) + tmp['is_hidden'] = False + if tmp['name'].endswith('.txt'): + tmp['is_hidden'] = True + + dlist.append(tmp) + + dlist_sum = len(dlist) + # print(dlist) + rdata = {} + rdata['data'] = dlist + rdata['self_hook'] = self_hook_exist + rdata['list'] = mw.getPage( + {'count': dlist_sum, 'p': 1, 'row': 100, 'tojs': 'self_page'}) + + return mw.returnJson(True, 'ok', rdata) + + +def projectScriptSelf_Create(): + args = getArgs() + data = checkArgs(args, ['user', 'name', 'file']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + file = args['file'] + + self_path = path = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks/self' + + if not os.path.exists(self_path): + os.mkdir(self_path) + + abs_file = self_path + '/' + file + '.sh' + if os.path.exists(abs_file): + return mw.returnJson(False, '脚本已经存在!') + + mw.writeFile(abs_file, "#!/bin/bash\necho `date +'%Y-%m-%d %H:%M:%S'`\n") + mw.execShell('chown -R www:www ' + abs_file) + rdata = {} + rdata['abs_file'] = abs_file + return mw.returnJson(True, '创建文件成功!', rdata) + + +def projectScriptSelf_Del(): + args = getArgs() + data = checkArgs(args, ['user', 'name', 'file']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + file = args['file'] + + custom_hooks = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks' + self_path = custom_hooks + '/self' + + if not os.path.exists(self_path): + os.mkdir(self_path) + + abs_file = self_path + '/' + file + # print(abs_file) + if not os.path.exists(abs_file): + return mw.returnJson(False, '脚本已经删除!') + + os.remove(abs_file) + + # 日志也删除 + log_file = custom_hooks + '/self_logs/' + file + '.log' + if os.path.exists(log_file): + os.remove(log_file) + + return mw.returnJson(True, '脚本删除成功!') + + +def projectScriptSelf_Logs(): + args = getArgs() + data = checkArgs(args, ['user', 'name', 'file']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + file = args['file'] + + self_path = path = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks/self_logs' + + if not os.path.exists(self_path): + os.mkdir(self_path) + + logs_file = self_path + '/' + file + '.log' + if os.path.exists(logs_file): + rdata = {} + rdata['path'] = logs_file + return mw.returnJson(True, 'ok', rdata) + + return mw.returnJson(False, '日志不存在!') + + +def projectScriptSelf_Run(): + args = getArgs() + data = checkArgs(args, ['user', 'name', 'file']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + file = args['file'] + + custom_hooks = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks' + self_path = custom_hooks + '/self/' + file + self_logs_path = custom_hooks + '/self_logs/' + file + '.log' + + shell = "sh -x " + self_path + " 2>" + self_logs_path + ' &' + mw.execShell(shell) + mw.execShell("chown -R www:www " + self_logs_path) + return mw.returnJson(True, '执行成功!') + + +def projectScriptSelf_Rename(): + args = getArgs() + data = checkArgs(args, ['user', 'name', 'o_file', 'n_file']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + o_file = args['o_file'] + n_file = args['n_file'] + + custom_hooks = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks' + self_path = custom_hooks + '/self' + + if not os.path.exists(self_path): + os.mkdir(self_path) + + o_file_abs = self_path + '/' + o_file + '.sh' + if not os.path.exists(o_file_abs): + return mw.returnJson(False, '原文件已经不存在了!') + + n_file_abs = self_path + '/' + n_file + '.sh' + + os.rename(o_file_abs, n_file_abs) + + # 日志也删除 + log_file = custom_hooks + '/self_logs/' + o_file + '.sh.log' + if os.path.exists(log_file): + os.remove(log_file) + + return mw.returnJson(True, '重命名成功!') + + +def projectScriptSelf_Enable(): + args = getArgs() + data = checkArgs(args, ['user', 'name', 'enable']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + enable = args['enable'] + + custom_path = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks' + + # 替换commit配置 + commit_path = custom_path + '/commit' + note = '#Gogs Script Don`t Remove and Change' + + self_file = custom_path + '/self_hook.sh' + self_hook_tpl = getPluginDir() + '/hook/self_hook.tpl' + + if enable == '1': + content = mw.readFile(self_hook_tpl) + content = content.replace('{$HOOK_DIR}', custom_path + '/self') + content = content.replace( + '{$HOOK_LOGS_DIR}', custom_path + '/self_logs') + mw.writeFile(self_file, content) + mw.execShell("chmod 777 " + self_file) + mw.execShell("chown -R www:www " + self_file) + + commit_content = mw.readFile(commit_path) + commit_content += "\n\n" + "bash " + self_file + " " + note + mw.writeFile(commit_path, commit_content) + + return mw.returnJson(True, '开启成功!') + else: + commit_content = mw.readFile(commit_path) + rep = ".*" + note + commit_content = re.sub(rep, '', commit_content, re.M) + commit_content = commit_content.strip() + mw.writeFile(commit_path, commit_content) + if os.path.exists(self_file): + os.remove(self_file) + return mw.returnJson(True, '关闭成功!') + + +def projectScriptSelf_Status(): + args = getArgs() + data = checkArgs(args, ['user', 'name', 'file', 'status']) + if not data[0]: + return data[1] + + user = args['user'] + name = args['name'] + '.git' + file = args['file'] + status = args['status'] + + custom_hooks = getRootPath() + '/' + user + '/' + \ + name + '/custom_hooks' + self_path = custom_hooks + '/self' + + if not os.path.exists(self_path): + os.mkdir(self_path) + + # 日志也删除 + log_file = custom_hooks + '/self_logs/' + file + '.log' + if os.path.exists(log_file): + os.remove(log_file) + + if status == '1': + file_abs = self_path + '/' + file + file_text_abs = self_path + '/' + file + '.txt' + os.rename(file_abs, file_text_abs) + return mw.returnJson(True, '开始禁用成功!') + else: + file_abs = self_path + '/' + file.strip('.txt') + file_text_abs = self_path + '/' + file + os.rename(file_text_abs, file_abs) + return mw.returnJson(True, '开始使用成功!') + + return mw.returnJson(True, '禁用成功!') + + +def getRsaPublic(): + path = getHomeDir() + path += '/.ssh/id_rsa.pub' + + content = mw.readFile(path) + + data = {} + data['mw'] = content + return mw.getJson(data) + + +def getTotalStatistics(): + st = status() + data = {} + if st.strip() == 'start': + list_count = pQuery('select count(id) as num from repository') + count = list_count[0]["num"] + data['status'] = True + data['count'] = count + data['ver'] = mw.readFile(getServerDir() + '/version.pl').strip() + return mw.returnJson(True, 'ok', data) + + data['status'] = False + data['count'] = 0 + return mw.returnJson(False, 'fail', data) + + +def uninstallPreInspection(): + repo_dir = getServerDir() + "/data/gitea-repositories" + if not os.path.exists(repo_dir): + return 'ok' + dir_list = os.listdir(repo_dir) + if len(dir_list) > 0: + return "有项目数据!请手动删除Gitea
rm -rf {}".format(getServerDir()) + 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 == 'uninstall_pre_inspection': + print(uninstallPreInspection()) + elif func == 'run_log': + print(runLog()) + elif func == 'post_receive_log': + print(postReceiveLog()) + elif func == 'conf': + print(getConf()) + elif func == 'init_conf': + print(getInitdConf()) + elif func == 'get_gogs_conf': + print(getGogsConf()) + elif func == 'submit_gogs_conf': + print(submitGogsConf()) + elif func == 'gogs_edit_tpl': + print(gogsEditTpl()) + elif func == 'user_list': + print(userList()) + elif func == 'repo_list': + print(repoList()) + elif func == 'user_project_list': + print(userProjectList()) + elif func == 'project_script_edit': + print(projectScriptEdit()) + elif func == 'project_script_load': + print(projectScriptLoad()) + elif func == 'project_script_unload': + print(projectScriptUnload()) + elif func == 'project_script_debug': + print(projectScriptDebug()) + elif func == 'project_script_run': + print(projectScriptRun()) + elif func == 'project_script_self': + print(projectScriptSelf()) + elif func == 'project_script_self_create': + print(projectScriptSelf_Create()) + elif func == 'project_script_self_del': + print(projectScriptSelf_Del()) + elif func == 'project_script_self_logs': + print(projectScriptSelf_Logs()) + elif func == 'project_script_self_run': + print(projectScriptSelf_Run()) + elif func == 'project_script_self_rename': + print(projectScriptSelf_Rename()) + elif func == 'project_script_self_enable': + print(projectScriptSelf_Enable()) + elif func == 'project_script_self_status': + print(projectScriptSelf_Status()) + elif func == 'get_rsa_public': + print(getRsaPublic()) + elif func == 'get_total_statistics': + print(getTotalStatistics()) + else: + print('fail') diff --git a/plugins/doh/info.json b/plugins/doh/info.json new file mode 100755 index 000000000..21edc77d9 --- /dev/null +++ b/plugins/doh/info.json @@ -0,0 +1,18 @@ +{ + "ps": "DNS over HTTPS(DoH)是一种通过HTTPS协议加密域名解析请求的技术!", + "name": "doh", + "title": "DoH", + "versions": ["0.9.15"], + "tip": "soft", + "install_pre_inspection":false, + "uninstall_pre_inspection":true, + "checks": "server/doh", + "path":"server/doh", + "author": "doh", + "date": "2025-11-23", + "home": "https://github.com/DNSCrypt/doh-server", + "type": "doh", + "shell": "install.sh", + "pid": "4", + "sort": 7 +} \ No newline at end of file diff --git a/plugins/doh/init.d/doh.service.tpl b/plugins/doh/init.d/doh.service.tpl new file mode 100644 index 000000000..8b71687a8 --- /dev/null +++ b/plugins/doh/init.d/doh.service.tpl @@ -0,0 +1,20 @@ +[Unit] +Description=DOH (Git with a cup of tea) +After=syslog.target +After=network.target + +[Service] +RestartSec=2s +Type=simple +User=www +Group=www +WorkingDirectory={$SERVER_PATH}/doh +ExecStart={$SERVER_PATH}/doh/doh web +Restart=always +Environment=USER=www HOME=/home/www GITEA_WORK_DIR={$SERVER_PATH}/doh +RemainAfterExit=yes +#AmbientCapabilities=CAP_NET_BIND_SERVICE +#CapabilityBoundingSet=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target diff --git a/plugins/doh/install.sh b/plugins/doh/install.sh new file mode 100755 index 000000000..62ce1a4ea --- /dev/null +++ b/plugins/doh/install.sh @@ -0,0 +1,96 @@ +#!/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") + +if [ -f ${rootPath}/bin/activate ];then + source ${rootPath}/bin/activate +fi + + +# cd /www/server/mdserver-web/plugins/doh && bash install.sh install 0.9.15 + +# 详细状态信息 +# sudo systemctl status doh -l +# 查看完整日志 +# sudo journalctl -u doh -n 100 +# 实时日志跟踪 +# sudo journalctl -u doh -f + + +URL_DOWNLOAD=https://github.com/DNSCrypt/doh-server/releases/download + + +bash ${rootPath}/scripts/getos.sh +OSNAME=`cat ${rootPath}/data/osname.pl` +OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'` + +Install_App() +{ + + mkdir -p $serverPath/source/doh + + echo '正在安装脚本文件...' + version=$1 + + if [ "macos" == "$OSNAME" ];then + echo "not support!" + exit + else + file=doh-proxy_${version}_linux-x86_64 + fi + + # https://github.com/DNSCrypt/doh-server/releases/download/0.9.15/doh-proxy_0.9.15_linux-aarch64.tar.bz2 + file_xz="${file}.tar.bz2" + echo "wget -O $serverPath/source/doh/$file_xz ${URL_DOWNLOAD}/${version}/${file_xz}" + if [ ! -f $serverPath/source/doh/$file_xz ];then + wget --no-check-certificate -O $serverPath/source/doh/$file_xz ${URL_DOWNLOAD}/doh/${version}/${file_xz} + fi + + cd $serverPath/source/doh && xz -k -d $file_xz + if [ -f $file ];then + mkdir -p $serverPath/doh + mv $serverPath/source/doh/$file $serverPath/doh/doh + fi + + + if [ -d $serverPath/doh ];then + echo $version > $serverPath/doh/version.pl + + cd ${rootPath} && python3 plugins/doh/index.py start + cd ${rootPath} && python3 plugins/doh/index.py initd_install + fi + + echo 'install doh success' +} + +Uninstall_App() +{ + + if [ -f /usr/lib/systemd/system/doh.service ];then + systemctl stop doh + systemctl disable doh + rm -rf /usr/lib/systemd/system/doh.service + systemctl daemon-reload + fi + + if [ -f $serverPath/doh/initd/doh ];then + $serverPath/doh/initd/doh stop + fi + + rm -rf $serverPath/doh + echo 'uninstall doh success' +} + + +action=$1 +version=$2 +if [ "${1}" == 'install' ];then + Install_App $version +else + Uninstall_App $version +fi diff --git a/plugins/doh/js/doh.js b/plugins/doh/js/doh.js new file mode 100755 index 000000000..98d85fadf --- /dev/null +++ b/plugins/doh/js/doh.js @@ -0,0 +1,774 @@ + +function gogsPost(method,args,callback, title){ + + var _args = null; + if (typeof(args) == 'string'){ + _args = JSON.stringify(toArrayObject(args)); + } else { + _args = JSON.stringify(args); + } + + var _title = '正在获取...'; + if (typeof(title) != 'undefined'){ + _title = title; + } + + var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 }); + $.post('/plugins/run', {name:'gitea', func:method, args:_args}, function(data) { + layer.close(loadT); + if (!data.status){ + layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + if(typeof(callback) == 'function'){ + callback(data); + } + },'json'); +} + +function gogsSetConfig(){ + gogsPost('get_gogs_conf', '', function(data){ + var rrdata = $.parseJSON(data.data); + if (!rrdata.status){ + layer.msg(rrdata.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + var rdata = rrdata.data; + var mlist = ''; + for (var i = 0; i < rdata.length; i++) { + var w = '140'; + if (rdata[i].name == 'error_reporting') w = '250'; + var ibody = ''; + switch (rdata[i].type) { + case 0: + var selected_1 = (rdata[i].value == 1) ? 'selected' : ''; + var selected_0 = (rdata[i].value == 0) ? 'selected' : ''; + ibody = ''; + break; + case 1: + var selected_1 = (rdata[i].value == 'On') ? 'selected' : ''; + var selected_0 = (rdata[i].value == 'Off') ? 'selected' : ''; + ibody = '' + break; + case 2: + var selected_1 = (rdata[i].value == 'true') ? 'selected' : ''; + var selected_0 = (rdata[i].value == 'false') ? 'selected' : ''; + ibody = '' + break; + } + mlist += '

' + rdata[i].name + '' + ibody + ', ' + rdata[i].ps + '

' + } + var html = '
\ + ' + mlist + '\ +
\ + \ +
\ +
'; + $(".soft-man-con").html(html); + }); +} + + +//提交PHP配置 +function submitGogsConf() { + var data = { + DOMAIN: $("input[name='DOMAIN']").val(), + ROOT_URL: $("input[name='ROOT_URL']").val(), + HTTP_ADDR: $("select[name='HTTP_ADDR']").val(), + HTTP_PORT: $("input[name='HTTP_PORT']").val(), + START_SSH_SERVER: $("select[name='START_SSH_SERVER']").val() || 'false', + SSH_PORT: $("input[name='SSH_PORT']").val(), + REQUIRE_SIGNIN_VIEW: $("select[name='REQUIRE_SIGNIN_VIEW']").val() || 'false', + ENABLE_CAPTCHA: $("select[name='ENABLE_CAPTCHA']").val() || 'true', + DISABLE_REGISTRATION: $("select[name='DISABLE_REGISTRATION']").val() || 'false', + ENABLE_NOTIFY_MAIL: $("select[name='ENABLE_NOTIFY_MAIL']").val() || 'false', + FORCE_PRIVATE: $("select[name='FORCE_PRIVATE']").val() || 'false', + SHOW_FOOTER_BRANDING: $("select[name='SHOW_FOOTER_BRANDING']").val() || 'false', + SHOW_FOOTER_VERSION: $("select[name='SHOW_FOOTER_VERSION']").val() || 'false', + SHOW_FOOTER_TEMPLATE_LOAD_TIME: $("select[name='SHOW_FOOTER_TEMPLATE_LOAD_TIME']").val() || 'false', + }; + + gogsPost('submit_gogs_conf', data, function(ret_data){ + var rdata = $.parseJSON(ret_data.data); + layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 }); + gogsSetConfig(); + }); +} + +function gogsEdit(){ + + gogsPost('gogs_edit',{} , function(data){ + // console.log(data); + var rdata = $.parseJSON(data.data); + var edit = '

通用的手动编辑:

'; + edit +='
\ + \ + \ +
'; + $(".soft-man-con").html(edit); + }); + +} + + +function giteaUserList(page, search) { + + var _data = {}; + if (typeof(page) =='undefined'){ + var page = 1; + } + + _data['page'] = page; + _data['page_size'] = 10; + if(typeof(search) != 'undefined'){ + _data['search'] = search; + } + + gogsPost('user_list', _data, function(data){ + + var rdata = $.parseJSON(data.data); + if (!rdata.status){ + layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + content = '
'; + content += '
'; + + content += '
'; + content += ''; + content += ''; + content += ''; + content += ''; + content += ''; + content += ''; + + content += ''; + + ulist = rdata['data']['data']; + for (i in ulist){ + + var email = ulist[i]["email"] == '' ? '无' : ulist[i]["email"]; + var user_url = rdata['data']['root_url'] + ulist[i]["name"]; + content += ''+ + ''+ + ''+ + ''+ + ''; + } + + content += ''; + content += '
序号用户或组织邮件地址操作(WEB管理)
'+ulist[i]["id"]+''+ulist[i]["name"]+''+email+'项目管理
'; + + var page_html = ''; + + content += page_html; + + $(".soft-man-con").html(content); + + $('.find_user').click(function(){ + var name = $('#find_user').val(); + giteaUserList(page, name); + }); + }); +} + +function userProjectList(user, search){ + var loadOpen = layer.open({ + type: 1, + title: '用户('+user+')项目列表', + area: '500px', + content:"
\ +
\ +
\ + \ + \ + \ +
项目操作
\ + \ +
\ +
\ +
", + success:function(){ + userProjectListPost(user,search); + } + }); +} + +function userProjectListPost(user, search){ + var req = {}; + if (!isNaN(user)){ + req['page'] = user; + req['name'] = user = getCookie('gogsUserSelected'); + } else { + req['page'] = 1; + req['name'] = user; + setCookie('gogsUserSelected', user); + } + + req['page_size'] = 5; + req['search'] = ''; + if(typeof(search) != 'undefined'){ + req['search'] = search; + } + + gogsPost('user_project_list', req, function(data){ + var rdata = []; + try { + rdata = $.parseJSON(data.data); + } catch(e){} + + if (!rdata['status']){ + layer.msg(rdata['msg'], { icon: 2 }); + return; + } + + var list = ''; + // console.log(rdata); + var project_list = rdata['data']['data']; + for (i in project_list) { + var name = project_list[i]['name']; + list += '\ + '+name+'\ + \ + 源码 | \ + 脚本\ + \ + '; + } + + $('#gitea_table tbody').html(list); + + var page = rdata['data']['list']; + $('#gitea_table .gitea_page').html(page); + }); +} + + +function projectScript(user, name,has_hook){ + // console.log(user,name,has_hook); + var html = ''; + if (has_hook){ + html += ''; + html += ''; + html += ''; + html += ''; + } else { + html += ''; + } + + var loadOpen = layer.open({ + type: 1, + title: '['+user+']['+name+']脚本设置', + area: '240px', + content:'
'+html+'
', + success:function(layero,index) { + + $('.hook_edit').click(function(){ + projectScriptEdit(user,name,index); + }); + + $('.hook_log').click(function(){ + projectScriptDebug(user,name,index); + }); + + $('.hook_load').click(function(){ + projectScriptLoad(user,name,index); + }); + + $('.hook_unload').click(function(){ + projectScriptUnload(user,name,index); + }); + } + }); +} + +function projectScriptEdit(user,name,index){ + gogsPost('project_script_edit', {'user':user,'name':name}, function(data){ + var rdata = $.parseJSON(data.data); + if (rdata['status']){ + onlineEditFile(0, rdata['data']['path']); + } else { + layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']}); + } + }); +} + +function projectScriptLoad(user,name,index){ + gogsPost('project_script_load', {'user':user,'name':name}, function(data){ + if (data.data != 'ok'){ + layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + showMsg('加载成功!',function(){ + layer.close(index); + userProjectListPost(1); + },{icon:1,time:2000,shade: [0.3, '#000']},2000); + }); +} + +function projectScriptUnload(user,name,index){ + gogsPost('project_script_unload', {'user':user,'name':name}, function(data){ + if (data.data != 'ok'){ + layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + showMsg('卸载成功!',function(){ + layer.close(index); + userProjectListPost(1); + },{icon:1,time:2000,shade: [0.3, '#000']},2000); + }); +} + +function projectScriptDebug(user,name,index){ + gogsPost('project_script_debug', {'user':user,'name':name}, function(data){ + var rdata = $.parseJSON(data.data); + if (rdata['status']){ + onlineEditFile(0, rdata['path']); + } else { + showMsg(rdata.msg,function(){ + },{icon:1,time:2000,shade: [0.3, '#000']},2000); + } + }); +} + +function gogsRepoListPage(page, search){ + var _data = {}; + if (typeof(page) =='undefined'){ + var page = 1; + } + + _data['page'] = page; + _data['page_size'] = 10; + if(typeof(search) != 'undefined'){ + _data['search'] = search; + } + + gogsPost('repo_list', _data, function(data){ + + var rdata = $.parseJSON(data.data); + if (!rdata.status){ + layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + var ulist = rdata['data']['data']; + var body = '' + for (i in ulist){ + // console.log(ulist[i]); + + var option = ''; + if(ulist[i]['has_hook']){ + option += '卸载脚本' + ' | '; + option += '重载' + ' | '; + option += '编辑' + ' | '; + option += '日志' + ' | '; + option += '手动' + ' | '; + option += '自定义'; + } else{ + option += '加载脚本'; + } + + + body += ''+ulist[i]["id"]+''+ + '' + ulist[i]["name"]+''+ + '' + ulist[i]["repo"]+''+ + '' + + '源码' + ' | ' + + option + + '' + + ''; + } + + $('#repo_list tbody').html(body); + $('#repo_list_page').html(rdata['data']['list']); + + $('.find_repo').click(function(){ + var find_repo = $('#find_repo').val(); + gogsRepoListPage(page, find_repo); + }); + + + $('#repo_list .load').click(function(){ + var i = $(this).data('index'); + var user = ulist[i]["name"]; + var name = ulist[i]["repo"]; + + gogsPost('project_script_load', {'user':user,'name':name}, function(data){ + if (data.data != 'ok'){ + layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']}); + setTimeout(function(){ + gogsRepoListPage(page, search); + }, 2000); + }); + }); + + $('#repo_list .unload').click(function(){ + var i = $(this).data('index'); + var user = ulist[i]["name"]; + var name = ulist[i]["repo"]; + + gogsPost('project_script_unload', {'user':user,'name':name}, function(data){ + if (data.data != 'ok'){ + layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']}); + setTimeout(function(){ + gogsRepoListPage(page, search); + }, 2000); + }); + }); + + $('#repo_list .edit').click(function(){ + var i = $(this).data('index'); + var user = ulist[i]["name"]; + var name = ulist[i]["repo"]; + + gogsPost('project_script_edit', {'user':user,'name':name}, function(data){ + var rdata = $.parseJSON(data.data); + if (rdata['status']){ + onlineEditFile(0, rdata['data']['path']); + } else { + layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']}); + } + }); + }); + + + $('#repo_list .debug').click(function(){ + var i = $(this).data('index'); + var user = ulist[i]["name"]; + var name = ulist[i]["repo"]; + + gogsPost('project_script_debug', {'user':user,'name':name}, function(data){ + var rdata = $.parseJSON(data.data); + if (rdata['status']){ + onlineEditFile(0, rdata['path']); + } else { + layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']}); + } + }); + }); + + + $('#repo_list .run').click(function(){ + var i = $(this).data('index'); + var user = ulist[i]["name"]; + var name = ulist[i]["repo"]; + + gogsPost('project_script_run', {'user':user,'name':name}, function(data){ + var data = $.parseJSON(data.data); + layer.msg(data.msg,{icon:data.status?1:2,time:2000,shade: [0.3, '#000']}); + }); + }); + + //--------- + }); +} + + +function giteaRepoList() { + content = '
'; + content += '
'; + + content += '
'; + content += ''; + content += ''; + content += ''; + content += ''; + content += ''; + content += ''; + + content += ''; + content += '
序号用户/组织项目名操作
'; + + var page = ''; + + content += page; + + $(".soft-man-con").html(content); + + gogsRepoListPage(1); +} + +function projectScriptSelfRender(user, name){ + gogsPost('project_script_self', {'user':user,'name':name}, function(data){ + var rdata = $.parseJSON(data.data); + + var data = rdata['data']['data']; + + if (rdata['data']['self_hook']){ + $('#open_script').prop('checked',true); + } + + var body = ''; + if(data.length == 0 ){ + body += '无脚本数据'; + } else{ + for (var i = 0; i < data.length; i++) { + var b_status = '已使用'; + if (data[i]["is_hidden"]){ + b_status = '已隐藏'; + } + + body += ''+ + '' + data[i]["name"]+''+ + '' + b_status + ''+ + '' + + '删除' + ' | ' + + '编辑' + ' | ' + + '日志' + ' | ' + + '手动' + ' | ' + + '重命名' + + ''; + } + + } + + $('#gogs_self_table tbody').html(body); + $('#gogs_self_table .page').html(rdata['data']['list']); + + $('#gogs_self_table .status').click(function(){ + var i = $(this).data('index'); + var file = data[i]["name"]; + var status = '1'; + if (data[i]["is_hidden"]){ + status = '0'; + } + gogsPost('project_script_self_status', {'user':user,'name':name,'file':file, status:status}, function(data){ + var data = $.parseJSON(data.data); + showMsg(data.msg ,function(){ + projectScriptSelfRender(user, name); + },{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000); + }); + }); + + $('#gogs_self_table .del').click(function(){ + var i = $(this).data('index'); + var file = data[i]["name"]; + gogsPost('project_script_self_del', {'user':user,'name':name,'file':file}, function(data){ + var data = $.parseJSON(data.data); + showMsg(data.msg ,function(){ + projectScriptSelfRender(user, name); + },{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000); + }); + }); + + $('#gogs_self_table .edit').click(function(){ + var i = $(this).data('index'); + var path = data[i]["path"]; + onlineEditFile(0,path); + }); + + $('#gogs_self_table .logs').click(function(){ + var i = $(this).data('index'); + var file = data[i]["name"]; + gogsPost('project_script_self_logs', {'user':user,'name':name,'file':file}, function(data){ + var rdata = $.parseJSON(data.data); + // console.log(rdata); + if (rdata['status']){ + onlineEditFile(0, rdata['data']['path']); + } else { + layer.msg(rdata.msg,{icon:data.status?2:1,time:2000,shade: [0.3, '#000']}); + } + }); + }); + + $('#gogs_self_table .run').click(function(){ + var i = $(this).data('index'); + var file = data[i]["name"]; + if (data[i]["is_hidden"]){ + layer.msg("已经禁用,不能执行!",{icon:2,time:2000,shade: [0.3, '#000']}); + return; + } + gogsPost('project_script_self_run', {'user':user,'name':name,'file':file}, function(data){ + var rdata = $.parseJSON(data.data); + layer.msg(rdata.msg,{icon:data.status?1:2,time:2000,shade: [0.3, '#000']}); + }); + }); + + + $('#gogs_self_table .rename').click(function(){ + var i = $(this).data('index'); + var file = data[i]["name"]; + + if (data[i]["is_hidden"]){ + layer.msg("已经禁用,不能执行!",{icon:2,time:2000,shade: [0.3, '#000']}); + return; + } + + file = file.split('.sh')[0]; + + layer.open({ + type: 1, + shift: 5, + closeBtn: 1, + area: '320px', + title: '重命名', + btn:['设置','关闭'], + content: '
\ +
\ + \ +
\ +
', + success:function(){ + $("#newFileName").focus().keyup(function(e){ + if(e.keyCode == 13) $(".layui-layer-btn0").click(); + }); + }, + yes:function(){ + var n_file = $("#newFileName").val(); + var o_file = file; + + gogsPost('project_script_self_rename', {'user':user,'name':name,'o_file':o_file,'n_file':n_file}, function(data){ + var data = $.parseJSON(data.data); + showMsg(data.msg ,function(){ + $(".layui-layer-btn1").click(); + projectScriptSelfRender(user, name); + },{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000); + }); + } + }); + //----- + }); + //------ + }); +} + +//新建文件 +function createScriptFile(type, user, name, file) { + if (type == 1) { + gogsPost('project_script_self_create', {'user':user,'name':name,'file': file }, function(data){ + var rdata = $.parseJSON(data.data); + if(!rdata['status']){ + layer.msg(rdata.msg,{icon:2,time:2000,shade: [0.3, '#000']}); + return; + } + + showMsg(rdata.msg, function(){ + $(".layui-layer-btn1").click(); + onlineEditFile(0,rdata['data']['abs_file']); + projectScriptSelfRender(user, name); + }, {icon:1,shade: [0.3, '#000']},2000); + }); + return; + } + layer.open({ + type: 1, + shift: 5, + closeBtn: 1, + area: '320px', + title: '新建自定义脚本', + btn:['新建','关闭'], + content: '
\ +
\ + \ +
\ +
', + success:function(){ + $("#newFileName").focus().keyup(function(e){ + if(e.keyCode == 13) $(".layui-layer-btn0").click(); + }); + }, + yes:function(){ + var file = $("#newFileName").val();; + createScriptFile(1, user, name, file); + } + }); +} + +function projectScriptSelf(user, name){ + layer.open({ + type: 1, + title: '项目('+user+'/'+name+')自定义脚本', + area: '500px', + content:"
\ + \ +
\ + 开启自定义脚本\ + \ + \ +
\ +
\ + \ + \ + \ +
脚本文件名状态操作
\ + \ +
\ +
", + success:function(){ + projectScriptSelfRender(user, name); + + $('#create_script').click(function(){ + createScriptFile(0, user, name); + }); + + $('#script_hook_enable').click(function(){ + var enable = $('#open_script').prop('checked'); + var enable_option = '0'; + if (!enable){ + enable_option = '1'; + } + gogsPost('project_script_self_enable', {'user':user,'name':name,'enable':enable_option}, function(data){ + var data = $.parseJSON(data.data); + showMsg(data.msg ,function(){ + projectScriptSelfRender(user, name); + },{icon:data.status?1:2,shade: [0.3, '#000']},2000); + }); + + }); + } + }); +} + +function getRsaPublic(){ + gogsPost('get_rsa_public', {}, function(data){ + var rdata = $.parseJSON(data.data); + var con = '
\ +
\ + \ +
\ + \ +
' + layer.open({ + type: 1, + area: "600px", + title: '本机公钥', + closeBtn: 2, + shift: 5, + shadeClose: false, + content:con + }); + }); +} + +function dohRead(){ + + var readme = ''; + + $('.soft-man-con').html(readme); +} \ No newline at end of file