You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
12 KiB

1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
1 year ago
4 months ago
  1. #coding: utf-8
  2. # +-------------------------------------------------------------------
  3. # | 宝塔Linux面板
  4. # +-------------------------------------------------------------------
  5. # | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
  6. # +-------------------------------------------------------------------
  7. # | Author: hwliang <hwl@bt.cn>
  8. # +-------------------------------------------------------------------
  9. #+--------------------------------------------------------------------
  10. #| 插件和模块加载器
  11. #+--------------------------------------------------------------------
  12. import public,os,sys,json
  13. def plugin_run(plugin_name,def_name,args):
  14. '''
  15. @name
  16. @param plugin_name<string>
  17. @param def_name<string>
  18. @param args<dict_obj>
  19. @return mixed
  20. '''
  21. if not plugin_name or not def_name: return public.returnMsg(False,'插件名称和插件方法名称不能为空!')
  22. # 获取插件目录
  23. plugin_path = public.get_plugin_path(plugin_name)
  24. is_php = os.path.exists(os.path.join(plugin_path,'index.php'))
  25. # 检查插件目录是否合法
  26. if is_php:
  27. plugin_file = os.path.join(plugin_path,'index.php')
  28. else:
  29. plugin_file = os.path.join(plugin_path, plugin_name + '_main.py')
  30. if not public.path_safe_check(plugin_file): return public.returnMsg(False,'插件路径不合法')
  31. # 检查插件入口文件是否存在
  32. if not os.path.exists(plugin_file): return public.returnMsg(False,'指定插件入口文件不存在')
  33. # 添加插件目录到系统路径
  34. public.sys_path_append(plugin_path)
  35. try:
  36. if not is_php:
  37. # 引用插件入口文件
  38. _name = "{}_main".format(plugin_name)
  39. plugin_main = __import__(_name)
  40. # 检查类名是否符合规范
  41. if not hasattr(plugin_main,_name):
  42. return public.returnMsg(False,'指定插件入口文件不符合规范')
  43. try:
  44. if sys.version_info[0] == 2:
  45. reload(plugin_main)
  46. else:
  47. from imp import reload
  48. reload(plugin_main)
  49. except:
  50. pass
  51. # 实例化插件类
  52. plugin_obj = getattr(plugin_main,_name)()
  53. # 检查方法是否存在
  54. if not hasattr(plugin_obj,def_name):
  55. return public.returnMsg(False,'在[%s]插件中找不到[%s]方法' % (plugin_name,def_name))
  56. if 'plugin_get_object' in args and args.plugin_get_object == 1:
  57. return getattr(plugin_obj, def_name)
  58. # 执行方法
  59. return getattr(plugin_obj,def_name)(args)
  60. else:
  61. if 'plugin_get_object' in args and args.plugin_get_object == 1:
  62. return None
  63. import panelPHP
  64. args.s = def_name
  65. args.name = plugin_name
  66. return panelPHP.panelPHP(plugin_name).exec_php_script(args)
  67. except SyntaxError as ex:
  68. return public.returnMsg(False,'指定插件不兼容当前操作系统')
  69. except Exception as ex:
  70. public.print_error()
  71. return public.returnMsg(False,'指定插件不存在')
  72. def get_module_list():
  73. '''
  74. @name
  75. @return list
  76. '''
  77. module_list = []
  78. class_path = public.get_class_path()
  79. for name in os.listdir(class_path):
  80. path = os.path.join(class_path,name)
  81. # 过滤无效文件
  82. if not name or name.endswith('.py') or name[0] == '.' or not name.endswith('Model') or os.path.isfile(path):continue
  83. module_list.append(name)
  84. return module_list
  85. def module_run(module_name,def_name,args):
  86. '''
  87. @name
  88. @param module_name<string>
  89. @param def_name<string>
  90. @param args<dict_obj>
  91. @return mixed
  92. '''
  93. if not module_name or not def_name: return public.returnMsg(False,'模块名称和模块方法名称不能为空!')
  94. model_index = args.get('model_index',None)
  95. class_path = public.get_class_path()
  96. panel_path = public.get_panel_path()
  97. module_file = None
  98. if model_index:
  99. # 新模块目录
  100. if model_index in ['mod']:
  101. _name = "{}Mod".format(module_name)
  102. module_file = os.path.join(panel_path,'mod','project',module_name + 'Mod.py')
  103. elif model_index:
  104. # 旧模块目录
  105. _name = "{}Model".format(module_name)
  106. module_file = os.path.join(class_path,model_index+"Model",module_name + 'Model.py')
  107. else:
  108. _name = "{}Model".format(module_name)
  109. module_file = os.path.join(class_path,"projectModel",module_name + 'Model.py')
  110. else:
  111. # 如果没指定模块名称,则遍历所有模块目录
  112. module_list = get_module_list()
  113. for name in module_list:
  114. module_file = os.path.join(class_path,name,module_name + 'Model.py')
  115. if os.path.exists(module_file):
  116. _name = "{}Model".format(module_name)
  117. break
  118. # 判断模块入口文件是否存在
  119. if not os.path.exists(module_file):
  120. return public.returnMsg(False,'模块[%s]不存在' % module_name)
  121. # 判断模块路径是否合法
  122. if not public.path_safe_check(module_file):
  123. return public.returnMsg(False,'模块路径不合法')
  124. public.sys_path_append(os.path.dirname(module_file))
  125. try:
  126. # 引用模块入口文件
  127. module_main = __import__(_name)
  128. # 检查模块是否符合规范
  129. if not hasattr(module_main,'main'):
  130. return public.returnMsg(False,'指定模块入口文件不符合规范')
  131. # 实例化模块类
  132. module_obj = getattr(module_main,'main')()
  133. # 检查方法是否存在
  134. if not hasattr(module_obj,def_name):
  135. return public.returnMsg(False,'在[%s]模块中找不到[%s]方法' % (module_name,def_name))
  136. if 'module_get_object' in args and args.module_get_object == 1:
  137. return getattr(module_obj,def_name)
  138. # 执行方法
  139. return getattr(module_obj,def_name)(args)
  140. except SyntaxError as ex:
  141. return public.returnMsg(False,'指定模块不兼容当前操作系统')
  142. except Exception as ex:
  143. public.print_error()
  144. return public.returnMsg(False,'指定模块不存在')
  145. def get_plugin_list(upgrade_force = False):
  146. '''
  147. @name
  148. @param upgrade_force<bool>
  149. @return dict
  150. '''
  151. api_root_url = 'https://api.bt.cn'
  152. api_url = api_root_url+ '/panel/get_plugin_list'
  153. panel_path = public.get_panel_path()
  154. data_path = os.path.join(panel_path,'data')
  155. if not os.path.exists(data_path):
  156. os.makedirs(data_path,384)
  157. plugin_list = {}
  158. plugin_list_file = os.path.join(data_path,'plugin_list.json')
  159. if os.path.exists(plugin_list_file) and not upgrade_force:
  160. plugin_list_body = public.readFile(plugin_list_file)
  161. try:
  162. plugin_list = json.loads(plugin_list_body)
  163. except:
  164. plugin_list = {}
  165. if not os.path.exists(plugin_list_file) or upgrade_force or not plugin_list:
  166. try:
  167. res = public.HttpGet(api_url)
  168. except Exception as ex:
  169. raise public.error_conn_cloud(str(ex))
  170. if not res: raise Exception(False,'云端插件列表获取失败')
  171. plugin_list = json.loads(res)
  172. if type(plugin_list)!=dict or 'list' not in plugin_list:
  173. if type(plugin_list)==str:
  174. raise Exception(plugin_list)
  175. else:
  176. raise Exception('云端插件列表获取失败')
  177. public.writeFile(plugin_list_file,json.dumps(plugin_list))
  178. return plugin_list
  179. def start_total():
  180. '''
  181. @name
  182. @return dict
  183. '''
  184. pass
  185. def get_soft_list(args):
  186. '''
  187. @name
  188. @param args<dict_obj>
  189. @return dict
  190. '''
  191. pass
  192. def db_encrypt(data):
  193. '''
  194. @name
  195. @param args<dict_obj>
  196. @return dict
  197. '''
  198. try:
  199. key = __get_db_sgin()
  200. iv = __get_db_iv()
  201. str_arr = data.split('\n')
  202. res_str = ''
  203. for data in str_arr:
  204. if not data: continue
  205. res_str += __aes_encrypt(data, key, iv)
  206. except:
  207. res_str = data
  208. result = {
  209. 'status' : True,
  210. 'msg' : res_str
  211. }
  212. return result
  213. def db_decrypt(data):
  214. '''
  215. @name
  216. @param args<dict_obj>
  217. @return dict
  218. '''
  219. try:
  220. key = __get_db_sgin()
  221. iv = __get_db_iv()
  222. str_arr = data.split('\n')
  223. res_str = ''
  224. for data in str_arr:
  225. if not data: continue
  226. res_str += __aes_decrypt(data, key, iv)
  227. except:
  228. res_str = data
  229. result = {
  230. 'status' : True,
  231. 'msg' : res_str
  232. }
  233. return result
  234. def __get_db_sgin():
  235. keystr = '3gP7+k_7lSNg3$+Fj!PKW+6$KYgHtw#R'
  236. key = ''
  237. for i in range(31):
  238. if i & 1 == 0:
  239. key += keystr[i]
  240. return key
  241. def __get_db_iv():
  242. div_file = "{}/data/div.pl".format(public.get_panel_path())
  243. if not os.path.exists(div_file):
  244. str = public.GetRandomString(16)
  245. str = __aes_encrypt_module(str)
  246. div = public.get_div(str)
  247. public.WriteFile(div_file, div)
  248. if os.path.exists(div_file):
  249. div = public.ReadFile(div_file)
  250. div = __aes_decrypt_module(div)
  251. else:
  252. keystr = '4jHCpBOFzL4*piTn^-4IHBhj-OL!fGlB'
  253. div = ''
  254. for i in range(31):
  255. if i & 1 == 0:
  256. div += keystr[i]
  257. return div
  258. def __aes_encrypt_module(data):
  259. key = 'Z2B87NEAS2BkxTrh'
  260. iv = 'WwadH66EGWpeeTT6'
  261. return __aes_encrypt(data, key, iv)
  262. def __aes_decrypt_module(data):
  263. key = 'Z2B87NEAS2BkxTrh'
  264. iv = 'WwadH66EGWpeeTT6'
  265. return __aes_decrypt(data, key, iv)
  266. def __aes_decrypt(data, key, iv):
  267. from Crypto.Cipher import AES
  268. import base64
  269. encodebytes = base64.decodebytes(data.encode('utf-8'))
  270. aes = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
  271. de_text = aes.decrypt(encodebytes)
  272. unpad = lambda s: s[0:-s[-1]]
  273. de_text = unpad(de_text)
  274. return de_text.decode('utf-8')
  275. def __aes_encrypt(data, key, iv):
  276. from Crypto.Cipher import AES
  277. import base64
  278. data = (lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16).encode('utf-8'))(data.encode('utf-8'))
  279. aes = AES.new(key.encode('utf8'), AES.MODE_CBC, iv.encode('utf8'))
  280. encryptedbytes = aes.encrypt(data)
  281. en_text = base64.b64encode(encryptedbytes)
  282. return en_text.decode('utf-8')
  283. def plugin_end():
  284. '''
  285. @name
  286. @return dict
  287. '''
  288. pass
  289. def daemon_task():
  290. '''
  291. @name
  292. @return dict
  293. '''
  294. pass
  295. def daemon_panel():
  296. '''
  297. @name
  298. @return dict
  299. '''
  300. pass
  301. def flush_auth_key():
  302. '''
  303. @name
  304. @return dict
  305. '''
  306. pass
  307. def get_auth_state():
  308. '''
  309. @name
  310. @return 0. 1. 2. -1.
  311. '''
  312. try:
  313. softList = get_plugin_list()
  314. if softList['ltd'] > -1:
  315. return 2
  316. elif softList['pro'] > -1:
  317. return 1
  318. else:
  319. return 0
  320. except:
  321. return -1