修复漏洞

This commit is contained in:
晚风拂柳颜 2024-01-02 19:52:29 +08:00
parent bc34e592ce
commit 173a5d4be3
5 changed files with 168 additions and 80 deletions

View File

@ -19,7 +19,7 @@ from utils.encode import base64Encode, base64Decode, fetch, post, request, getCr
from utils.encode import verifyCode, setDetail, join, urljoin2, parseText, requireCache, forceOrder, base64ToImage, \ from utils.encode import verifyCode, setDetail, join, urljoin2, parseText, requireCache, forceOrder, base64ToImage, \
encodeStr, decodeStr encodeStr, decodeStr
from utils.encode import md5 as mmd5 from utils.encode import md5 as mmd5
from utils.safePython import safePython from utils.safePython import safePython, safe_eval
from utils.parser import runPy, runJScode, JsObjectWrapper, PyJsObject, PyJsString from utils.parser import runPy, runJScode, JsObjectWrapper, PyJsObject, PyJsString
from utils.htmlParser import jsoup from utils.htmlParser import jsoup
from urllib.parse import urljoin, quote, unquote from urllib.parse import urljoin, quote, unquote
@ -185,7 +185,7 @@ class CMS:
if isinstance(HOST, PyJsString): # JsObjectWrapper if isinstance(HOST, PyJsString): # JsObjectWrapper
HOST = parseText(str(HOST)) HOST = parseText(str(HOST))
host = HOST.rstrip('/') host = HOST.rstrip('/')
print('host:',host) print('host:', host)
except Exception as e: except Exception as e:
logger.info(f'执行{hostJs}获取host发生错误:{e}') logger.info(f'执行{hostJs}获取host发生错误:{e}')
@ -828,8 +828,9 @@ class CMS:
# print(url_rep) # print(url_rep)
# print(cnt_page) # print(cnt_page)
cnt_ctx = {} cnt_ctx = {}
exec(f'cnt_pg={cnt_page}', cnt_ctx) safe_eval(f'cnt_pg={cnt_page}', cnt_ctx)
cnt_pg = str(cnt_ctx['cnt_pg']) # 计算表达式的结果 # exec(f'cnt_pg={cnt_page}', cnt_ctx)
cnt_pg = str(cnt_ctx['cnt_pg']) if cnt_ctx.get('cnt_pg') else 1 # 计算表达式的结果
url = url.replace(url_rep, str(cnt_pg)).replace('(', '').replace(')', '') url = url.replace(url_rep, str(cnt_pg)).replace('(', '').replace(')', '')
# print(url) # print(url)
else: else:
@ -1351,8 +1352,9 @@ class CMS:
# print(url_rep) # print(url_rep)
# print(cnt_page) # print(cnt_page)
cnt_ctx = {} cnt_ctx = {}
exec(f'cnt_pg={cnt_page}', cnt_ctx) # exec(f'cnt_pg={cnt_page}', cnt_ctx)
cnt_pg = str(cnt_ctx['cnt_pg']) # 计算表达式的结果 safe_eval(f'cnt_pg={cnt_page}', cnt_ctx)
cnt_pg = str(cnt_ctx['cnt_pg']) if cnt_ctx.get('cnt_pg') else 1 # 计算表达式的结果
url = url.replace(url_rep, str(cnt_pg)).replace('(', '').replace(')', '') url = url.replace(url_rep, str(cnt_pg)).replace('(', '').replace(')', '')
# print(url) # print(url)
else: else:

View File

@ -8,33 +8,35 @@ import ujson
import os import os
import re import re
from flask import Blueprint,abort,render_template,render_template_string,url_for,redirect,make_response,send_from_directory,request from flask import Blueprint, abort, render_template, render_template_string, url_for, redirect, make_response, \
from controllers.service import storage_service,rules_service,parse_service send_from_directory, request
from controllers.classes import getClasses,getClassInfo from controllers.service import storage_service, rules_service, parse_service
from controllers.classes import getClasses, getClassInfo
from utils.files import getPics,custom_merge,getAlist,get_live_url,get_multi_rules,getCustonDict from utils.files import getPics, custom_merge, getAlist, get_live_url, get_multi_rules, getCustonDict
from js.rules import getRules,getPys from js.rules import getRules, getPys
from utils.encode import parseText,base64Encode,base64Decode from utils.encode import parseText, base64Encode, base64Decode
from base.R import R from base.R import R
from utils.system import getHost,is_linux from utils.system import getHost, is_linux
from utils.cfg import cfg from utils.cfg import cfg
from utils import parser from utils import parser
from utils.ua import time,get_interval from utils.ua import time, get_interval
from utils.log import logger from utils.log import logger
from utils.update import getLocalVer,getHotSuggest from utils.update import getLocalVer, getHotSuggest
from js.rules import getJxs from js.rules import getJxs
import random import random
from utils.web import getParmas,verfy_token from utils.web import getParmas, verfy_token
from utils.common_api import js_render from utils.common_api import js_render
import functools import functools
home = Blueprint("home", __name__, static_folder='/static')
home = Blueprint("home", __name__,static_folder='/static')
@home.route('/') @home.route('/')
def forbidden(): # put application's code here def forbidden(): # put application's code here
abort(403) abort(403)
@home.route('/favicon.ico') # 设置icon @home.route('/favicon.ico') # 设置icon
def favicon(): def favicon():
# return home.send_static_file('img/favicon.svg') # return home.send_static_file('img/favicon.svg')
@ -42,6 +44,7 @@ def favicon():
# 对于当前文件所在路径,比如这里是static下的favicon.ico # 对于当前文件所在路径,比如这里是static下的favicon.ico
# return send_from_directory(os.path.join(app.root_path, 'static'), 'img/favicon.svg', mimetype='image/vnd.microsoft.icon') # return send_from_directory(os.path.join(app.root_path, 'static'), 'img/favicon.svg', mimetype='image/vnd.microsoft.icon')
@home.route('/index') @home.route('/index')
def index(): def index():
sup_port = cfg.get('SUP_PORT', 9001) sup_port = cfg.get('SUP_PORT', 9001)
@ -49,7 +52,7 @@ def index():
pid_url = lsg.getItem('PID_URL') pid_url = lsg.getItem('PID_URL')
manager0 = ':'.join(getHost(0).split(':')[0:2]) manager0 = ':'.join(getHost(0).split(':')[0:2])
manager1 = ':'.join(getHost(1).split(':')[0:2]) manager1 = ':'.join(getHost(1).split(':')[0:2])
manager2 = pid_url or ':'.join(getHost(2).split(':')[0:2]).replace('https','http') manager2 = pid_url or ':'.join(getHost(2).split(':')[0:2]).replace('https', 'http')
if sup_port: if sup_port:
manager0 += f':{sup_port}' manager0 += f':{sup_port}'
manager1 += f':{sup_port}' manager1 += f':{sup_port}'
@ -57,15 +60,25 @@ def index():
manager2 += f':{sup_port}' manager2 += f':{sup_port}'
# print(manager2) # print(manager2)
ver = getLocalVer() ver = getLocalVer()
return render_template('index.html',ver=ver,getHost=getHost,manager0=manager0,manager1=manager1,manager2=manager2,is_linux=is_linux()) return render_template('index.html', ver=ver, getHost=getHost, manager0=manager0, manager1=manager1,
manager2=manager2, is_linux=is_linux())
@home.route('/rules/clear') @home.route('/rules/clear')
def rules_to_clear(): def rules_to_clear():
return render_template('rules_to_clear.html',rules=getRules(),classes=getClasses()) if not verfy_token():
# return render_template('login.html')
return R.error('请登录后再试')
return render_template('rules_to_clear.html', rules=getRules(), classes=getClasses())
@home.route('/rules/view') @home.route('/rules/view')
def rules_to_view(): def rules_to_view():
return render_template('rules_to_view.html',rules=getRules(),classes=getClasses()) if not verfy_token():
# return render_template('login.html')
return R.error('请登录后再试')
return render_template('rules_to_view.html', rules=getRules(), classes=getClasses())
@home.route('/pics') @home.route('/pics')
def random_pics(): def random_pics():
@ -92,6 +105,7 @@ def random_pics():
else: else:
return redirect(new_conf.WALL_PAPER) return redirect(new_conf.WALL_PAPER)
@home.route('/clear') @home.route('/clear')
def clear_rule(): def clear_rule():
rule = getParmas('rule') rule = getParmas('rule')
@ -99,24 +113,26 @@ def clear_rule():
return R.failed('规则字段必填') return R.failed('规则字段必填')
cache_path = os.path.abspath(f'cache/{rule}.js') cache_path = os.path.abspath(f'cache/{rule}.js')
if not os.path.exists(cache_path): if not os.path.exists(cache_path):
return R.failed('服务端没有此规则的缓存文件!'+cache_path) return R.failed('服务端没有此规则的缓存文件!' + cache_path)
os.remove(cache_path) os.remove(cache_path)
return R.success('成功删除文件:'+cache_path) return R.success('成功删除文件:' + cache_path)
@home.route("/plugin/<name>",methods=['GET'])
@home.route("/plugin/<name>", methods=['GET'])
def plugin(name): def plugin(name):
# name=道长影视模板.js # name=道长影视模板.js
if not name or not name.split('.')[-1] in ['js','txt','py','json']: if not name or not name.split('.')[-1] in ['js', 'txt', 'py', 'json']:
return R.failed(f'非法猥亵,未指定文件名。必须包含js|txt|json|py') return R.failed(f'非法猥亵,未指定文件名。必须包含js|txt|json|py')
try: try:
return parser.toJs(name) return parser.toJs(name)
except Exception as e: except Exception as e:
return R.failed(f'非法猥亵\n{e}') return R.failed(f'非法猥亵\n{e}')
@home.route('/files/<name>') @home.route('/files/<name>')
def get_files(name): def get_files(name):
base_path = 'base/files' base_path = 'base/files'
os.makedirs(base_path,exist_ok=True) os.makedirs(base_path, exist_ok=True)
file_path = os.path.join(base_path, f'{name}') file_path = os.path.join(base_path, f'{name}')
if not os.path.exists(file_path): if not os.path.exists(file_path):
return R.failed(f'{file_path}文件不存在') return R.failed(f'{file_path}文件不存在')
@ -129,34 +145,39 @@ def get_files(name):
response.headers['Content-Disposition'] = f'attachment;filename="{filename}"' response.headers['Content-Disposition'] = f'attachment;filename="{filename}"'
return response return response
@home.route('/txt/<path:filename>') @home.route('/txt/<path:filename>')
def custom_static_txt(filename): def custom_static_txt(filename):
# 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}}
# print(filename) # print(filename)
return send_from_directory('txt', filename) return send_from_directory('txt', filename)
@home.route('/libs/<path:filename>') @home.route('/libs/<path:filename>')
def custom_static_libs(filename): def custom_static_libs(filename):
# 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}}
# print(filename) # print(filename)
return send_from_directory('libs', filename) return send_from_directory('libs', filename)
# @home.route('/js/<path:filename>') # @home.route('/js/<path:filename>')
# def custom_static_js(filename): # def custom_static_js(filename):
# # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}}
# # print(filename) # # print(filename)
# return send_from_directory('js', filename) # return send_from_directory('js', filename)
@home.route('/js/<path:name>',methods=['GET']) @home.route('/js/<path:name>', methods=['GET'])
def custom_static_js(name): def custom_static_js(name):
# 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}}
# print(name) # print(name)
return js_render(name) return js_render(name)
@home.route('/raw/js/<path:filename>') @home.route('/raw/js/<path:filename>')
def custom_raw_js(filename): def custom_raw_js(filename):
return send_from_directory('js', filename) return send_from_directory('js', filename)
# @home.route('/txt/<name>') # @home.route('/txt/<name>')
# def get_txt_files(name): # def get_txt_files(name):
# base_path = 'txt' # base_path = 'txt'
@ -177,14 +198,15 @@ def get_lives():
# ?path=base/live.txt # ?path=base/live.txt
path = getParmas('path') path = getParmas('path')
live_path = path or 'base/直播.txt' live_path = path or 'base/直播.txt'
if not re.search('(txt|json|conf)$',live_path,re.M|re.S) or not re.search('^(txt|base)',live_path,re.M|re.S): if not re.search('(txt|json|conf)$', live_path, re.M | re.S) or not re.search('^(txt|base)', live_path,
re.M | re.S):
abort(403) abort(403)
if not os.path.exists(live_path): if not os.path.exists(live_path):
# with open(live_path,mode='w+',encoding='utf-8') as f: # with open(live_path,mode='w+',encoding='utf-8') as f:
# f.write('') # f.write('')
return '' return ''
with open(live_path,encoding='utf-8') as f: with open(live_path, encoding='utf-8') as f:
live_text = f.read() live_text = f.read()
if len(live_text) > 100 and live_text.find('http') < 0: if len(live_text) > 100 and live_text.find('http') < 0:
try: try:
@ -196,6 +218,7 @@ def get_lives():
response.headers['Content-Type'] = 'text/plain; charset=utf-8' response.headers['Content-Type'] = 'text/plain; charset=utf-8'
return response return response
@home.route('/liveslib') @home.route('/liveslib')
def get_liveslib(): def get_liveslib():
lsg = storage_service() lsg = storage_service()
@ -203,10 +226,10 @@ def get_liveslib():
live_path = f'libs/jar/{SPIDER_JAR}' live_path = f'libs/jar/{SPIDER_JAR}'
logger.info(f'SPIDER_JAR{SPIDER_JAR}>>当前系统挂载的指定jar文件位置:{live_path}') logger.info(f'SPIDER_JAR{SPIDER_JAR}>>当前系统挂载的指定jar文件位置:{live_path}')
if not os.path.exists(live_path): if not os.path.exists(live_path):
with open(live_path,mode='w+',encoding='utf-8') as f: with open(live_path, mode='w+', encoding='utf-8') as f:
f.write('') f.write('')
with open(live_path,mode='rb') as f: with open(live_path, mode='rb') as f:
live_text = f.read() live_text = f.read()
response = make_response(live_text) response = make_response(live_text)
filename = 'custom_spider.jar' filename = 'custom_spider.jar'
@ -214,12 +237,14 @@ def get_liveslib():
response.headers['Content-Disposition'] = f'attachment;filename="{filename}"' response.headers['Content-Disposition'] = f'attachment;filename="{filename}"'
return response return response
@home.route('/hotsugg') @home.route('/hotsugg')
def get_hot_search(): def get_hot_search():
s_from = getParmas('from') s_from = getParmas('from')
size = getParmas('size') size = getParmas('size')
data = getHotSuggest(s_from,size) data = getHotSuggest(s_from, size)
return R.success('获取成功',data) return R.success('获取成功', data)
def merged_hide(merged_config): def merged_hide(merged_config):
t1 = time() t1 = time()
@ -230,14 +255,16 @@ def merged_hide(merged_config):
all_cnt = len(merged_config['sites']) all_cnt = len(merged_config['sites'])
def filter_show(x): def filter_show(x):
name = x['api'].split('rule=')[1].split('&')[0] if 'rule=' in x['api'] else x['key'].replace('dr_','') name = x['api'].split('rule=')[1].split('&')[0] if 'rule=' in x['api'] else x['key'].replace('dr_', '')
# print(name) # print(name)
if not str(x['key']).startswith('dr_') and name == 'drpy': if not str(x['key']).startswith('dr_') and name == 'drpy':
name = x['key'] name = x['key']
return name not in hide_rule_names return name not in hide_rule_names
merged_config['sites'] = list(filter(filter_show, merged_config['sites'])) merged_config['sites'] = list(filter(filter_show, merged_config['sites']))
logger.info(f'数据库筛选隐藏规则耗时{get_interval(t1)}毫秒,共计{all_cnt}条规则,隐藏后可渲染{len(merged_config["sites"])}条规则') logger.info(
f'数据库筛选隐藏规则耗时{get_interval(t1)}毫秒,共计{all_cnt}条规则,隐藏后可渲染{len(merged_config["sites"])}条规则')
@home.route('/config/<int:mode>') @home.route('/config/<int:mode>')
def config_render(mode): def config_render(mode):
@ -248,7 +275,7 @@ def config_render(mode):
m = getParmas('mode') m = getParmas('mode')
sp = getParmas('sp') # 优选 sp = getParmas('sp') # 优选
logger.info(f'ver:{ver},UA:{UA}') logger.info(f'ver:{ver},UA:{UA}')
if ver not in ['1','2']: if ver not in ['1', '2']:
ISTVB = 'okhttp/3' in UA ISTVB = 'okhttp/3' in UA
elif ver == '1': elif ver == '1':
ISTVB = False ISTVB = False
@ -278,7 +305,7 @@ def config_render(mode):
pass pass
print(f'{type(js_mode)} jsmode:{js_mode}') print(f'{type(js_mode)} jsmode:{js_mode}')
# print(ali_token) # print(ali_token)
customConfig = getCustonDict(host,ali_token,js0_password) customConfig = getCustonDict(host, ali_token, js0_password)
# print(customConfig) # print(customConfig)
jxs = getJxs(host=host) jxs = getJxs(host=host)
use_py = lsg.getItem('USE_PY') use_py = lsg.getItem('USE_PY')
@ -286,8 +313,8 @@ def config_render(mode):
# print(pys) # print(pys)
alists = getAlist() alists = getAlist()
alists_str = json.dumps(alists, ensure_ascii=False) alists_str = json.dumps(alists, ensure_ascii=False)
live_url = get_live_url(new_conf,mode) live_url = get_live_url(new_conf, mode)
rules = getRules('js',js_mode) rules = getRules('js', js_mode)
rules = get_multi_rules(rules) rules = get_multi_rules(rules)
# html = render_template('config.txt',rules=getRules('js'),host=host,mode=mode,jxs=jxs,base64Encode=base64Encode,config=new_conf) # html = render_template('config.txt',rules=getRules('js'),host=host,mode=mode,jxs=jxs,base64Encode=base64Encode,config=new_conf)
if new_conf.EXT_FUNC and new_conf.EXT_FUNC.strip(): if new_conf.EXT_FUNC and new_conf.EXT_FUNC.strip():
@ -300,23 +327,25 @@ def config_render(mode):
else: else:
new_conf.EXT_FUNC = [] new_conf.EXT_FUNC = []
html = render_template('config.txt',js0_password=js0_password,UA=UA,xr_mode=xr_mode,ISTVB=ISTVB,pys=pys,rules=rules,host=host,mode=mode,js_mode=js_mode,jxs=jxs,alists=alists,alists_str=alists_str,live_url=live_url,config=new_conf) html = render_template('config.txt', js0_password=js0_password, UA=UA, xr_mode=xr_mode, ISTVB=ISTVB, pys=pys,
merged_config = custom_merge(parseText(html),customConfig) rules=rules, host=host, mode=mode, js_mode=js_mode, jxs=jxs, alists=alists,
alists_str=alists_str, live_url=live_url, config=new_conf)
merged_config = custom_merge(parseText(html), customConfig)
# print(merged_config['sites']) # print(merged_config['sites'])
merged_hide(merged_config) merged_hide(merged_config)
# response = make_response(html) # response = make_response(html)
# print(len(merged_config['sites'])) # print(len(merged_config['sites']))
# print(merged_config['sites']) # print(merged_config['sites'])
merged_config['sites'] = sort_sites_by_order(merged_config['sites'],js_mode) merged_config['sites'] = sort_sites_by_order(merged_config['sites'], js_mode)
# print(merged_config['sites']) # print(merged_config['sites'])
if sp: # 执行动态优选源 if sp: # 执行动态优选源
special_rule(merged_config,lsg) special_rule(merged_config, lsg)
# print(merged_config['parses']) # print(merged_config['parses'])
parses = sort_parses_by_order(merged_config['parses'],host) parses = sort_parses_by_order(merged_config['parses'], host)
# print(parses) # print(parses)
merged_config['parses'] = parses merged_config['parses'] = parses
config_text = json.dumps(merged_config,ensure_ascii=False,indent=1) config_text = json.dumps(merged_config, ensure_ascii=False, indent=1)
# 依赖代理逻辑修改,改为admin/view去动态代理 # 依赖代理逻辑修改,改为admin/view去动态代理
# if js_proxy: # if js_proxy:
@ -333,7 +362,8 @@ def config_render(mode):
logger.info(f'自动生成动态配置共计耗时:{get_interval(tt)}毫秒') logger.info(f'自动生成动态配置共计耗时:{get_interval(tt)}毫秒')
return response return response
def special_rule(merged_config,lsg):
def special_rule(merged_config, lsg):
# print(merged_config['sites']) # print(merged_config['sites'])
special = lsg.getItem('SPECIAL').strip() special = lsg.getItem('SPECIAL').strip()
# print('SPECIAL',special) # print('SPECIAL',special)
@ -350,6 +380,7 @@ def special_rule(merged_config,lsg):
merged_config['sites'] = special_st merged_config['sites'] = special_st
merged_config['dr_count'] = len(special_st) merged_config['dr_count'] = len(special_st)
def comp(x, y): def comp(x, y):
if x['order'] > y['order']: if x['order'] > y['order']:
return 1 return 1
@ -363,7 +394,8 @@ def comp(x, y):
else: else:
return 0 return 0
def sort_sites_by_order(sites,js_mode=0):
def sort_sites_by_order(sites, js_mode=0):
rules = rules_service() rules = rules_service()
rule_list = rules.query_all() rule_list = rules.query_all()
# print(rule_list) # print(rule_list)
@ -374,7 +406,7 @@ def sort_sites_by_order(sites,js_mode=0):
# sites[i]['id'] = i+1 # sites[i]['id'] = i+1
site_name = sites[i]['api'].split('rule=')[1].split('&')[0] if 'rule=' in sites[i]['api'] else sites[i]['key'] site_name = sites[i]['api'].split('rule=')[1].split('&')[0] if 'rule=' in sites[i]['api'] else sites[i]['key']
if js_mode and str(site_name).startswith('dr'): if js_mode and str(site_name).startswith('dr'):
site_name = site_name.replace('dr_','') site_name = site_name.replace('dr_', '')
if not str(sites[i]['key']).startswith('dr_') and site_name == 'drpy': if not str(sites[i]['key']).startswith('dr_') and site_name == 'drpy':
site_name = sites[i]['key'] site_name = sites[i]['key']
# print(sites[i]) # print(sites[i])
@ -399,7 +431,8 @@ def sort_sites_by_order(sites,js_mode=0):
del site['write_date'] del site['write_date']
return sites return sites
def sort_parses_by_order(parses,host):
def sort_parses_by_order(parses, host):
t1 = time() t1 = time()
parse = parse_service() parse = parse_service()
parse_list = parse.query_all() parse_list = parse.query_all()
@ -413,7 +446,7 @@ def sort_parses_by_order(parses,host):
# print(f"重复的解析:{parses[i]['name']},{parses[i]['url']}") # print(f"重复的解析:{parses[i]['name']},{parses[i]['url']}")
continue continue
if str(parses[i]['url']).startswith(host): if str(parses[i]['url']).startswith(host):
parses[i]['url'] = parses[i]['url'].replace(host,'') parses[i]['url'] = parses[i]['url'].replace(host, '')
if parses[i]['url'] in parse_url_list: if parses[i]['url'] in parse_url_list:
parse_rule = parse_list[parse_url_list.index(parses[i]['url'])] parse_rule = parse_list[parse_url_list.index(parses[i]['url'])]
parses[i]['state'] = 1 if parse_rule['state'] is None else parse_rule['state'] parses[i]['state'] = 1 if parse_rule['state'] is None else parse_rule['state']
@ -441,12 +474,13 @@ def sort_parses_by_order(parses,host):
logger.info(f'{len(new_parses)}/{len(parses)}条解析解析排序耗时:{get_interval(t1)}毫秒') logger.info(f'{len(new_parses)}/{len(parses)}条解析解析排序耗时:{get_interval(t1)}毫秒')
return new_parses return new_parses
@home.route('/configs') @home.route('/configs')
def config_gen(): def config_gen():
if not verfy_token(): if not verfy_token():
return R.failed('请登录后再试') return R.failed('请登录后再试')
# 生成文件 # 生成文件
os.makedirs('txt',exist_ok=True) os.makedirs('txt', exist_ok=True)
new_conf = cfg new_conf = cfg
lsg = storage_service() lsg = storage_service()
store_conf_dict = lsg.getStoreConfDict() store_conf_dict = lsg.getStoreConfDict()
@ -466,24 +500,30 @@ def config_gen():
js0_password = new_conf.JS0_PASSWORD js0_password = new_conf.JS0_PASSWORD
pys = getPys() if use_py else False pys = getPys() if use_py else False
alists = getAlist() alists = getAlist()
alists_str = json.dumps(alists,ensure_ascii=False) alists_str = json.dumps(alists, ensure_ascii=False)
rules = getRules('js',js_mode) rules = getRules('js', js_mode)
rules = get_multi_rules(rules) rules = get_multi_rules(rules)
host0 = getHost(0) host0 = getHost(0)
jxs = getJxs(host=host0) jxs = getJxs(host=host0)
set_local = render_template('config.txt',js0_password=js0_password,pys=pys,rules=rules,alists=alists,alists_str=alists_str,live_url=get_live_url(new_conf,0),mode=0,js_mode=js_mode,host=host0,jxs=jxs,config=new_conf) set_local = render_template('config.txt', js0_password=js0_password, pys=pys, rules=rules, alists=alists,
alists_str=alists_str, live_url=get_live_url(new_conf, 0), mode=0, js_mode=js_mode,
host=host0, jxs=jxs, config=new_conf)
# print(set_local) # print(set_local)
host1 = getHost(1) host1 = getHost(1)
jxs = getJxs(host=host1) jxs = getJxs(host=host1)
set_area = render_template('config.txt',js0_password=js0_password,pys=pys,rules=rules,alists=alists,alists_str=alists_str,live_url=get_live_url(new_conf,1),mode=1,js_mode=js_mode,host=host1,jxs=jxs,config=new_conf) set_area = render_template('config.txt', js0_password=js0_password, pys=pys, rules=rules, alists=alists,
alists_str=alists_str, live_url=get_live_url(new_conf, 1), mode=1, js_mode=js_mode,
host=host1, jxs=jxs, config=new_conf)
host2 = getHost(2) or host1 host2 = getHost(2) or host1
# print('远程地址:'+host2) # print('远程地址:'+host2)
jxs = getJxs(host=host2) jxs = getJxs(host=host2)
set_online = render_template('config.txt',js0_password=js0_password,pys=pys,rules=rules,alists=alists,alists_str=alists_str,live_url=get_live_url(new_conf,2),mode=1,js_mode=js_mode,host=host2,jxs=jxs,config=new_conf) set_online = render_template('config.txt', js0_password=js0_password, pys=pys, rules=rules, alists=alists,
alists_str=alists_str, live_url=get_live_url(new_conf, 2), mode=1, js_mode=js_mode,
host=host2, jxs=jxs, config=new_conf)
ali_token = new_conf.ALI_TOKEN ali_token = new_conf.ALI_TOKEN
# parses = [] # parses = []
with open('txt/pycms0.json','w+',encoding='utf-8') as f: with open('txt/pycms0.json', 'w+', encoding='utf-8') as f:
customConfig = getCustonDict(host0,ali_token,js0_password) customConfig = getCustonDict(host0, ali_token, js0_password)
set_dict = custom_merge(parseText(set_local), customConfig) set_dict = custom_merge(parseText(set_local), customConfig)
merged_hide(set_dict) merged_hide(set_dict)
set_dict['sites'] = sort_sites_by_order(set_dict['sites'], js_mode) set_dict['sites'] = sort_sites_by_order(set_dict['sites'], js_mode)
@ -491,33 +531,37 @@ def config_gen():
# print('生成静态配置时初始化排序parses') # print('生成静态配置时初始化排序parses')
# parses = sort_parses_by_order(set_dict['parses']) # parses = sort_parses_by_order(set_dict['parses'])
# set_dict['parses'] = parses # set_dict['parses'] = parses
set_dict['parses'] = sort_parses_by_order(set_dict['parses'],host0) set_dict['parses'] = sort_parses_by_order(set_dict['parses'], host0)
# set_dict = json.loads(set_local) # set_dict = json.loads(set_local)
f.write(json.dumps(set_dict,ensure_ascii=False,indent=4)) f.write(json.dumps(set_dict, ensure_ascii=False, indent=4))
with open('txt/pycms1.json','w+',encoding='utf-8') as f: with open('txt/pycms1.json', 'w+', encoding='utf-8') as f:
customConfig = getCustonDict(host1,ali_token,js0_password) customConfig = getCustonDict(host1, ali_token, js0_password)
set_dict = custom_merge(parseText(set_area), customConfig) set_dict = custom_merge(parseText(set_area), customConfig)
merged_hide(set_dict) merged_hide(set_dict)
set_dict['sites'] = sort_sites_by_order(set_dict['sites'], js_mode) set_dict['sites'] = sort_sites_by_order(set_dict['sites'], js_mode)
set_dict['parses'] = sort_parses_by_order(set_dict['parses'],host1) set_dict['parses'] = sort_parses_by_order(set_dict['parses'], host1)
# set_dict = json.loads(set_area) # set_dict = json.loads(set_area)
f.write(json.dumps(set_dict,ensure_ascii=False,indent=4)) f.write(json.dumps(set_dict, ensure_ascii=False, indent=4))
with open('txt/pycms2.json','w+',encoding='utf-8') as f: with open('txt/pycms2.json', 'w+', encoding='utf-8') as f:
customConfig = getCustonDict(host2,ali_token,js0_password) customConfig = getCustonDict(host2, ali_token, js0_password)
set_dict = custom_merge(parseText(set_online), customConfig) set_dict = custom_merge(parseText(set_online), customConfig)
merged_hide(set_dict) merged_hide(set_dict)
set_dict['sites'] = sort_sites_by_order(set_dict['sites'], js_mode) set_dict['sites'] = sort_sites_by_order(set_dict['sites'], js_mode)
set_dict['parses'] = sort_parses_by_order(set_dict['parses'],host2) set_dict['parses'] = sort_parses_by_order(set_dict['parses'], host2)
# set_dict = json.loads(set_online) # set_dict = json.loads(set_online)
f.write(json.dumps(set_dict,ensure_ascii=False,indent=4)) f.write(json.dumps(set_dict, ensure_ascii=False, indent=4))
files = [os.path.abspath(rf'txt\pycms{i}.json') for i in range(3)] files = [os.path.abspath(rf'txt\pycms{i}.json') for i in range(3)]
# print(files) # print(files)
return R.success('猫配置生成完毕,文件位置在:\n'+'\n'.join(files)) return R.success('猫配置生成完毕,文件位置在:\n' + '\n'.join(files))
except Exception as e: except Exception as e:
return R.failed(f'配置文件生成错误:\n{e}') return R.failed(f'配置文件生成错误:\n{e}')
@home.route("/info",methods=['get'])
@home.route("/info", methods=['get'])
def info_all(): def info_all():
if not verfy_token():
# return render_template('login.html')
return R.error('请登录后再试')
data = storage_service.query_all() data = storage_service.query_all()
return R.ok(data=data) return R.ok(data=data)

View File

@ -1,3 +1,6 @@
###### 2024/01/02
- [X] 3.9.49beta11 fixed issues#49
###### 2023/11/25 ###### 2023/11/25
- [X] 3.9.49beta8 增加直播转换小工具 - [X] 3.9.49beta8 增加直播转换小工具
@ -11,6 +14,7 @@
```shell ```shell
git config --global http.proxy http://127.0.0.1:10808 git config --global http.proxy http://127.0.0.1:10808
git config --global https.proxy http://127.0.0.1:10808 git config --global https.proxy http://127.0.0.1:10808
git config --global --unset http.proxy
# 我的v2vary在10808上系统代理 # 我的v2vary在10808上系统代理
``` ```

View File

@ -1 +1 @@
3.9.49beta10 3.9.49beta11

View File

@ -9,7 +9,7 @@ import tokenize
from func_timeout import func_set_timeout from func_timeout import func_set_timeout
from func_timeout.exceptions import FunctionTimedOut from func_timeout.exceptions import FunctionTimedOut
from urllib.parse import urljoin,quote,unquote from urllib.parse import urljoin, quote, unquote
import requests import requests
import time import time
import json import json
@ -20,6 +20,8 @@ import base64
from utils.log import logger from utils.log import logger
time_out_sec = 8 # 安全执行python代码超时 time_out_sec = 8 # 安全执行python代码超时
class my_exception(Exception): class my_exception(Exception):
def __init__(self, message): def __init__(self, message):
self.message = message self.message = message
@ -28,10 +30,12 @@ class my_exception(Exception):
message = f'函数执行超时: "{self.message}"' message = f'函数执行超时: "{self.message}"'
return message return message
@func_set_timeout(time_out_sec) @func_set_timeout(time_out_sec)
def excute(*args): def excute(*args):
exec(*args) exec(*args)
def check_unsafe_attributes(string): def check_unsafe_attributes(string):
""" """
安全检测需要exec执行的python代码 安全检测需要exec执行的python代码
@ -48,6 +52,7 @@ def check_unsafe_attributes(string):
elif toktype == tokenize.OP: elif toktype == tokenize.OP:
pre_op = tokval pre_op = tokval
DEFAULT_PYTHON_CODE = """# 可用内置环境变量: DEFAULT_PYTHON_CODE = """# 可用内置环境变量:
# - log: log(message): 打印日志功能 # - log: log(message): 打印日志功能
# - error: 弹出用户错误的弹窗 # - error: 弹出用户错误的弹窗
@ -57,12 +62,45 @@ zyw_lists = env['hikerule.zyw.list'].with_context(active_test=True).sudo().searc
result = env['hikerule.zyw.list2data.wizard'].sudo().get_publish_value(zyw_lists) result = env['hikerule.zyw.list2data.wizard'].sudo().get_publish_value(zyw_lists)
""" """
def safe_eval(code: str = '', localdict: dict = None):
code = code.strip()
logger.info('code:' + code)
if not code:
return {}
if localdict is None:
localdict = {}
builtins = __builtins__
builtins = dict(builtins).copy()
for key in ['__import__', 'eval', 'exec', 'globals', 'dir', 'copyright', 'open', 'quit']:
del builtins[key] # 删除不安全的关键字
# print(builtins)
global_dict = {'__builtins__': builtins,
'requests': requests, 'urljoin': urljoin, 'quote': quote, 'unquote': unquote,
'log': logger.info, 'json': json, 'print': print,
're': re, 'etree': etree, 'time': time, 'datetime': datetime, 'base64': base64
} # 禁用内置函数,不允许导入包
try:
check_unsafe_attributes(code)
# 待解决windows下运行超时的问题
try:
# excute(to_run_code, global_dict, localdict)
excute(code, global_dict, localdict)
return localdict
except FunctionTimedOut:
raise my_exception(f'safe_eval运行时间超过{time_out_sec}秒,疑似死循环,已被系统切断')
except Exception as e:
ret = f'执行报错:{e}'
logger.info(ret)
return ret
class safePython: class safePython:
def __init__(self,name, code): def __init__(self, name, code):
self.name = name or '未定义' self.name = name or '未定义'
self.code = code self.code = code
def action_task_exec(self,call=None,params=None): def action_task_exec(self, call=None, params=None):
""" """
接口调用执行函数 接口调用执行函数
:return: :return:
@ -71,13 +109,13 @@ class safePython:
params = [] params = []
builtins = __builtins__ builtins = __builtins__
builtins = dict(builtins).copy() builtins = dict(builtins).copy()
for key in ['__import__','eval','exec','globals','dir','copyright','open','quit']: for key in ['__import__', 'eval', 'exec', 'globals', 'dir', 'copyright', 'open', 'quit']:
del builtins[key] # 删除不安全的关键字 del builtins[key] # 删除不安全的关键字
# print(builtins) # print(builtins)
global_dict = {'__builtins__': builtins, global_dict = {'__builtins__': builtins,
'requests': requests, 'urljoin':urljoin,'quote':quote,'unquote': unquote, 'requests': requests, 'urljoin': urljoin, 'quote': quote, 'unquote': unquote,
'log': logger.info, 'json': json,'print':print, 'log': logger.info, 'json': json, 'print': print,
're':re,'etree':etree,'time':time,'datetime':datetime,'base64':base64 're': re, 'etree': etree, 'time': time, 'datetime': datetime, 'base64': base64
} # 禁用内置函数,不允许导入包 } # 禁用内置函数,不允许导入包
try: try:
check_unsafe_attributes(self.code) check_unsafe_attributes(self.code)
@ -102,4 +140,4 @@ class safePython:
# print(global_dict) # print(global_dict)
# print(localdict) # print(localdict)
ret = localdict['result'] ret = localdict['result']
return ret return ret