# -*- coding: utf-8 -*- r'''走 Halo 的「邮箱找回密码」流程。 == 流程长什么样 == Halo 2.x 的重置密码分两步: 1. POST /password/restore/email {"email": "..."} -> 服务器往这个邮箱发一个验证码(6 位数字) 2. POST /password/restore/email/verify {"email": "...", "code": "..."} -> 校验验证码 3. PUT /password/restore {"password": "新密码"} -> 用上一步换来的临时凭据改密码 **⚠ 但前提是 Halo 配了 SMTP** —— 没配的话邮件根本发不出去, 用户等半天收不到码,白折腾。 所以这个脚本**先查 SMTP 配置**,再决定要不要发。 == 为什么不用令牌 == 用户先提邮箱这个方案,就按他的来。但两个方案其实可以并行: * 邮箱重置:能改密码 → 然后我用新密码登录 * 个人令牌:不用改密码,更安全 **改密码有个副作用**:用户自己也得记住新密码。 所以我会把新密码**明确告诉用户**。 == 关于验证码 == 用户会把验证码发给我。验证码有时效(Halo 默认 10 分钟), 所以拿到之后要**立刻**用。 ''' from __future__ import annotations import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) from lssh import run # noqa: E402 EMAIL = "3235109770@qq.com" def main() -> int: print("=" * 62) print(" Halo 邮箱找回密码 —— 先确认能不能发邮件") print("=" * 62) print() print("── 1. 重置接口存在吗 ──") out = run(r''' BASE=http://127.0.0.1:3001 for ep in \ "/password/restore/email" \ "/apis/api.halo.run/v1alpha1/password/restore/email" \ "/apis/uc.api.auth.halo.run/v1alpha1/password/restore/email" \ "/apis/api.console.halo.run/v1alpha1/indices/-/users" \ ; do printf " %-64s " "$ep" curl -s -o /dev/null -w "%{http_code}\n" --max-time 8 "$BASE$ep" done echo echo "── 2. 探测一下 POST 的形状(不发真请求,只看方法是否允许)──" curl -s -o /dev/null -w " POST /password/restore/email -> %{http_code}\n" \ --max-time 10 -X POST "http://127.0.0.1:3001/password/restore/email" \ -H "Content-Type: application/json" -d '{}' echo echo "── 3. Halo 的 SMTP 配了吗(数据库里找)──" sudo docker exec halo sh -c " find /root/.halo2 -name '*.mv.db' -o -name '*.db' 2>/dev/null | head -3 " 2>/dev/null | sed 's/^/ /' echo " 从设置接口看(需要登录,先看看会不会泄露结构):" curl -s --max-time 8 "http://127.0.0.1:3001/apis/api.halo.run/v1alpha1/configmaps" | head -c 200 echo echo echo "── 4. 邮件相关的日志(有没有发信记录/报错)──" sudo docker logs halo 2>&1 | grep -iE "mail|smtp|email|JavaMail" | tail -10 | sed 's/^/ /' || echo " (日志里没提邮件)" echo echo "── 5. 用户的邮箱地址(确认收件人)──" curl -s --max-time 8 "http://127.0.0.1:3001/apis/api.halo.run/v1alpha1/users" | head -c 300 echo ''', timeout=300, quiet=True) print(out[1] if isinstance(out, tuple) else out) print() print("── 6. 试发一次(如果接口在)──") out = run(r''' curl -s -w "\n HTTP %{http_code}\n" --max-time 20 \ -X POST "http://127.0.0.1:3001/password/restore/email" \ -H "Content-Type: application/json" \ -d '{"email":"__EMAIL__"}' 2>&1 | head -20 '''.replace("__EMAIL__", EMAIL), timeout=200, quiet=True) print(out[1] if isinstance(out, tuple) else out) print() print("── 7. 发完之后看日志(有没有真发出去)──") out = run(r''' sleep 3 sudo docker logs --tail 40 halo 2>&1 | grep -iE "mail|smtp|email|restore|code|error|exception" | tail -15 | sed 's/^/ /' || echo " (没有相关日志)" ''', timeout=200, quiet=True) print(out[1] if isinstance(out, tuple) else out) return 0 if __name__ == "__main__": sys.exit(main())