diff --git a/.gitignore b/.gitignore index 11ea802..237a098 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Byte-compiled / optimized / DLL files __pycache__/ -*.py[cod] +*.py[co] *$py.class # C extensions diff --git a/lib/cli/code_encode.py b/lib/cli/code_encode.py new file mode 100644 index 0000000..77e549d --- /dev/null +++ b/lib/cli/code_encode.py @@ -0,0 +1,46 @@ + +import argparse +import os +import sys + +sys.path.append(os.path.dirname(os.path.dirname(__file__))) + +from support import SupportFile, SupportSC, logger + + +class CodeEncode: + def start_folder(self, folderpath): + for name in os.listdir(folderpath): + filepath = os.path.join(folderpath, name) + if os.path.isfile(filepath) and name not in ['setup.py', '__init__.py'] and name.endswith('.py'): + self.encode_file(filepath) + + def encode_file(self, filepath): + if filepath.endswith(".py") == False: + logger.info("is not .py file") + return + text = SupportFile.read_file(filepath) + data = SupportSC.encode(text, 1) + SupportFile.write_file(filepath + 'f', data) + logger.info(f"Create {os.path.basename(filepath + 'f')}") + + + def process_args(self): + parser = argparse.ArgumentParser() + parser.add_argument('--mode', default='encode') + parser.add_argument('--source', required=True, help=u'absolute path. folder or file') + args = parser.parse_args() + if SupportSC.LIBRARY_LOADING == False: + logger.error("sc import fail") + return + if os.path.exists(args.source): + if os.path.isdir(args.source): + self.start_folder(args.source) + elif os.path.isfile(args.source): + self.encode_file(args.source) + + +if __name__== "__main__": + CodeEncode().process_args() + + # python C:\work\FlaskFarm\flaskfarm\lib\cli\code_encode.py --source=C:\work\FlaskFarm\data\LOADING\klive_plus\source_spotv.py diff --git a/lib/framework/init_main.py b/lib/framework/init_main.py index 417f830..15c1b34 100644 --- a/lib/framework/init_main.py +++ b/lib/framework/init_main.py @@ -204,7 +204,7 @@ class Framework: from .init_web import jinja_initialize jinja_initialize(self.app) - + from .init_plugin import PluginManager self.PluginManager = PluginManager PluginManager.plugin_update() diff --git a/lib/framework/init_plugin.py b/lib/framework/init_plugin.py index ef751c4..1fafe7f 100644 --- a/lib/framework/init_plugin.py +++ b/lib/framework/init_plugin.py @@ -21,19 +21,8 @@ class PluginManager: @classmethod def get_plugin_name_list(cls): - #if not app.config['config']['auth_status']: - # return - """ - plugin_path = os.path.join(frame.config['path_app'], 'plugins') - sys.path.insert(0, plugin_path) - from system import SystemModelSetting - plugins = os.listdir(plugin_path) - """ plugins = [] - - #2019-07-17 - try: plugin_path = os.path.join(F.config['path_data'], 'plugins') if os.path.exists(plugin_path) == True and os.path.isdir(plugin_path) == True: @@ -115,51 +104,18 @@ class PluginManager: F.logger.debug(plugins) for plugin_name in plugins: - - #logger.debug(len(system.LogicPlugin.current_loading_plugin_list)) - #if plugin_name.startswith('_'): - # continue - #if plugin_name == 'terminal' and platform.system() == 'Windows': - # continue - #if plugin_name in except_plugin_list: - # F.logger.debug('Except plugin : %s' % frame.plugin_menu) - # continue F.logger.debug(f'[+] PLUGIN LOADING Start.. [{plugin_name}]') entity = cls.all_package_list[plugin_name] entity['version'] = '3' try: mod = __import__('%s' % (plugin_name), fromlist=[]) mod_plugin_info = None - # 2021-12-31 - #import system - #if plugin_name not in system.LogicPlugin.current_loading_plugin_list: - # system.LogicPlugin.current_loading_plugin_list[plugin_name] = {'status':'loading'} - try: mod_plugin_info = getattr(mod, 'plugin_info') entity['module'] = mod - """ - if 'category' not in mod_plugin_info and 'category_name' in mod_plugin_info: - mod_plugin_info['category'] = mod_plugin_info['category_name'] - if 'policy_point' in mod_plugin_info: - if mod_plugin_info['policy_point'] > app.config['config']['point']: - system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'violation_policy_point' - continue - if 'policy_level' in mod_plugin_info: - if mod_plugin_info['policy_level'] > app.config['config']['level']: - system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'violation_policy_level' - continue - if 'category' in mod_plugin_info and mod_plugin_info['category'] == 'beta': - if SystemModelSetting.get_bool('use_beta') == False: - system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'violation_beta' - continue - """ except Exception as exception: - #logger.error('Exception:%s', exception) - #logger.error(traceback.format_exc()) - - #mod_plugin_info = getattr(mod, 'setup') F.logger.info(f'[!] PLUGIN_INFO not exist : [{plugin_name}] - is FF') + if mod_plugin_info == None: try: mod = __import__(f'{plugin_name}.setup', fromlist=['setup']) @@ -168,13 +124,10 @@ class PluginManager: F.logger.error(f'Exception:{str(e)}') F.logger.error(traceback.format_exc()) F.logger.warning(f'[!] NOT normal plugin : [{plugin_name}]') - #entity['version'] = 'not_plugin' - try: if entity['version'] != '4': mod_blue_print = getattr(mod, 'blueprint') - else: entity['setup_mod'] = mod entity['P'] = getattr(mod, 'P') @@ -196,24 +149,7 @@ class PluginManager: cls.all_package_list[plugin_name]['status'] = 'import fail' cls.all_package_list[plugin_name]['log'] = traceback.format_exc() - #from tool_base import d - #logger.error(d(system.LogicPlugin.current_loading_plugin_list)) - # 2021-07-01 모듈에 있는 DB 테이블 생성이 안되는 문제 - # 기존 구조 : db.create_all() => 모듈 plugin_load => celery task 등록 후 리턴 - # 변경 구조 : 모듈 plugin_load => db.create_all() => celery인 경우 리턴 - - # plugin_load 를 해야 하위 로직에 있는 DB가 로딩된다. - # plugin_load 에 db는 사용하는 코드가 있으면 안된다. (테이블도 없을 때 에러발생) - try: - #logger.warning('module plugin_load in celery ') - cls.plugin_list['mod']['module'].plugin_load() - except Exception as exception: - F.logger.debug(f'mod plugin_load error!!') - #logger.error('Exception:%s', exception) - #logger.error(traceback.format_exc()) - - # import가 끝나면 DB를 만든다. - # 플러그인 로드시 DB 초기화를 할 수 있다. + if not F.config['run_celery']: try: @@ -225,17 +161,6 @@ class PluginManager: F.logger.debug('db.create_all error') if not F.config['run_flask']: - # 2021-06-03 - # 모듈의 로직에 있는 celery 함수는 등록해주어야한다. - #try: - # logger.warning('module plugin_load in celery ') - # plugin_instance_list['mod'].plugin_load() - #except Exception as exception: - # logger.error('module plugin_load error') - # logger.error('Exception:%s', exception) - # logger.error(traceback.format_exc()) - # 2021-07-01 - # db때문에 위에서 로딩함. return for key, entity in cls.plugin_list.items(): @@ -259,6 +184,13 @@ class PluginManager: cls.all_package_list[key]['loading'] = False cls.all_package_list[key]['status'] = 'plugin_load error' cls.all_package_list[key]['log'] = traceback.format_exc() + + if key in cls.plugin_menus: + del cls.plugin_menus[key] + from framework.init_menu import MenuManager + MenuManager.init_menu() + + # mod는 위에서 로딩 if key != 'mod': t = threading.Thread(target=func, args=(mod_plugin_load, key)) diff --git a/lib/plugin/logic.py b/lib/plugin/logic.py index ae3c114..92f1019 100644 --- a/lib/plugin/logic.py +++ b/lib/plugin/logic.py @@ -16,34 +16,30 @@ class Logic(object): self.P = P def plugin_load(self): - try: - self.P.logger.debug('%s plugin_load', self.P.package_name) - self.db_init() + self.P.logger.debug('%s plugin_load', self.P.package_name) + self.db_init() + for module in self.P.module_list: + module.migration() + if module.page_list is not None: + for page_instance in module.page_list: + page_instance.migration() + + for module in self.P.module_list: + module.plugin_load() + if module.page_list is not None: + for page_instance in module.page_list: + page_instance.plugin_load() + if self.P.ModelSetting is not None: for module in self.P.module_list: - module.migration() + key = f'{module.name}_auto_start' + if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key): + self.scheduler_start(module.name) if module.page_list is not None: for page_instance in module.page_list: - page_instance.migration() + key = f'{module.name}_{page_instance.name}_auto_start' + if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key): + self.scheduler_start_sub(module.name, page_instance.name) - for module in self.P.module_list: - module.plugin_load() - if module.page_list is not None: - for page_instance in module.page_list: - page_instance.plugin_load() - if self.P.ModelSetting is not None: - for module in self.P.module_list: - key = f'{module.name}_auto_start' - if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key): - self.scheduler_start(module.name) - if module.page_list is not None: - for page_instance in module.page_list: - key = f'{module.name}_{page_instance.name}_auto_start' - if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key): - self.scheduler_start_sub(module.name, page_instance.name) - - except Exception as e: - self.P.logger.error(f'Exception:{str(e)}') - self.P.logger.error(traceback.format_exc()) def db_init(self): try: diff --git a/lib/plugin/model_setting.py b/lib/plugin/model_setting.py index d21e8af..fdbc35d 100644 --- a/lib/plugin/model_setting.py +++ b/lib/plugin/model_setting.py @@ -1,4 +1,5 @@ import traceback +from datetime import datetime from framework import F @@ -32,8 +33,8 @@ def get_model_setting(package_name, logger, table_name=None): if ret is not None: return ret.value.strip() return None - except Exception as exception: - logger.error('Exception:%s %s', exception, key) + except Exception as e: + logger.error(f"Exception:{str(e)} [{key}]") logger.error(traceback.format_exc()) @staticmethod @@ -45,16 +46,24 @@ def get_model_setting(package_name, logger, table_name=None): def get_int(key): try: return int(ModelSetting.get(key)) - except Exception as exception: - logger.error('Exception:%s %s', exception, key) + except Exception as e: + logger.error(f"Exception:{str(e)} [{key}]") logger.error(traceback.format_exc()) @staticmethod def get_bool(key): try: return (ModelSetting.get(key) == 'True') - except Exception as exception: - logger.error('Exception:%s %s', exception, key) + except Exception as e: + logger.error(f"Exception:{str(e)} [{key}]") + logger.error(traceback.format_exc()) + + @staticmethod + def get_datetime(key): + try: + return datetime.strptime(ModelSetting.get(key), '%Y-%m-%d %H:%M:%S.%f') + except Exception as e: + logger.error(f"Exception:{str(e)} [{key}]") logger.error(traceback.format_exc()) @staticmethod @@ -68,8 +77,8 @@ def get_model_setting(package_name, logger, table_name=None): else: F.db.session.add(ModelSetting(key, value.strip())) F.db.session.commit() - except Exception as exception: - logger.error('Exception:%s %s', exception, key) + except Exception as e: + logger.error(f"Exception:{str(e)} [{key}]") logger.error(traceback.format_exc()) @staticmethod @@ -78,8 +87,8 @@ def get_model_setting(package_name, logger, table_name=None): ret = ModelSetting.db_list_to_dict(F.db.session.query(ModelSetting).all()) ret['package_name'] = package_name return ret - except Exception as exception: - logger.error('Exception:%s', exception) + except Exception as e: + logger.error(f"Exception:{str(e)}") logger.error(traceback.format_exc()) @@ -99,8 +108,8 @@ def get_model_setting(package_name, logger, table_name=None): entity.value = value F.db.session.commit() return True, change_list - except Exception as exception: - logger.error('Exception:%s', exception) + except Exception as e: + logger.error(f"Exception:{str(e)}") logger.error(traceback.format_exc()) logger.debug('Error Key:%s Value:%s', key, value) return False, [] @@ -115,8 +124,8 @@ def get_model_setting(package_name, logger, table_name=None): values = [x.split(comment)[0].strip() for x in value.split(delimeter)] values = ModelSetting.get_list_except_empty(values) return values - except Exception as exception: - logger.error('Exception:%s', exception) + except Exception as e: + logger.error(f"Exception:{str(e)}") logger.error(traceback.format_exc()) logger.error('Error Key:%s Value:%s', key, value) diff --git a/lib/support/__init__.py b/lib/support/__init__.py index 1746d13..a7ce849 100644 --- a/lib/support/__init__.py +++ b/lib/support/__init__.py @@ -15,8 +15,9 @@ logger = get_logger() from .base.aes import SupportAES from .base.discord import SupportDiscord from .base.file import SupportFile +from .base.sc import SupportSC from .base.string import SupportString -from .base.subprocess import SupportSubprocess +from .base.sub_process import SupportSubprocess from .base.telegram import SupportTelegram from .base.util import (AlchemyEncoder, SingletonClass, SupportUtil, default_headers, pt) diff --git a/lib/support/base/aes.py b/lib/support/base/aes.py index e590e2b..37c5ec3 100644 --- a/lib/support/base/aes.py +++ b/lib/support/base/aes.py @@ -1,10 +1,16 @@ -import os, base64, traceback -from Crypto.Cipher import AES +import base64 +import os +import traceback + from Crypto import Random +from Crypto.Cipher import AES + from . import logger + BS = 16 -pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) -unpad = lambda s : s[0:-s[-1]] +pad = lambda s: s + (BS - len(s.encode('utf-8')) % BS) * chr(BS - len(s.encode('utf-8')) % BS) +#unpad = lambda s : s[0:-s[-1]] +unpad = lambda s : s[:-ord(s[len(s)-1:])] key = b'140b41b22a29beb4061bda66b6747e14' class SupportAES(object): @@ -39,5 +45,56 @@ class SupportAES(object): iv = enc[:16] if len(iv) != 16: iv = os.urandom(16) + if mykey is not None and type(mykey) == type(''): + mykey = mykey.encode() cipher = AES.new(key if mykey is None else mykey, AES.MODE_CBC, iv ) return unpad(cipher.decrypt( enc[16:] )).decode() + + @classmethod + def md5(cls, text): + import hashlib + enc = hashlib.md5() + enc.update(text.encode()) + return enc.hexdigest() + + + + + @classmethod + def encrypt_(cls, raw, mykey=None, iv=None): + try: + Random.atfork() + except Exception as exception: + logger.error('Exception:%s', exception) + logger.error(traceback.format_exc()) + raw = pad(raw) + if type(raw) == type(''): + raw = raw.encode() + if mykey is not None and type(mykey) == type(''): + mykey = mykey.encode() + if iv == None: + iv = Random.new().read( AES.block_size ) + elif iv is not None and type(iv) == type(''): + iv = iv.encode() + cipher = AES.new(key if mykey is None else mykey, AES.MODE_CBC, iv ) + try: + tmp = cipher.encrypt( raw ) + except Exception as exception: + logger.error('Exception:%s', exception) + logger.error(traceback.format_exc()) + tmp = cipher.encrypt( raw.encode() ) + ret = base64.b64encode( tmp ) + ret = ret.decode() + return ret + + @classmethod + def decrypt_(cls, enc, mykey=None, iv=None): + enc = base64.b64decode(enc) + if iv == None: + iv = os.urandom(16) + elif iv is not None and type(iv) == type(''): + iv = iv.encode() + if mykey is not None and type(mykey) == type(''): + mykey = mykey.encode() + cipher = AES.new(key if mykey is None else mykey, AES.MODE_CBC, iv ) + return unpad(cipher.decrypt( enc )).decode() diff --git a/lib/support/base/file.py b/lib/support/base/file.py index 326392a..dbea798 100644 --- a/lib/support/base/file.py +++ b/lib/support/base/file.py @@ -94,23 +94,6 @@ class SupportFile(object): - @classmethod - def write(cls, data, filepath, mode='w'): - try: - import codecs - ofp = codecs.open(filepath, mode, encoding='utf8') - if isinstance(data, bytes) and mode == 'w': - data = data.decode('utf-8') - ofp.write(data) - ofp.close() - return True - except Exception as exception: - logger.debug('Exception:%s', exception) - logger.debug(traceback.format_exc()) - return False - - - @classmethod diff --git a/lib/support/base/sc.py b/lib/support/base/sc.py new file mode 100644 index 0000000..f67bede --- /dev/null +++ b/lib/support/base/sc.py @@ -0,0 +1,79 @@ +import argparse +import os +import platform +import re +import sys +import traceback + +from . import logger + + +class SupportSC: + LIBRARY_LOADING = False + try: + if platform.system() == 'Linux': + if (platform.platform().find('86') == -1 and platform.platform().find('64') == -1) or platform.platform().find('arch') != -1 or platform.platform().find('arm') != -1: + sys.path.insert(2, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib', 'sc', 'LinuxArm')) + else: + sys.path.insert(2, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib', 'sc', 'Linux')) + if platform.system() == 'Windows': + sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'sc', 'Windows')) + import sc + LIBRARY_LOADING = True + except: + pass + + + @classmethod + def encode(cls, text, mode=0): + try: + import sc + return sc.encode(text, mode) + except Exception as e: + logger.error(f'Exception:{str(e)}') + logger.error(traceback.format_exc()) + return None + + + @classmethod + def decode(cls, text): + try: + import sc + return sc.decode(text) + except: + return None + + @classmethod + def load_module(cls, module_name, module_code): + try: + import sc + mod = sc.load_module(module_name, module_code) + sys.modules[mod] = mod + logger.warning(f"C-LOADING : {module_name}") + return mod + except Exception as e: + logger.error(f'Exception:{str(e)}') + logger.error(traceback.format_exc()) + + @classmethod + def load_module_P(cls, plugin_ins, filename): + return cls.load_module_f(plugin_ins.setting['filepath'], filename) + + @classmethod + def load_module_f(cls, package_filepath, filename): + dirname = os.path.dirname(package_filepath) + filepath = os.path.join(dirname, filename + '.pyf') + if os.path.exists(filepath) and os.path.exists(filepath): + from support import SupportFile + code = SupportFile.read_file(filepath) + return cls.load_module(f"{os.path.basename(dirname)}.{filename}", code) + + @classmethod + def td(self, mediacode, ts, url): + try: + import sc + ret = sc.td1(mediacode, str(ts), url).strip() + ret = re.sub('[^ -~]+', '', ret).strip() + return ret + except: + return None diff --git a/lib/support/base/subprocess.py b/lib/support/base/sub_process.py similarity index 100% rename from lib/support/base/subprocess.py rename to lib/support/base/sub_process.py diff --git a/lib/support/sc/Windows/sc.cp310-win_amd64.pyd b/lib/support/sc/Windows/sc.cp310-win_amd64.pyd new file mode 100644 index 0000000..98cabed Binary files /dev/null and b/lib/support/sc/Windows/sc.cp310-win_amd64.pyd differ diff --git a/lib/system/mod_setting.py b/lib/system/mod_setting.py index 6fcd8a3..e2b0651 100644 --- a/lib/system/mod_setting.py +++ b/lib/system/mod_setting.py @@ -21,6 +21,7 @@ class ModuleSetting(PluginModuleBase): 'web_title': 'Home', 'use_apikey': 'False', 'apikey': ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)), + 'app_id': ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)), f'restart_interval': f'{random.randint(0,59)} {random.randint(1,23)} * * *', 'restart_notify': 'False', 'theme' : 'Cerulean',