diff --git a/controllers/cms.py b/controllers/cms.py index 4cd6bf5..c5f89bb 100644 --- a/controllers/cms.py +++ b/controllers/cms.py @@ -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, \ encodeStr, decodeStr 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.htmlParser import jsoup from urllib.parse import urljoin, quote, unquote @@ -185,7 +185,7 @@ class CMS: if isinstance(HOST, PyJsString): # JsObjectWrapper HOST = parseText(str(HOST)) host = HOST.rstrip('/') - print('host:',host) + print('host:', host) except Exception as e: logger.info(f'执行{hostJs}获取host发生错误:{e}') @@ -828,8 +828,9 @@ class CMS: # print(url_rep) # print(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) + # 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(')', '') # print(url) else: @@ -1351,8 +1352,9 @@ class CMS: # print(url_rep) # print(cnt_page) cnt_ctx = {} - exec(f'cnt_pg={cnt_page}', cnt_ctx) - cnt_pg = str(cnt_ctx['cnt_pg']) # 计算表达式的结果 + # exec(f'cnt_pg={cnt_page}', cnt_ctx) + 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(')', '') # print(url) else: diff --git a/controllers/home.py b/controllers/home.py index 9501830..f2fb098 100644 --- a/controllers/home.py +++ b/controllers/home.py @@ -8,33 +8,35 @@ import ujson import os import re -from flask import Blueprint,abort,render_template,render_template_string,url_for,redirect,make_response,send_from_directory,request -from controllers.service import storage_service,rules_service,parse_service -from controllers.classes import getClasses,getClassInfo +from flask import Blueprint, abort, render_template, render_template_string, url_for, redirect, make_response, \ + send_from_directory, request +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 js.rules import getRules,getPys -from utils.encode import parseText,base64Encode,base64Decode +from utils.files import getPics, custom_merge, getAlist, get_live_url, get_multi_rules, getCustonDict +from js.rules import getRules, getPys +from utils.encode import parseText, base64Encode, base64Decode 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 import parser -from utils.ua import time,get_interval +from utils.ua import time, get_interval from utils.log import logger -from utils.update import getLocalVer,getHotSuggest +from utils.update import getLocalVer, getHotSuggest from js.rules import getJxs import random -from utils.web import getParmas,verfy_token +from utils.web import getParmas, verfy_token from utils.common_api import js_render import functools +home = Blueprint("home", __name__, static_folder='/static') -home = Blueprint("home", __name__,static_folder='/static') @home.route('/') def forbidden(): # put application's code here abort(403) + @home.route('/favicon.ico') # 设置icon def favicon(): # return home.send_static_file('img/favicon.svg') @@ -42,6 +44,7 @@ def favicon(): # 对于当前文件所在路径,比如这里是static下的favicon.ico # return send_from_directory(os.path.join(app.root_path, 'static'), 'img/favicon.svg', mimetype='image/vnd.microsoft.icon') + @home.route('/index') def index(): sup_port = cfg.get('SUP_PORT', 9001) @@ -49,7 +52,7 @@ def index(): pid_url = lsg.getItem('PID_URL') manager0 = ':'.join(getHost(0).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: manager0 += f':{sup_port}' manager1 += f':{sup_port}' @@ -57,15 +60,25 @@ def index(): manager2 += f':{sup_port}' # print(manager2) 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') 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') 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') def random_pics(): @@ -92,6 +105,7 @@ def random_pics(): else: return redirect(new_conf.WALL_PAPER) + @home.route('/clear') def clear_rule(): rule = getParmas('rule') @@ -99,24 +113,26 @@ def clear_rule(): return R.failed('规则字段必填') cache_path = os.path.abspath(f'cache/{rule}.js') if not os.path.exists(cache_path): - return R.failed('服务端没有此规则的缓存文件!'+cache_path) + return R.failed('服务端没有此规则的缓存文件!' + cache_path) os.remove(cache_path) - return R.success('成功删除文件:'+cache_path) + return R.success('成功删除文件:' + cache_path) -@home.route("/plugin/",methods=['GET']) + +@home.route("/plugin/", methods=['GET']) def plugin(name): # 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') try: return parser.toJs(name) except Exception as e: return R.failed(f'非法猥亵\n{e}') + @home.route('/files/') def get_files(name): 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}') if not os.path.exists(file_path): return R.failed(f'{file_path}文件不存在') @@ -129,34 +145,39 @@ def get_files(name): response.headers['Content-Disposition'] = f'attachment;filename="{filename}"' return response + @home.route('/txt/') def custom_static_txt(filename): # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # print(filename) return send_from_directory('txt', filename) + @home.route('/libs/') def custom_static_libs(filename): # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # print(filename) return send_from_directory('libs', filename) + # @home.route('/js/') # def custom_static_js(filename): # # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # # print(filename) # return send_from_directory('js', filename) -@home.route('/js/',methods=['GET']) +@home.route('/js/', methods=['GET']) def custom_static_js(name): # 自定义静态目录 {{ url_for('custom_static',filename='help.txt')}} # print(name) return js_render(name) + @home.route('/raw/js/') def custom_raw_js(filename): return send_from_directory('js', filename) + # @home.route('/txt/') # def get_txt_files(name): # base_path = 'txt' @@ -177,14 +198,15 @@ def get_lives(): # ?path=base/live.txt path = getParmas('path') 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) if not os.path.exists(live_path): # with open(live_path,mode='w+',encoding='utf-8') as f: # f.write('') return '' - with open(live_path,encoding='utf-8') as f: + with open(live_path, encoding='utf-8') as f: live_text = f.read() if len(live_text) > 100 and live_text.find('http') < 0: try: @@ -196,6 +218,7 @@ def get_lives(): response.headers['Content-Type'] = 'text/plain; charset=utf-8' return response + @home.route('/liveslib') def get_liveslib(): lsg = storage_service() @@ -203,10 +226,10 @@ def get_liveslib(): live_path = f'libs/jar/{SPIDER_JAR}' logger.info(f'SPIDER_JAR:{SPIDER_JAR}>>当前系统挂载的指定jar文件位置:{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('') - with open(live_path,mode='rb') as f: + with open(live_path, mode='rb') as f: live_text = f.read() response = make_response(live_text) filename = 'custom_spider.jar' @@ -214,12 +237,14 @@ def get_liveslib(): response.headers['Content-Disposition'] = f'attachment;filename="{filename}"' return response + @home.route('/hotsugg') def get_hot_search(): s_from = getParmas('from') size = getParmas('size') - data = getHotSuggest(s_from,size) - return R.success('获取成功',data) + data = getHotSuggest(s_from, size) + return R.success('获取成功', data) + def merged_hide(merged_config): t1 = time() @@ -230,14 +255,16 @@ def merged_hide(merged_config): all_cnt = len(merged_config['sites']) 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) if not str(x['key']).startswith('dr_') and name == 'drpy': name = x['key'] return name not in hide_rule_names 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/') def config_render(mode): @@ -248,7 +275,7 @@ def config_render(mode): m = getParmas('mode') sp = getParmas('sp') # 优选 logger.info(f'ver:{ver},UA:{UA}') - if ver not in ['1','2']: + if ver not in ['1', '2']: ISTVB = 'okhttp/3' in UA elif ver == '1': ISTVB = False @@ -278,7 +305,7 @@ def config_render(mode): pass print(f'{type(js_mode)} jsmode:{js_mode}') # print(ali_token) - customConfig = getCustonDict(host,ali_token,js0_password) + customConfig = getCustonDict(host, ali_token, js0_password) # print(customConfig) jxs = getJxs(host=host) use_py = lsg.getItem('USE_PY') @@ -286,8 +313,8 @@ def config_render(mode): # print(pys) alists = getAlist() alists_str = json.dumps(alists, ensure_ascii=False) - live_url = get_live_url(new_conf,mode) - rules = getRules('js',js_mode) + live_url = get_live_url(new_conf, mode) + rules = getRules('js', js_mode) rules = get_multi_rules(rules) # 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(): @@ -300,23 +327,25 @@ def config_render(mode): else: 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) - merged_config = custom_merge(parseText(html),customConfig) + 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) + merged_config = custom_merge(parseText(html), customConfig) # print(merged_config['sites']) merged_hide(merged_config) # response = make_response(html) # print(len(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']) if sp: # 执行动态优选源 - special_rule(merged_config,lsg) + special_rule(merged_config, lsg) # print(merged_config['parses']) - parses = sort_parses_by_order(merged_config['parses'],host) + parses = sort_parses_by_order(merged_config['parses'], host) # print(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去动态代理 # if js_proxy: @@ -333,7 +362,8 @@ def config_render(mode): logger.info(f'自动生成动态配置共计耗时:{get_interval(tt)}毫秒') return response -def special_rule(merged_config,lsg): + +def special_rule(merged_config, lsg): # print(merged_config['sites']) special = lsg.getItem('SPECIAL').strip() # print('SPECIAL:',special) @@ -350,6 +380,7 @@ def special_rule(merged_config,lsg): merged_config['sites'] = special_st merged_config['dr_count'] = len(special_st) + def comp(x, y): if x['order'] > y['order']: return 1 @@ -363,7 +394,8 @@ def comp(x, y): else: return 0 -def sort_sites_by_order(sites,js_mode=0): + +def sort_sites_by_order(sites, js_mode=0): rules = rules_service() rule_list = rules.query_all() # print(rule_list) @@ -374,7 +406,7 @@ def sort_sites_by_order(sites,js_mode=0): # 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'] 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': site_name = sites[i]['key'] # print(sites[i]) @@ -399,7 +431,8 @@ def sort_sites_by_order(sites,js_mode=0): del site['write_date'] return sites -def sort_parses_by_order(parses,host): + +def sort_parses_by_order(parses, host): t1 = time() parse = parse_service() parse_list = parse.query_all() @@ -413,7 +446,7 @@ def sort_parses_by_order(parses,host): # print(f"重复的解析:{parses[i]['name']},{parses[i]['url']}") continue 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: 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'] @@ -441,12 +474,13 @@ def sort_parses_by_order(parses,host): logger.info(f'{len(new_parses)}/{len(parses)}条解析解析排序耗时:{get_interval(t1)}毫秒') return new_parses + @home.route('/configs') def config_gen(): if not verfy_token(): return R.failed('请登录后再试') # 生成文件 - os.makedirs('txt',exist_ok=True) + os.makedirs('txt', exist_ok=True) new_conf = cfg lsg = storage_service() store_conf_dict = lsg.getStoreConfDict() @@ -466,24 +500,30 @@ def config_gen(): js0_password = new_conf.JS0_PASSWORD pys = getPys() if use_py else False alists = getAlist() - alists_str = json.dumps(alists,ensure_ascii=False) - rules = getRules('js',js_mode) + alists_str = json.dumps(alists, ensure_ascii=False) + rules = getRules('js', js_mode) rules = get_multi_rules(rules) host0 = getHost(0) 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) host1 = getHost(1) 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 # print('远程地址:'+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 # parses = [] - with open('txt/pycms0.json','w+',encoding='utf-8') as f: - customConfig = getCustonDict(host0,ali_token,js0_password) + with open('txt/pycms0.json', 'w+', encoding='utf-8') as f: + customConfig = getCustonDict(host0, ali_token, js0_password) set_dict = custom_merge(parseText(set_local), customConfig) merged_hide(set_dict) set_dict['sites'] = sort_sites_by_order(set_dict['sites'], js_mode) @@ -491,33 +531,37 @@ def config_gen(): # print('生成静态配置时初始化排序parses') # parses = sort_parses_by_order(set_dict['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) - f.write(json.dumps(set_dict,ensure_ascii=False,indent=4)) - with open('txt/pycms1.json','w+',encoding='utf-8') as f: - customConfig = getCustonDict(host1,ali_token,js0_password) + f.write(json.dumps(set_dict, ensure_ascii=False, indent=4)) + with open('txt/pycms1.json', 'w+', encoding='utf-8') as f: + customConfig = getCustonDict(host1, ali_token, js0_password) set_dict = custom_merge(parseText(set_area), customConfig) merged_hide(set_dict) 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) - 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: - customConfig = getCustonDict(host2,ali_token,js0_password) + with open('txt/pycms2.json', 'w+', encoding='utf-8') as f: + customConfig = getCustonDict(host2, ali_token, js0_password) set_dict = custom_merge(parseText(set_online), customConfig) merged_hide(set_dict) 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) - 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)] # print(files) - return R.success('猫配置生成完毕,文件位置在:\n'+'\n'.join(files)) + return R.success('猫配置生成完毕,文件位置在:\n' + '\n'.join(files)) except Exception as e: return R.failed(f'配置文件生成错误:\n{e}') -@home.route("/info",methods=['get']) + +@home.route("/info", methods=['get']) def info_all(): + if not verfy_token(): + # return render_template('login.html') + return R.error('请登录后再试') data = storage_service.query_all() - return R.ok(data=data) \ No newline at end of file + return R.ok(data=data) diff --git a/doc/更新日志.md b/doc/更新日志.md index abbe750..bdd842e 100644 --- a/doc/更新日志.md +++ b/doc/更新日志.md @@ -1,3 +1,6 @@ +###### 2024/01/02 +- [X] 3.9.49beta11 fixed issues#49 + ###### 2023/11/25 - [X] 3.9.49beta8 增加直播转换小工具 @@ -11,6 +14,7 @@ ```shell 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 --unset http.proxy # 我的v2vary在10808上系统代理 ``` diff --git a/js/version.txt b/js/version.txt index 44470f3..8d5213d 100644 --- a/js/version.txt +++ b/js/version.txt @@ -1 +1 @@ -3.9.49beta10 \ No newline at end of file +3.9.49beta11 \ No newline at end of file diff --git a/utils/safePython.py b/utils/safePython.py index e37bac8..578f0d9 100644 --- a/utils/safePython.py +++ b/utils/safePython.py @@ -9,7 +9,7 @@ import tokenize from func_timeout import func_set_timeout from func_timeout.exceptions import FunctionTimedOut -from urllib.parse import urljoin,quote,unquote +from urllib.parse import urljoin, quote, unquote import requests import time import json @@ -20,6 +20,8 @@ import base64 from utils.log import logger time_out_sec = 8 # 安全执行python代码超时 + + class my_exception(Exception): def __init__(self, message): self.message = message @@ -28,10 +30,12 @@ class my_exception(Exception): message = f'函数执行超时: "{self.message}"' return message + @func_set_timeout(time_out_sec) def excute(*args): exec(*args) + def check_unsafe_attributes(string): """ 安全检测需要exec执行的python代码 @@ -48,6 +52,7 @@ def check_unsafe_attributes(string): elif toktype == tokenize.OP: pre_op = tokval + DEFAULT_PYTHON_CODE = """# 可用内置环境变量: # - log: log(message): 打印日志功能 # - 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) """ + +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: - def __init__(self,name, code): + def __init__(self, name, code): self.name = name or '未定义' self.code = code - def action_task_exec(self,call=None,params=None): + def action_task_exec(self, call=None, params=None): """ 接口调用执行函数 :return: @@ -71,13 +109,13 @@ class safePython: params = [] builtins = __builtins__ 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] # 删除不安全的关键字 # 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 + '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(self.code) @@ -102,4 +140,4 @@ class safePython: # print(global_dict) # print(localdict) ret = localdict['result'] - return ret \ No newline at end of file + return ret