# -*- coding: utf-8 -*- """ 清理 E2E 崩掉时残留在 demo 租户里的测试账号。 背景:e2e-m0-user.py 在 [5] 自锁防线那一段曾因脚本自身 bug 抛异常退出, 没有走到 [14] 的清理,于是 demo 租户里留下了 `dup*` / `t*` / `imp*` 之类的测试账号。 它们会出现在账号管理页上,必须清掉。 """ import base64 import json import os import re import sys import urllib.error import urllib.request sys.stdout.reconfigure(encoding='utf-8') BASE = "http://localhost:8080" PUB = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "deploy", "rsa-public-key-dev.pem") # E2E 造账号时用的前缀(见 scripts/e2e-m0-user.py) TEST_PATTERNS = [ re.compile(r'^dup[0-9a-f]{6}$'), # 重名测试 re.compile(r'^t[0-9a-f]{6}$'), # 测试班主任 re.compile(r'^ht[0-9a-f]{6}$'), # 班主任回归护栏 re.compile(r'^imp[123][0-9a-f]{6}$'), # 导入进来的 re.compile(r'^esc2?[0-9a-f]{6}$'), # 提权测试(正常不该存在) re.compile(r'^mix[0-9a-f]{6}$'), # 类型不符测试(正常不该存在) re.compile(r'^bad[0-9a-f]{6}$'), # 手机号错(正常不该存在) ] def rsa(plain: str) -> str: from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding with open(PUB, "rb") as f: pub = serialization.load_pem_public_key(f.read()) return base64.b64encode(pub.encrypt(plain.encode(), padding.PKCS1v15())).decode() def call(method: str, path: str, token: str | None = None, body: dict | None = None): headers = {"Content-Type": "application/json; charset=utf-8"} if token: headers["Authorization"] = f"Bearer {token}" data = json.dumps(body).encode() if body is not None else None req = urllib.request.Request(BASE + path, data=data, headers=headers, method=method) try: with urllib.request.urlopen(req, timeout=25) as r: return json.loads(r.read().decode()) except urllib.error.HTTPError as e: try: return json.loads(e.read().decode()) except Exception: return {"code": e.code} # 登录 r = call("POST", "/api/v1/auth/login", body={"username": "admin", "password": rsa("Admin@123"), "tenantCode": "demo"}) if r.get("code") != 0: sys.exit(f"登录失败:{r}") token = r["data"]["token"] admin_uid = r["data"]["user"]["id"] print(f" 已登录(admin uid={admin_uid})") # 拉全量 r = call("GET", "/api/v1/users?pageSize=200", token) users = (r.get("data") or {}).get("list") or [] print(f" demo 租户共 {len(users)} 个账号") victims = [] for u in users: if u["id"] == admin_uid: continue uname = u.get("username") or "" if any(p.match(uname) for p in TEST_PATTERNS): victims.append(u) if not victims: print(" ✓ 没有残留的测试账号") sys.exit(0) print(f" 发现 {len(victims)} 个残留测试账号:") for v in victims: print(f" id={v['id']:<4} username={v.get('username'):<14} realName={v.get('realName')}") print() for v in victims: res = call("DELETE", f"/api/v1/users/{v['id']}", token) flag = "✓" if res.get("code") == 0 else "✗" print(f" {flag} 删除 {v.get('username')} code={res.get('code')}") # 复核 r = call("GET", "/api/v1/users?pageSize=200", token) left = (r.get("data") or {}).get("list") or [] print() print(f" 清理后剩 {len(left)} 个账号:") for u in left: print(f" id={u['id']:<4} username={u.get('username'):<14} realName={u.get('realName')} 角色={u.get('roleNames')}")