#!/usr/bin/env python3 """WeChat Viewer 注册/权限分层 ad-hoc 验证(幂等,可重复运行)。 覆盖:注册 → user 登录 → 日报可见(/reports /digest /api/reports GET)→ 敏感页 403(/resumes /boss-jobs /chat/* /api/articles 带 CF header)→ 隧道流量 API 302/403 → 本地 cron 豁免 200 → admin 全权限。 验证脚本结尾自动清理测试账号 verifyuser。 用法: python3 verify-auth-permissions.py # 在 wechat-viewer 目录下直接跑;或任意目录跑(脚本自动 chdir) """ import os import sqlite3 import sys VIEWER = "/data/data/com.termux/files/home/wechat-viewer" sys.path.insert(0, VIEWER) os.chdir(VIEWER) results = [] def check(name, cond, detail=""): results.append((name, bool(cond), detail)) # 清理上次残留的 verifyuser(幂等) _conn = sqlite3.connect(os.path.join(VIEWER, "circle.db")) _conn.execute("DELETE FROM users WHERE username='verifyuser'") _conn.commit() _conn.close() import app as viewer_app client = viewer_app.app.test_client() # 注册 check("register 页面 200", client.get("/register").status_code == 200) r = client.post("/register", data={"username": "verifyuser", "password": "verify123", "password2": "verify123"}) check("register 提交 302", r.status_code == 302) # 未登录:公开路由 /digest/ 免登录(2026-08-13 起公网分享),其余仍受保护 check("未登录 /digest 200", client.get("/digest/2026-08-07").status_code == 200) check("未登录(带CF) /digest 200", client.get("/digest/2026-08-07", headers={"CF-Connecting-IP": "1.2.3.4"}).status_code == 200) check("未登录 /reports 302", client.get("/reports").status_code == 302) check("未登录(带CF) /api/reports 302", client.get("/api/reports", headers={"CF-Connecting-IP": "1.2.3.4"}).status_code == 302) # user 登录 check("user login 302", client.post("/login", data={"username": "verifyuser", "password": "verify123"}).status_code == 302) # user 日报可见 check("user /reports 200", client.get("/reports").status_code == 200) check("user /digest 200", client.get("/digest/2026-08-07").status_code == 200) check("user /api/reports 200", client.get("/api/reports").status_code == 200) # user 敏感页 403(真实公网流量必带 CF header;不带 header 的 127.0.0.1 = 本地 cron 豁免场景) for p in ["/resumes", "/boss-jobs", "/chat/x"]: check(f"user {p} 403", client.get(p).status_code == 403) check("user /api/articles(带CF) 403", client.get("/api/articles", headers={"CF-Connecting-IP": "1.2.3.4"}).status_code == 403) # 隧道流量(remote_addr=127.0.0.1 + CF header):未登录 302,user 403 client.get("/logout") r = client.get("/api/articles", environ_base={"REMOTE_ADDR": "127.0.0.1"}, headers={"CF-Connecting-IP": "1.2.3.4"}) check("隧道未登录 /api/articles 302", r.status_code == 302) client.post("/login", data={"username": "verifyuser", "password": "verify123"}) r = client.get("/api/articles", environ_base={"REMOTE_ADDR": "127.0.0.1"}, headers={"CF-Connecting-IP": "1.2.3.4"}) check("隧道 user /api/articles 403", r.status_code == 403) # 本地 cron 豁免(127.0.0.1 无 header)→ 200 client.get("/logout") r = client.get("/api/articles", environ_base={"REMOTE_ADDR": "127.0.0.1"}) check("本地 cron /api/articles 200", r.status_code == 200) # admin 权限(默认账号 admin/wechat2026) check("admin login 302", client.post("/login", data={"username": "admin", "password": "wechat2026"}).status_code == 302) check("admin /resumes 200", client.get("/resumes").status_code == 200) check("admin /api/articles 200", client.get("/api/articles").status_code == 200) # 清理测试账号 _conn = sqlite3.connect(os.path.join(VIEWER, "circle.db")) _conn.execute("DELETE FROM users WHERE username='verifyuser'") _conn.commit() _conn.close() ok = True for name, cond, detail in results: print(("PASS " if cond else "FAIL ") + name + (f" | {detail}" if detail and not cond else "")) ok = ok and cond print() print("RESULT:", "ALL PASS" if ok else f"{sum(1 for _, c, _ in results if not c)} FAILURES") sys.exit(0 if ok else 1)