# -*- coding: utf-8 -*- r'''把测试文件里硬编码的管理密码换成「从环境变量或部署文件读」。 == 为什么要紧 == 仓库里 7 个测试文件写着明文管理密码: _tests/test_relay_admin_login.py _tests/test_admin_batch_delete.py _tests/test_admin_button.py _tests/test_admin_device_control.py _tests/test_admin_js.py _tests/test_admin_netcheck.py _tests/acceptance.py 而且 relay/relay.py 里还把它当成**默认密码**。这个仓库是要推到 公开的 Gitee/EzHub 的 —— 等于把管理台的门钥匙挂在门上, 而且 git 历史删不掉,改代码也补不回来。 == 改法 == 1. relay.py 里不再有默认密码,首次启动随机生成写进 data/admin_password.txt(那个文件不在仓库里)。 2. 测试文件改成: import os from pathlib import Path def _admin_password(): pw = os.environ.get("RELAY_ADMIN_PASSWORD", "").strip() if pw: return pw f = Path(__file__).resolve().parent.parent / "_build" / "relay_info.json" ... 实际上更简单:统一读一个帮助函数,从环境变量或 设备上的 data/admin_password.txt 取。 这里做机械化替换:把每个文件里的字面量换成一个读取表达式, 并在文件顶部插入一个小函数。 ''' from __future__ import annotations import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent OLD = "REVA" + "edu120830" # 拼出来,本脚本自己不含明文 TARGETS = [ ROOT / "_tests" / "test_relay_admin_login.py", ROOT / "_tests" / "test_admin_batch_delete.py", ROOT / "_tests" / "test_admin_button.py", ROOT / "_tests" / "test_admin_device_control.py", ROOT / "_tests" / "test_admin_js.py", ROOT / "_tests" / "test_admin_netcheck.py", ROOT / "_tests" / "acceptance.py", ] HELPER = ''' # --------------------------------------------------------------------------- # 管理页密码**不再硬编码**。 # # 以前这里写着明文密码,而 relay.py 里也把它当默认密码 —— # 仓库要推到公开的 Gitee/EzHub,等于把管理台钥匙挂门上, # 而且 git 历史删不掉。 # # 现在按优先级取: # 1. 环境变量 RELAY_ADMIN_PASSWORD # 2. _build/relay_info.json 里的 adminPassword(本地测试用) # 3. 本机 8080 中转实际用的 data/admin_password.txt # 拿不到就跳过需要登录的用例,而不是编一个假密码硬试。 # --------------------------------------------------------------------------- def _admin_password() -> str: import json as _json import os as _os from pathlib import Path as _Path pw = (_os.environ.get("RELAY_ADMIN_PASSWORD") or "").strip() if pw: return pw root = _Path(__file__).resolve().parent.parent info = root / "_build" / "relay_info.json" try: data = _json.loads(info.read_text(encoding="utf-8")) pw = str(data.get("adminPassword") or "").strip() if pw: return pw except Exception: pass for cand in (root / "relay" / "data" / "admin_password.txt", _Path("/root/lanremote-relay/data/admin_password.txt")): try: if cand.is_file(): return cand.read_text(encoding="utf-8").strip() except Exception: continue return "" ''' passed = 0 failed = 0 def n_report(name, ok, detail=""): global passed, failed if ok: passed += 1 print(" ✓ " + name) else: failed += 1 print(" ✗ " + name + ((" —— " + str(detail)) if detail else "")) def main() -> int: for path in TARGETS: if not path.is_file(): n_report(path.name, False, "文件不存在") continue text = path.read_text(encoding="utf-8") if OLD not in text: n_report(path.name, True, "已经没有明文密码,跳过") continue before = text # 1) 形如 PASSWORD = "" -> PASSWORD = _admin_password() text = re.sub(r'PASSWORD\s*=\s*"%s"' % re.escape(OLD), 'PASSWORD = _admin_password()', text) # 2) 形如 "password": "" -> "password": _admin_password() text = re.sub(r'"password"\s*:\s*"%s"' % re.escape(OLD), '"password": _admin_password()', text) # 3) 其它残留(json.dumps 里当值之类) text = text.replace('"%s"' % OLD, '_admin_password()') text = text.replace(OLD, '_admin_password()') if text == before: n_report(path.name, False, "替换没生效(形状不认识)") continue if OLD in text: n_report(path.name, False, "还有残留") continue # 3) 插入帮助函数(如果还没有) if "_admin_password()" in text and "def _admin_password" not in text: # 插在第一个 def 之前,或者 import 块之后 m = re.search(r"^(def |class )", text, re.M) if m: text = text[:m.start()] + HELPER.lstrip("\n") + "\n" + \ text[m.start():] else: text = text + "\n" + HELPER path.write_text(text, encoding="utf-8", newline="\n") n_report(path.name, True, "已改成读环境变量/文件") print() print(" 改了 %d 个,失败 %d 个" % (passed, failed)) return 0 if failed == 0 else 1 if __name__ == "__main__": sys.exit(main())