obfuscate_non_billing.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #!/usr/bin/env python3
  2. """
  3. 非计费模块代码混淆脚本
  4. 使用PyArmor对非计费相关的代码进行混淆,保护核心业务逻辑
  5. 保留计费模块的可读性,便于客户集成和维护
  6. """
  7. import os
  8. import shutil
  9. import subprocess
  10. from pathlib import Path
  11. from typing import List, Set
  12. # 计费相关的核心文件(不混淆)
  13. BILLING_FILES = {
  14. # Models
  15. "backend/app/models/billing.py",
  16. "backend/app/models/consumption.py",
  17. "backend/app/models/invoice.py",
  18. "backend/app/models/invoice_info.py",
  19. "backend/app/models/invoice_info_history.py",
  20. "backend/app/models/user.py",
  21. # Services
  22. "backend/app/services/billing_service.py",
  23. "backend/app/services/balance_service.py",
  24. "backend/app/services/recharge_service.py",
  25. "backend/app/services/billing_calculator.py",
  26. "backend/app/services/recharge_handler.py",
  27. # Routers
  28. "backend/app/routers/billing_router.py",
  29. "backend/app/routers/invoice_router.py",
  30. # Schemas
  31. "backend/app/schemas/billing_schema.py",
  32. "backend/app/schemas/invoice_schema.py",
  33. # Dependencies
  34. "backend/app/dependencies/balance_check.py",
  35. # Core
  36. "backend/app/core/config.py",
  37. "backend/app/core/async_database.py",
  38. "backend/app/core/async_logger.py",
  39. "backend/app/core/redis.py",
  40. "backend/app/database.py",
  41. # Middleware (部分需要保留)
  42. "backend/app/middleware/auth_log_middleware.py",
  43. "backend/app/middleware/error_handler.py",
  44. }
  45. # 需要混淆的非计费模块目录
  46. NON_BILLING_MODULES = [
  47. "backend/app/models/conversation.py",
  48. "backend/app/models/ai_picture.py",
  49. "backend/app/models/ai_video.py",
  50. "backend/app/models/audio.py",
  51. "backend/app/models/image_translation.py",
  52. "backend/app/models/translation.py",
  53. "backend/app/models/zhiwen.py",
  54. "backend/app/models/research.py",
  55. "backend/app/models/ocr.py",
  56. "backend/app/models/photo_answer.py",
  57. "backend/app/models/tingwu.py",
  58. "backend/app/models/toolbox.py",
  59. "backend/app/models/search.py",
  60. "backend/app/models/api_call_log.py",
  61. "backend/app/models/platform_api_key.py",
  62. "backend/app/models/parsed_pricing.py",
  63. "backend/app/models/model.py",
  64. "backend/app/models/config.py",
  65. "backend/app/models/log.py",
  66. "backend/app/models/admin.py",
  67. # Services
  68. "backend/app/services/llm_service.py",
  69. "backend/app/services/image_service.py",
  70. "backend/app/services/video_service.py",
  71. "backend/app/services/audio_billing.py",
  72. "backend/app/services/image_billing.py",
  73. "backend/app/services/video_billing.py",
  74. "backend/app/services/translation_billing.py",
  75. "backend/app/services/image_translation_billing.py",
  76. "backend/app/services/ocr_billing_calculator.py",
  77. "backend/app/services/translation_service.py",
  78. "backend/app/services/image_translation_service.py",
  79. "backend/app/services/multimodal_translation_service.py",
  80. "backend/app/services/zhiwen_service.py",
  81. "backend/app/services/zhiwen_client.py",
  82. "backend/app/services/research_service.py",
  83. "backend/app/services/qwen_deep_research_service.py",
  84. "backend/app/services/ocr_service.py",
  85. "backend/app/services/qwen_ocr.py",
  86. "backend/app/services/photo_answer_service.py",
  87. "backend/app/services/tingwu_service.py",
  88. "backend/app/services/tingwu_client.py",
  89. "backend/app/services/tingwu_realtime_client.py",
  90. "backend/app/services/tingwu_params_adapter.py",
  91. "backend/app/services/asr_service.py",
  92. "backend/app/services/tts_service.py",
  93. "backend/app/services/voice_clone_service.py",
  94. "backend/app/services/system_voice_service.py",
  95. "backend/app/services/conversation_service.py",
  96. "backend/app/services/message_service.py",
  97. "backend/app/services/model_service.py",
  98. "backend/app/services/local_model_service.py",
  99. "backend/app/services/openai_compat_service.py",
  100. "backend/app/services/dashscope_client.py",
  101. "backend/app/services/anytrans_client.py",
  102. "backend/app/services/edututor_client.py",
  103. "backend/app/services/admin_auth_service.py",
  104. "backend/app/services/admin_user_service.py",
  105. "backend/app/services/admin_model_service.py",
  106. "backend/app/services/admin_stats_service.py",
  107. "backend/app/services/admin_order_service.py",
  108. "backend/app/services/admin_bill_service.py",
  109. "backend/app/services/admin_consumption_service.py",
  110. "backend/app/services/admin_invoice_service.py",
  111. "backend/app/services/auth_service.py",
  112. "backend/app/services/user_service.py",
  113. "backend/app/services/config_service.py",
  114. "backend/app/services/log_service.py",
  115. "backend/app/services/operation_log_service.py",
  116. "backend/app/services/api_call_log_service.py",
  117. "backend/app/services/platform_api_key_service.py",
  118. "backend/app/services/parsed_pricing_service.py",
  119. "backend/app/services/consumption_sync_service.py",
  120. "backend/app/services/review_service.py",
  121. "backend/app/services/toolbox_service.py",
  122. "backend/app/services/oss_service.py",
  123. "backend/app/services/avatar_service.py",
  124. "backend/app/services/cache_service.py",
  125. "backend/app/services/rate_limiter.py",
  126. "backend/app/services/health_service.py",
  127. "backend/app/services/system_config_manager.py",
  128. "backend/app/services/crypto_utils.py",
  129. "backend/app/services/token_revocation_service.py",
  130. "backend/app/services/phrase_service.py",
  131. "backend/app/services/terminology_service.py",
  132. "backend/app/services/translation_memory_service.py",
  133. "backend/app/services/citation_formatter.py",
  134. "backend/app/services/search_options_validator.py",
  135. "backend/app/services/stream_search_state.py",
  136. "backend/app/services/vertical_domain_processor.py",
  137. ]
  138. def check_pyarmor_installed():
  139. """检查PyArmor是否已安装"""
  140. try:
  141. result = subprocess.run(
  142. ["pyarmor", "--version"],
  143. capture_output=True,
  144. text=True,
  145. check=True
  146. )
  147. print(f"✓ PyArmor已安装: {result.stdout.strip()}")
  148. return True
  149. except (subprocess.CalledProcessError, FileNotFoundError):
  150. print("✗ PyArmor未安装")
  151. print("\n请先安装PyArmor:")
  152. print(" pip install pyarmor")
  153. return False
  154. def create_output_directory():
  155. """创建输出目录"""
  156. output_dir = Path("backend_obfuscated")
  157. if output_dir.exists():
  158. print(f"清理旧的输出目录: {output_dir}")
  159. shutil.rmtree(output_dir)
  160. output_dir.mkdir(parents=True, exist_ok=True)
  161. print(f"✓ 创建输出目录: {output_dir}")
  162. return output_dir
  163. def copy_billing_files(output_dir: Path):
  164. """复制计费相关文件(不混淆)"""
  165. print("\n正在复制计费模块文件(保持可读)...")
  166. for file_path in BILLING_FILES:
  167. src = Path(file_path)
  168. if not src.exists():
  169. print(f" ⚠ 文件不存在,跳过: {file_path}")
  170. continue
  171. # 计算目标路径
  172. dst = output_dir / src
  173. dst.parent.mkdir(parents=True, exist_ok=True)
  174. # 复制文件
  175. shutil.copy2(src, dst)
  176. print(f" ✓ 复制: {file_path}")
  177. print(f"✓ 已复制 {len(BILLING_FILES)} 个计费模块文件")
  178. def obfuscate_non_billing_files(output_dir: Path):
  179. """混淆非计费模块文件"""
  180. print("\n正在混淆非计费模块...")
  181. obfuscated_count = 0
  182. failed_files = []
  183. for file_path in NON_BILLING_MODULES:
  184. src = Path(file_path)
  185. if not src.exists():
  186. print(f" ⚠ 文件不存在,跳过: {file_path}")
  187. continue
  188. # 计算目标路径
  189. dst = output_dir / src.parent
  190. dst.mkdir(parents=True, exist_ok=True)
  191. try:
  192. # 使用PyArmor混淆单个文件
  193. result = subprocess.run(
  194. [
  195. "pyarmor",
  196. "obfuscate",
  197. "--output", str(dst),
  198. "--exact", # 只混淆指定文件
  199. "--no-cross-protection", # 不启用交叉保护
  200. str(src)
  201. ],
  202. capture_output=True,
  203. text=True,
  204. check=True
  205. )
  206. print(f" ✓ 混淆: {file_path}")
  207. obfuscated_count += 1
  208. except subprocess.CalledProcessError as e:
  209. print(f" ✗ 混淆失败: {file_path}")
  210. print(f" 错误: {e.stderr}")
  211. failed_files.append(file_path)
  212. print(f"\n✓ 成功混淆 {obfuscated_count} 个文件")
  213. if failed_files:
  214. print(f"✗ 失败 {len(failed_files)} 个文件:")
  215. for f in failed_files:
  216. print(f" - {f}")
  217. return obfuscated_count, failed_files
  218. def copy_other_files(output_dir: Path):
  219. """复制其他必要文件(配置、依赖等)"""
  220. print("\n正在复制其他必要文件...")
  221. other_files = [
  222. "backend/requirements.txt",
  223. "backend/.env.example",
  224. "backend/README.md",
  225. "backend/app/__init__.py",
  226. "backend/app/main.py",
  227. ]
  228. for file_path in other_files:
  229. src = Path(file_path)
  230. if not src.exists():
  231. continue
  232. dst = output_dir / src
  233. dst.parent.mkdir(parents=True, exist_ok=True)
  234. shutil.copy2(src, dst)
  235. print(f" ✓ 复制: {file_path}")
  236. def copy_init_files(output_dir: Path):
  237. """复制所有__init__.py文件"""
  238. print("\n正在复制__init__.py文件...")
  239. backend_dir = Path("backend")
  240. for init_file in backend_dir.rglob("__init__.py"):
  241. relative_path = init_file.relative_to(backend_dir.parent)
  242. dst = output_dir / relative_path
  243. dst.parent.mkdir(parents=True, exist_ok=True)
  244. shutil.copy2(init_file, dst)
  245. print(f" ✓ 复制: {relative_path}")
  246. def create_readme(output_dir: Path):
  247. """创建README说明文件"""
  248. readme_content = """# 计费模块交付包
  249. ## 说明
  250. 本包包含完整的计费系统代码,其中:
  251. ### 可读模块(未混淆)
  252. - **计费核心模块**: `app/models/billing.py`, `app/models/consumption.py`, `app/models/invoice.py`
  253. - **计费服务**: `app/services/billing_service.py`, `app/services/balance_service.py`, `app/services/recharge_service.py`
  254. - **计费API**: `app/routers/billing_router.py`, `app/routers/invoice_router.py`
  255. - **用户模型**: `app/models/user.py`
  256. - **核心配置**: `app/core/`, `app/database.py`
  257. ### 混淆模块(已保护)
  258. - **业务模块**: AI对话、AI生图、AI视频、语音合成、语音识别等
  259. - **业务服务**: 各业务模块的服务层实现
  260. - **管理后台**: 管理员相关功能
  261. ## 部署说明
  262. 1. 安装依赖:
  263. ```bash
  264. pip install -r requirements.txt
  265. ```
  266. 2. 配置环境变量:
  267. ```bash
  268. cp .env.example .env
  269. # 编辑.env文件,配置数据库、支付宝等参数
  270. ```
  271. 3. 运行数据库迁移:
  272. ```bash
  273. alembic upgrade head
  274. ```
  275. 4. 启动服务:
  276. ```bash
  277. uvicorn app.main:app --host 0.0.0.0 --port 8000
  278. ```
  279. ## 计费模块文档
  280. 详细的计费模块文档请参考:`.kiro/specs/billing-system-documentation/design.md`
  281. ## 技术支持
  282. 如有问题,请联系技术支持团队。
  283. ---
  284. 生成时间: {datetime}
  285. 混淆工具: PyArmor
  286. """
  287. from datetime import datetime
  288. readme_path = output_dir / "README.md"
  289. readme_path.write_text(
  290. readme_content.format(datetime=datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
  291. encoding="utf-8"
  292. )
  293. print(f"\n✓ 创建README: {readme_path}")
  294. def main():
  295. """主函数"""
  296. print("=" * 60)
  297. print("非计费模块代码混淆工具")
  298. print("=" * 60)
  299. # 1. 检查PyArmor
  300. if not check_pyarmor_installed():
  301. return
  302. # 2. 创建输出目录
  303. output_dir = create_output_directory()
  304. # 3. 复制计费文件(不混淆)
  305. copy_billing_files(output_dir)
  306. # 4. 混淆非计费文件
  307. obfuscated_count, failed_files = obfuscate_non_billing_files(output_dir)
  308. # 5. 复制其他文件
  309. copy_other_files(output_dir)
  310. copy_init_files(output_dir)
  311. # 6. 创建README
  312. create_readme(output_dir)
  313. # 7. 总结
  314. print("\n" + "=" * 60)
  315. print("混淆完成!")
  316. print("=" * 60)
  317. print(f"输出目录: {output_dir.absolute()}")
  318. print(f"计费模块文件: {len(BILLING_FILES)} 个(未混淆)")
  319. print(f"非计费模块文件: {obfuscated_count} 个(已混淆)")
  320. if failed_files:
  321. print(f"\n⚠ 警告: {len(failed_files)} 个文件混淆失败")
  322. print("\n下一步:")
  323. print("1. 检查输出目录中的文件")
  324. print("2. 测试混淆后的代码是否正常运行")
  325. print("3. 将整个目录打包交付给客户")
  326. if __name__ == "__main__":
  327. main()