update: smtp 验证码有效期 60s 调整为 10 分钟,邮件正文从 CODE_TTL 派生

60 秒对邮件送达延迟过于紧张;正文有效期文案改为按 TTL 自动生成避免漂移,前端提示与 README 同步。同时移除 .env 排查用的凭证明文调试打印。
This commit is contained in:
qing committed 2026-07-29 19:32:44 +08:00
1 parent f5b69d0b4c
commit f4a7aca2fa
5 files changed
+8 -11

No files matched your search

+1 -1
View File
@@ -136,7 +136,7 @@
### smtp(邮件服务)
- 注册流程的邮箱验证码后端,基于 pymsg(MsgServer,TCP 长度前缀帧 + JSON),监听 127.0.0.1:8008。
- pymsg 路由:`send_email`(生成 6 位验证码并经 SMTP_SSL 发送,60 秒有效,发送失败自动作废)、`verify_email`(校验,通过即一次性消费防重放,兼容旧字段 `input_captcha`)、`health`。
- pymsg 路由:`send_email`(生成 6 位验证码并经 SMTP_SSL 发送,10 分钟有效,发送失败自动作废)、`verify_email`(校验,通过即一次性消费防重放,兼容旧字段 `input_captcha`)、`health`。
- 验证码存于进程内存(锁保护 + 惰性过期清理),SMTP 账号通过 `.env` 配置(`SMTP_SERVER` / `SMTP_PORT` / `SMTP_USER` / `__PASSWORD`,`__PASSWORD` 兼容别名 `SMTP_PASSWORD`)。
### aibox(独立 AI 智能体系统)
+2 -2
View File
@@ -9,7 +9,7 @@ UniServe Framework 的应用层网关,C++20 实现。
- **账号鉴权**:`/register` 注册(需邮箱验证码,经 pymsg 调 smtp:8008 校验)、`/login` 登录,签发 RSA 签名的 Token。
- **反向代理**:携带 Token 的请求校验后转发到 `Proxy.opened` 中放开的内部服务。
- **CAPTCHA 接口**:`/captcha` 生成验证码 token + 文本(内存存储,5 分钟过期,一次性使用)。
- **邮箱验证码**:`/register/send_code` 发送 6 位验证码邮件(60 秒有效);注册时校验,一次性消费。
- **邮箱验证码**:`/register/send_code` 发送 6 位验证码邮件(10 分钟有效);注册时校验,一次性消费。
- **速率限制**:登录 5 次/5 分钟、注册 3 次/10 分钟、发验证码 5 次/10 分钟,按 `X-Forwarded-For` 客户端 IP 计数(由 WAF 注入),超限一律返回 429。
- **OPTIONS 预检**:通配 `*` 返回 CORS 头,允许跨域。
@@ -84,7 +84,7 @@ UniServe Framework 的应用层网关,C++20 实现。
### `POST /register/send_code`
向目标邮箱发送注册验证码(经 pymsg 调 smtp:8008 `send_email`,60 秒有效)。
向目标邮箱发送注册验证码(经 pymsg 调 smtp:8008 `send_email`,10 分钟有效)。
```json
{ "email": "user@example.com" }
+3 -6
View File
@@ -71,12 +71,13 @@ SMTP_USER = os.environ.get("SMTP_USER", "")
SMTP_PASSWORD = os.environ.get("__PASSWORD") or os.environ.get("SMTP_PASSWORD", "")
CODE_LEN = 6
CODE_TTL = 60 # 验证码有效期(秒)
CODE_TTL = 600 # 验证码有效期(秒)
# 多数邮箱服务商(163/QQ 等)强制 From 头与登录账号一致,故默认跟随 SMTP_USER;
# 仅当服务商允许自定义发件身份时才在 .env 里显式配 MAIL_FROM 覆盖
MAIL_FROM = os.environ.get("MAIL_FROM") or SMTP_USER
DEFAULT_SUBJECT = "DNFS 邮箱验证"
DEFAULT_CONTENT = "DNFS: 您的邮箱验证码为 {code},一分钟内有效。"
# 有效期文案由 CODE_TTL 派生,改 TTL 不用同步改这里({{code}} 是 f-string 转义)
DEFAULT_CONTENT = f"DNFS: 您的邮箱验证码为 {{code}},{CODE_TTL // 60} 分钟内有效。"
code_store = {} # email -> {'code': str, 'expires_at': float}
STORE_LOCK = threading.Lock()
@@ -104,10 +105,6 @@ class SmtpServer:
# ── 启动 / 停止 ──────────────────────────────────────────────────
def start(self) -> None:
"""启动服务(阻塞当前线程)。"""
# 调试:打印加载到的凭证(明文,含密码;仅 print 不落日志库,调完请删)
print(f"[smtp] 凭证加载(.env 贡献 {_env_loaded} 项): "
f"SMTP_SERVER={SMTP_SERVER!r} SMTP_PORT={SMTP_PORT} "
f"SMTP_USER={SMTP_USER!r} __PASSWORD={SMTP_PASSWORD!r}")
if not all([SMTP_SERVER, SMTP_USER, SMTP_PASSWORD]):
# 只报缺失的 key 名,绝不报值
missing = [k for k, v in (("SMTP_SERVER", SMTP_SERVER),
+1 -1
View File
@@ -127,7 +127,7 @@ getCodeButton.addEventListener('click', async function () {
codeTarget = email;
codeInput.value = '';
codeTip.textContent = '验证码已发送至邮箱,请查收(60 秒内有效)';
codeTip.textContent = '验证码已发送至邮箱,请查收(10 分钟内有效)';
codeTip.classList.remove('tip-red', 'tip-yellow', 'tip-green');
codeTip.classList.add('tip-green');
} catch (err) {
+1 -1
View File
@@ -7,7 +7,7 @@ smtp 黑盒用户模拟测试 — 发送邮箱验证码 → 校验。
3. 用空参数校验 → 应报错
注意: SMTP 服务需要配置真实的邮件服务器。若服务不可达或邮件发送失败,
相关测试将标记为 SKIP。验证码有效期为 60 秒。
相关测试将标记为 SKIP。验证码有效期为 10 分钟(600 秒)。
"""
import json