Smail/docs/配置系统重构需求文档.md

1859 lines
83 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Smail 配置系统重构需求文档
## 1. 文档信息
| 项目 | 内容 |
|---|---|
| 文档名称 | Smail 配置系统重构需求文档 |
| 文档状态 | 产品决定与技术复审已通过,待实施 |
| 当前版本 | 0.7 |
| 编写日期 | 2026-08-25 |
| 适用项目 | Smail |
| 主要范围 | 初始化流程、统一配置入口、分区配置、分级管理、插件配置、登录认证、密码恢复、安全控制 |
> 本文档用于明确配置系统重构需求,不作为最终技术实现的唯一依据。完成需求确认后,还需要编写技术设计和实施任务清单。
---
## 2. 背景
当前 Smail 使用 `config/config.json` 保存数据库、域名、SSL、第三方推送和插件许可等多种配置。随着 SMTP 中继、邮箱验证码、插件管理和第三方推送能力增加,单一配置结构将出现以下问题:
1. 基础启动配置与业务配置混合;
2. 敏感凭据分散,保护范围不完整;
3. 初始化向导承担过多后续管理职责;
4. 配置修改是否立即生效缺少统一定义;
5. 插件配置来源不统一;
6. 配置文件拆分后可能出现版本和状态不一致;
7. 普通用户配置与管理员全局配置边界不清晰;
8. 配置验证、保存、回滚和审计缺少统一入口。
因此,需要重构配置系统,使 `config.json` 成为唯一主入口,并将 SMTP、邮箱策略、SSL 和插件配置拆分为独立配置分区,由 Smail 主程序统一管理。
---
## 3. 建设目标
### 3.1 核心目标
1. 将 `config.json` 作为 Smail 配置系统的唯一主入口;
2. 将 SMTP、邮箱策略、SSL、插件配置拆分为独立文件;
3. 建立统一配置加载、验证、加密、保存、应用和回滚机制;
4. 缩减首次初始化流程,将高级配置迁移到管理员设置页面;
5. 明确配置的权限边界和生效方式;
6. 保证数据库密码、SMTP 密码、第三方 Token 和 Secret 不以明文落盘;
7. 插件不得直接读取主配置或数据库凭据;
8. 配置错误时优先进入可恢复状态,不允许带着明显错误启动全部邮件服务;
9. 保持 Windows 开发环境和 Ubuntu 22.04、24.04 生产环境可用;
10. 为后续增加新配置分区和新插件保留扩展能力;
11. 建立超级管理员、管理员和普通用户的插件配置权限边界;
12. 支持用户名或完整用户邮箱登录,并建立分角色的密码修改和恢复机制。
### 3.2 非目标
本阶段不默认包含以下内容,除非后续明确纳入:
1. 完整实现新的邮箱注册业务;
2. 新增短信验证码、TOTP 或第三方社交账号登录;
3. 重写与本轮 SMTP Relay 和验证码投递无关的邮件传输协议实现;
4. 提供任意第三方插件上传和在线安装能力;
5. 支持插件直接访问 Smail 主数据库;
6. 支持管理员配置任意系统绝对路径;
7. 支持在不重启的情况下切换数据库;
8. 支持多个管理员同时无冲突地编辑同一个配置区。
---
## 4. 术语定义
| 术语 | 定义 |
|---|---|
| 主入口配置 | `config/config.json`,保存系统基础配置、启动状态和配置分区信息 |
| 分区配置 | SMTP、邮箱策略、SSL、插件等独立配置文件 |
| 运行时配置 | 主程序加载并验证所有配置后生成的只读内存快照 |
| 候选配置 | 尚未正式应用的新配置 |
| 配置代次 | 每次成功保存配置后递增的版本号,用于防止并发覆盖 |
| 全局配置 | 仅超级管理员可修改、对整个 Smail 实例生效的配置;管理员只能按授权查看脱敏状态 |
| 用户配置 | 当前登录用户自己的插件或邮箱偏好设置 |
| 引导模式 | 已创建数据库和管理员,但邮件服务尚未完全启用的状态 |
| 降级模式 | 配置损坏或关键服务不可用时,只启动安全管理入口的状态 |
| 敏感字段 | 数据库密码、SMTP 密码、Token、Secret、签名密钥等需要加密保护的字段 |
---
## 5. 用户角色和访问身份
### 5.1 角色模型
系统必须采用基于角色的访问控制,并设置以下三个持久化角色:
| 角色 | 角色标识 | 定位 |
|---|---|---|
| 超级管理员 | `super_admin` | 负责系统级配置、安全配置、管理员授权和故障恢复 |
| 管理员 | `admin` | 负责日常用户管理、运行维护和非敏感管理操作 |
| 普通用户 | `user` | 使用自己的邮箱和用户级功能 |
角色要求:
1. 初始化流程创建的第一个账户必须是超级管理员;
2. 系统任何时刻必须至少保留一个未禁用的超级管理员;
3. 新建用户未明确指定角色时,默认角色必须是普通用户;
4. 角色判断必须由后端完成,不能依赖前端隐藏按钮实现权限控制;
5. 后端必须使用明确的权限能力进行授权,不能只通过角色名称的大小关系推断权限;
6. 未初始化访问者不是持久化用户角色,只能持有受限的初始化访问身份;
7. 当前两级 `is_admin` 模型不能作为重构后的最终授权依据,需要迁移为明确的角色字段;
8. 迁移期间如保留 `is_admin`,该字段只能作为兼容输出,不能与新角色字段分别参与授权判断。
### 5.2 超级管理员
允许:
- 查看系统、服务和配置分区的运行状态;
- 修改系统基础、数据库、SMTP、SSL 和插件全局配置;
- 测试数据库、SMTP、SSL 和第三方服务;
- 启用、禁用、重启和授权插件;
- 创建、授权、停用和恢复管理员;
- 重置管理员和普通用户的密码,并要求目标用户下次登录时修改临时密码;
- 将普通用户提升为管理员,或者将管理员降级为普通用户;
- 查看脱敏后的配置、配置应用结果、审计日志和最近错误;
- 执行配置回滚、故障恢复和需要高权限确认的系统操作。
- 通过管理接口修改数据库密码、SMTP 密码、Token;
禁止:
- 通过管理接口读取数据库密码、SMTP 密码、Token、Secret 或私钥原文;
- 删除、停用或降级系统中最后一个可用的超级管理员;
- 通过普通用户编辑接口变更超级管理员身份;
- 配置任意未授权文件路径;
- 将插件配置为直接读取主数据库凭据;
- 绕过配置校验、审计或二次身份确认强制应用高风险配置。
### 5.3 管理员
允许:
- 查看系统和邮件服务的运行状态;
- 查看脱敏后的非机密配置和配置应用结果;
- 管理普通用户、邮箱账户和日常邮件业务;
- 停用或恢复普通用户;
- 使用系统已经保存的配置执行连接测试和服务健康检查;
- 查看职责范围内的运行日志、告警和审计记录;
- 重启明确授权的业务服务或插件实例。
禁止:
- 创建、删除、停用、恢复、提升或降级超级管理员和管理员;
- 修改数据库连接、加密主密钥、SMTP 凭据、SSL 私钥和第三方全局凭据;
- 修改系统启动状态、配置目录、插件全局权限和安全策略;
- 查看任何敏感字段原文;
- 管理其他管理员的密码、会话或安全认证信息;
- 执行配置回滚、数据库切换等仅限超级管理员的高风险操作;
- 绕过后端权限检查调用超级管理员接口。
### 5.4 普通用户
允许:
- 使用自己的邮箱和普通业务功能;
- 修改自己的资料、密码和用户级安全设置;
- 查看和撤销自己的登录会话;
- 修改自己的用户级插件设置;
- 测试自己的 Telegram Chat ID 等个人配置。
禁止:
- 访问超级管理员或管理员接口;
- 查看或修改插件全局 Token;
- 查看其他用户的资料、邮件、会话或插件设置;
- 创建、停用、删除或修改其他用户;
- 修改系统基础、数据库、SMTP、SSL、插件权限和安全策略配置。
### 5.5 未初始化访问身份
未初始化访问身份只在 `setupState` 为 `new` 或允许继续初始化的 `bootstrap` 阶段有效。
允许:
- 访问初始化状态和初始化页面;
- 配置初始化所需的最小参数;
- 创建第一个超级管理员账户;
- 在初始化授权有效期内继续未完成的初始化步骤。
禁止:
- 访问正常的超级管理员、管理员或普通用户页面;
- 读取现有敏感配置;
- 启用普通插件或完整邮件服务;
- 修改初始化范围之外的邮件业务配置;
- 在初始化完成后继续使用初始化凭据。
### 5.6 通用授权要求
1. 所有管理接口必须默认拒绝访问,只有明确授权的角色和权限能力才能调用;
2. 越权访问统一返回无权限结果,不得通过响应差异泄露敏感资源是否存在;
3. 修改角色、凭据、数据库、SMTP、SSL、插件权限和安全策略时,必须重新验证当前操作者身份;
4. 角色变更、账户停用、密码修改和高风险配置修改后,必须使受影响的旧会话失效;
5. 所有角色和权限变更必须写入安全审计日志,并记录操作者、目标账户、变更前后角色、时间和结果;
6. 审计日志、接口响应和错误信息不得记录密码、Token、Secret、私钥或完整数据库连接凭据;
7. 前端菜单和按钮应根据权限能力显示,但前端判断不能替代后端授权;
8. 超级管理员与管理员应使用独立的管理接口或明确的权限中间件,不能继续统一使用单一 `IsAdmin` 布尔判断;
9. 角色字段只能使用受控枚举值,遇到未知、空值或损坏值时必须按普通用户或拒绝访问处理,不能自动提升权限。
---
## 6. 总体配置结构
### 6.1 目录结构
```text
config/
├── config.json
├── smtp.json
├── email.json
├── ssl.json
├── plugins.json
├── dkim/
│ └── dkim.priv
└── ssl/
├── private.key
└── public.crt
```
### 6.2 主入口原则
`config.json` 必须是配置系统的唯一主入口。
主程序启动时只从 `config.json` 开始加载配置。其他业务模块和插件不得绕过配置管理器直接读取配置文件。
### 6.3 固定分区文件
分区名称和文件名由程序固定映射:
| 分区 | 文件 |
|---|---|
| SMTP | `smtp.json` |
| 邮箱策略 | `email.json` |
| SSL | `ssl.json` |
| 插件 | `plugins.json` |
不允许通过配置或 API 指定以下内容:
- 绝对路径;
- 上级目录;
- 符号链接目标;
- 任意文件名;
- 网络路径;
- 其他配置目录。
---
## 7. 主入口配置需求
### 7.1 推荐结构
```json
{
"schemaVersion": 2,
"generation": 1,
"setupState": "bootstrap",
"logLevel": "info",
"database": {
"type": "mysql",
"host": "127.0.0.1",
"port": 3306,
"username": "smail",
"password": "ENC[...]",
"name": "smail"
},
"domains": {
"primary": "example.com",
"accepted": [
"example.com"
],
"web": "mail.example.com"
},
"ports": {
"http": 80,
"https": 443
},
"sections": {
"smtp": true,
"email": true,
"ssl": true,
"plugins": true
}
}
```
### 7.2 字段要求
| 字段 | 必需 | 说明 |
|---|---:|---|
| `schemaVersion` | 是 | 配置格式版本 |
| `generation` | 是 | 配置代次,成功保存后递增 |
| `setupState` | 是 | 当前初始化和运行状态 |
| `logLevel` | 是 | 日志级别 |
| `database` | 是 | MySQL、PostgreSQL 或 SQLite 的结构化连接配置 |
| `domains` | 引导模式后必需 | 主域名、接收域名、管理域名 |
| `ports` | 是 | HTTP、HTTPS 管理端口 |
| `sections` | 是 | 各分区是否启用 |
### 7.3 主入口限制
1. 不保存 SMTP Relay 的具体配置;
2. 不保存邮箱验证码的具体配置;
3. 不保存 SSL 私钥内容;
4. 不保存第三方插件配置;
5. 不保存用户级插件设置;
6. 不允许出现未定义字段;
7. 数据库凭据必须加密保存;
8. API 返回时数据库连接信息必须脱敏。
数据库字段必须满足:
1. `type` 只允许 `mysql`、`postgresql`、`sqlite`;
2. MySQL 和 PostgreSQL 使用 `host`、`port`、`username`、`password`、`name`;
3. 初始化页面默认只要求选择类型并填写主机地址、用户名和密码,端口按数据库类型自动填写,可在高级设置中修改;
4. 数据库名称由系统按部署规则自动生成并允许超级管理员后续按第 20 章迁移,初始化页面不要求普通输入;
5. 数据库和表结构由系统自动创建,不要求用户预先创建;
6. SQLite 使用独立本地数据库模式,不显示主机、端口、用户名和密码,也不得接受客户端提供任意文件路径;
7. `password` 必须使用当前凭据保护机制加密,配置加密主密钥不得与密文保存在同一数据库;
8. DSN 只能由后端在内存中根据结构化字段构造,不得作为主配置模型或通过 API 返回。
---
## 8. 初始化状态需求
### 8.1 状态定义
| 状态 | 说明 | 允许启动的服务 |
|---|---|---|
| `new` | 尚未初始化 | 初始化服务 |
| `bootstrap` | 数据库和管理员已建立 | 数据库、Session、管理后台 |
| `ready` | 配置完整并已启用 | 全部允许的服务 |
| `degraded` | 关键配置损坏或服务启动失败 | 数据库、Session、安全管理后台 |
### 8.2 状态转换
```text
new
→ 完成数据库验证和管理员创建
bootstrap
→ 完成必需配置并通过预检
ready
→ 关键配置损坏或关键服务启动失败
degraded
→ 管理员修复并通过预检
ready
```
### 8.3 状态要求
1. 不再使用单一 `isInit` 表达全部状态;
2. `bootstrap` 状态不得启动 SMTP、POP3、IMAP 和普通插件;
3. `degraded` 状态不得自动回退到不安全默认配置;
4. `ready` 状态必须通过启动前完整预检;
5. 非法状态必须拒绝启动正式服务;
6. 状态变化必须记录审计日志;
7. 状态变化必须原子保存。
---
## 9. 初始化流程需求
### 9.1 初始化阶段必需内容
初始向导至少完成:
1. 数据库类型选择;
2. 数据库连接验证;
3. 数据库初始化;
4. 第一个超级管理员账户创建;
5. 超级管理员密码设置;
6. 主域名和 Web 域名设置;
7. SSL 默认目录或自定义上传托管模式配置;
8. 基础监听端口设置;
9. SSL 配置成功后安全跳转至超级管理员登录页。
### 9.2 已确认的初始化范围
初始化阶段继续完成数据库、首个超级管理员、主域名、Web 域名和 SSL 配置。SSL 尚未配置成功时,可以仅在初始化范围内临时使用 HTTP;SSL 配置成功后,生产环境管理后台必须强制使用 HTTPS,不得继续提供公网明文管理入口。
启用管理员和普通用户的公开自助重置功能后,系统必须在已配置的 Web 域名或访问 IP 下提供固定入口 `/Reset`,即 `https://域名/Reset` 或 `https://IP/Reset`。入口路径大小写敏感,仅允许 `GET` 加载恢复页面;功能关闭、配置未完成或没有有效访问主机时不得开放。该入口只属于普通 Web 自助恢复范围,超级管理员仍只能通过部署端 `systemctl start smail-admin` 和受保护本机 IPC 重置。
### 9.3 初始化完成条件
进入 `bootstrap` 状态前必须满足:
- 数据库连接成功;
- 必需数据表已经建立;
- 超级管理员账户已经建立;
- 超级管理员密码满足安全要求;
- 管理后台可以安全访问;
- 基础配置已经原子写入。
进入 `ready` 状态前必须满足:
- 主域名合法;
- 至少存在一个接收域名;
- 数据库可用;
- DKIM 配置可用;
- SSL 配置可用,生产环境管理后台已切换为 HTTPS;
- SMTP 配置通过验证;
- 所有启用插件的配置通过验证;
- 必需监听端口未冲突。
---
## 10. SMTP 配置需求
### 10.1 配置文件
```text
config/smtp.json
```
### 10.2 推荐结构
```json
{
"version": 1,
"inbound": {
"spamFilterLevel": 0
},
"outbound": {
"mode": "direct",
"relay": {
"host": "",
"port": 465,
"encryption": "tls",
"authType": "login",
"username": "",
"password": "",
"from": ""
}
},
"dkim": {
"privateKeyPath": "config/dkim/dkim.priv"
}
}
```
### 10.3 功能要求
1. 支持直接投递和中继投递两种模式;
2. 中继模式必须提供连接测试;
3. 中继密码必须加密保存;
4. 管理 API 不得返回中继密码原文;
5. 日志不得输出完整认证信息;
6. SMTP 主机、端口和加密方式必须严格校验;
7. 不允许因为配置错误形成开放中继;
8. 发件人地址必须受管理员配置和登录用户权限限制;
9. 配置修改后必须明确是否需要重启邮件发送模块;
10. 连接测试必须有超时、频率限制和目标限制。
### 10.4 生效方式
| 配置 | 生效方式 |
|---|---|
| 垃圾邮件过滤等级 | 可立即生效 |
| SMTP 中继超时 | 可立即生效 |
| 直接投递与中继模式切换 | 重启发送模块或整个服务 |
| DKIM 私钥路径 | 重启相关邮件服务 |
| 中继认证信息 | 重新创建发送客户端后生效 |
---
## 11. 邮箱策略配置需求
### 11.1 配置文件
```text
config/email.json
```
### 11.2 推荐结构
```json
{
"version": 1,
"verificationCode": {
"enabled": false,
"from": "",
"fromName": "",
"expireMinutes": 5,
"sendIntervalSeconds": 60,
"maxPerHour": 5,
"maxVerifyAttempts": 5,
"tokenExpireMinutes": 5,
"hashSecret": ""
}
}
```
### 11.3 功能要求
1. 验证码功能默认关闭,必须通过api请求后才开启,使用后即关闭;
2. 签名密钥由系统自动生成,不要求管理员手工填写;
3. 签名密钥必须加密保存;
4. 验证码不得明文持久化;
5. 验证码必须与用途、用户、邮箱和有效期绑定;
6. 必须限制发送频率;
7. 必须限制验证尝试次数;
8. 必须防止验证码重放;
9. 错误响应不得泄露账户是否存在;
10. 配置修改必须记录审计日志。
### 11.4 范围说明
本轮完整实现邮箱策略配置、外部安全邮箱和验证码业务。功能开关仅用于安全验收后的受控启停;在验证码生成、内存生命周期、SMTP 投递、校验、限流、审计、故障处理和清理任务全部通过验收并由超级管理员显式启用前,不得开放对应登录或恢复路径,也不得降低现有恢复验证要求。
本轮必须完成:
- 配置模型;
- 配置保存;
- 凭据保护;
- 管理页面;
- 配置验证。
- 完整邮箱验证码服务;
- SMTP 投递;
- 登录邮箱二次验证;
- 外部邮箱密码恢复;
- 外部邮箱管理页面;
- 非敏感运营数据和定期清理。
验证码原文、校验值和验证码任务只能存在于签发验证码的认证进程内存,过期、消费、进程退出或服务重启后立即销毁;非敏感限流、投递、脱敏统计和安全审计数据允许持久化,并按独立需求规定每 14 天执行一次清理任务。
---
## 12. SSL 配置需求
### 12.1 配置文件
```text
config/ssl.json
```
### 12.2 推荐结构
```json
{
"version": 1,
"enabled": true,
"mode": "managed_default",
"storage": {
"source": "default",
"certificateRef": "current/public.crt",
"privateKeyRef": "current/private.key"
},
"acme": {
"enabled": false,
"challenge": "http",
"provider": "",
"renewBeforeDays": 30
}
}
```
### 12.3 功能要求
1. SSL 使用“默认受控目录”和“自定义上传后由 Smail 托管”两种模式;
2. 默认模式使用 Smail 管理的 `config/ssl` 目录;自定义模式必须先上传证书和私钥,再由 Smail 复制到受控目录并生成内部引用;
3. 不允许通过 API 配置或读取任意系统绝对路径,客户端不得提交服务器文件路径;
4. 不允许跟随符号链接、重解析点或硬链接读取证书和私钥;
5. 私钥文件权限必须受到限制;
6. 保存前必须校验证书与私钥匹配;
7. 必须校验证书有效期和域名;
8. ACME 更新失败不得破坏当前有效证书;
9. 新证书必须先写入候选目录,再原子切换内部引用;
10. SSL 配置修改后必须提示重启 HTTPS 服务,并允许超级管理员点击受控重启按钮;
11. API 不得返回私钥内容、真实服务器绝对路径或可用于路径探测的信息;
12. 自定义上传文件必须限制类型、大小和数量,拒绝路径穿越、压缩包、可执行文件和异常 PEM 内容。
---
## 13. 插件配置需求
### 13.1 配置文件
```text
config/plugins.json
```
### 13.2 插件逻辑标识
统一使用固定插件 ID:
```text
spam_block
wechat_push
telegram_push
```
业务 ID 不得直接依赖 Windows 或 Linux 可执行文件名。
### 13.3 推荐结构
```json
{
"version": 1,
"plugins": {
"spam_block": {
"enabled": false,
"executable": "spam_block",
"permissions": {
"network": true
},
"settings": {}
},
"wechat_push": {
"enabled": false,
"executable": "wechat_push",
"permissions": {
"network": true
},
"settings": {}
},
"telegram_push": {
"enabled": false,
"executable": "pmail_telegram_push",
"permissions": {
"network": true
},
"settings": {}
}
}
}
```
### 13.4 功能要求
1. 使用 `enabled` 代替按文件名维护的插件许可列表;
2. 插件逻辑 ID 与可执行文件名分离;
3. 主程序负责读取、验证、解密和保存插件配置;
4. 插件不得直接读取 `config.json`;
5. 插件不得获得数据库 DSN;
6. 插件不得直接访问 Smail 主数据库;
7. 主程序只向插件传递该插件自己的运行时配置;
8. 插件 Secret 和 Token 必须加密保存;
9. 管理 API 只返回脱敏信息;
10. 插件配置失败时不得注册邮件 Hook;
11. 插件配置更新失败时必须保留旧配置;
12. 网络权限必须按插件配置,不能继续只使用全局网络开关;
13. 插件启动前必须检查可执行文件权限和所有者;
14. 插件源代码目录与运行时可执行文件目录需要保持清晰边界;
15. 只有超级管理员可以启用、禁用插件,以及修改插件全局配置和权限;
16. 超级管理员可以查看和修改所有角色用户的用户级插件配置;
17. 管理员只能查看和修改普通用户的用户级插件配置,不得修改超级管理员或其他管理员的插件配置;
18. 普通用户只能查看和修改自己的用户级插件配置;
19. 超级管理员或管理员代替其他用户修改插件配置时,必须明确记录操作者、目标用户、插件、变更内容和结果;
20. 跨用户修改接口必须使用目标用户 ID,不得仅依赖可伪造或可能变更的用户名、邮箱地址;
21. 批量修改所有用户插件配置必须作为独立的高风险操作,由超级管理员二次确认,不得静默覆盖用户已经保存的个性化配置。
22. 首版对插件可访问的目标主机、端口和协议实施强制白名单,未列入白名单的网络请求默认拒绝;
23. 插件 Token、Secret、API Key 等关键信息必须保存在数据库并加密,不能以明文写入插件配置文件;
24. 插件不得读取配置加密主密钥、主配置、数据库凭据、主数据库或其他插件配置;
25. Web Push 作为插件能力统一管理,不保留绕过插件权限模型的系统内置配置入口。
### 13.5 用户级插件配置
以下配置必须保存在数据库:
- Telegram Chat ID;
- 是否显示邮件正文;
- 是否发送附件;
- 是否禁用链接预览;
- 用户自己的推送开关。
用户级设置不得写入 `plugins.json`。
用户级插件配置接口必须按以下权限执行:
| 操作者 | 可操作范围 | 禁止范围 |
|---|---|---|
| 超级管理员 | 所有用户的用户级插件配置 | 读取插件 Token、Secret 等敏感值原文 |
| 管理员 | 普通用户的用户级插件配置 | 超级管理员、管理员和插件全局配置 |
| 普通用户 | 当前登录用户自己的用户级插件配置 | 其他用户和插件全局配置 |
用户级插件配置发生越权访问时必须统一拒绝,不得通过响应内容泄露目标用户或配置是否存在。
---
## 14. 配置管理器需求
### 14.1 唯一磁盘访问入口
只有统一配置管理器可以:
- 读取配置文件;
- 写入配置文件;
- 加密和解密敏感字段;
- 执行配置迁移;
- 更新配置代次;
- 创建运行时快照。
业务模块和插件禁止直接读取分区配置文件。
### 14.2 推荐运行时模型
```go
type RuntimeConfig struct {
Root RootConfig
SMTP SMTPConfig
Email EmailConfig
SSL SSLConfig
Plugins PluginConfig
}
```
### 14.3 加载流程
```text
读取 config.json
→ 校验主入口结构和版本
→ 加载启用的分区配置
→ 严格解析 JSON
→ 解密敏感字段
→ 执行分区校验
→ 执行跨分区校验
→ 生成不可变运行时快照
→ 一次性替换当前配置
```
### 14.4 JSON 解析要求
1. 拒绝未知字段;
2. 拒绝重复字段;
3. 拒绝尾随多余 JSON 内容;
4. 限制单个配置文件大小;
5. 限制字符串、数组和嵌套结构大小;
6. 拒绝非法数字范围;
7. 不允许使用宽松类型转换绕过校验。
### 14.5 并发要求
1. 运行时读取不能看到半更新状态;
2. 配置保存必须串行处理;
3. API 更新必须携带预期配置代次;
4. 配置代次不一致时拒绝覆盖;
5. 运行时快照应当只读;
6. 不允许业务模块直接修改全局配置对象。
---
## 15. 配置保存和回滚需求
### 15.1 单分区更新流程
```text
验证超级管理员权限
→ 验证 CSRF
→ 检查请求体大小
→ 检查 expectedGeneration
→ 严格解析请求
→ 构造候选运行时配置
→ 执行完整校验
→ 测试外部连接或插件配置
→ 加密敏感字段
→ 原子写入目标分区文件
→ 更新主入口 generation
→ 应用运行时配置
→ 返回生效方式
```
### 15.2 失败处理
1. 校验失败不得写入文件;
2. 测试失败不得覆盖旧配置;
3. 文件写入失败不得修改运行时配置;
4. 应用失败必须恢复旧运行时配置;
5. 恢复失败时停止受影响服务并进入 `degraded` 状态;
6. 失败日志不得包含敏感字段;
7. 管理页面必须显示可理解的中文错误信息。
### 15.3 配置备份
配置备份采用以下策略:
- 周期:每 7 天创建一次已验证备份;
- 最长保留:30 天;
- 最大数量:4 份;
- 始终保留至少一个已经验证可以恢复的有效配置代次;
- 备份包含主入口、相关分区、配置代次、摘要、Schema 版本和必要审计元数据,不包含解密后的 Secret。
清理顺序必须为:
1. 新备份成功创建并完成完整性与可恢复性验证;
2. 删除超过 30 天的备份;
3. 仍超过 4 份时再删除最旧备份;
4. 新备份失败时不得删除当前任何有效备份;
5. 清理过程不得删除当前运行代次或唯一有效备份。
备份文件必须与正式配置采用相同的安全权限,备份创建、验证、清理和恢复均写入审计日志。
---
## 16. 敏感信息保护需求
### 16.1 必须加密的字段
至少包括:
- 结构化数据库配置中的数据库密码;
- SMTP 中继密码;
- 微信 Secret;
- Telegram Bot Token;
- Web Push Token;
- 邮箱验证码签名密钥;
- DNS 提供商 API Secret;
- 其他第三方访问凭据。
### 16.2 加密要求
1. 复用 Smail 当前凭据保护机制;
2. 不使用登录密码哈希算法加密第三方 Secret;
3. 登录密码继续使用不可逆密码哈希;
4. 第三方 Secret 使用经过认证的可逆加密;
5. 新配置不得依赖旧的弱加密算法;
6. 密文被篡改时必须拒绝加载;
7. 密钥文件不得提交到 Git;
8. 凭据不得通过 URL、命令行参数或普通日志传递;
9. 尽量避免通过环境变量长期传递插件 Secret;
10. 前端不得缓存敏感字段原文。
### 16.3 API 脱敏
配置查询返回:
```json
{
"username": "admin@example.com",
"passwordConfigured": true
}
```
不得返回:
```json
{
"password": "原始密码或密文"
}
```
更新 Secret 时需要区分:
- 保留原 Secret;
- 设置新 Secret;
- 明确清除 Secret。
### 16.4 登录标识要求
Web 登录页面必须允许以下两种登录方式,并统一使用“登录标识 + 密码”表单:
1. 用户名 + 密码;
2. 完整用户邮箱 + 密码。
具体要求:
1. 登录请求字段建议使用 `identifier`,不得由前端声明本次输入是用户名还是邮箱;
2. 后端根据规范化后的格式解析登录标识,并通过唯一索引完成精确匹配;
3. 用户邮箱必须是已经绑定到该用户、允许登录且状态正常的完整邮箱地址;
4. 不得简单删除 `@` 及其后面的域名后按用户名登录,必须校验邮箱地址与用户的真实绑定关系;
5. 邮箱别名默认不得作为登录标识,确需支持时必须显式标记为允许登录并保证全局唯一;
6. 用户名、主邮箱和允许登录的邮箱地址不得产生跨用户冲突;
7. 登录成功后必须得到同一个用户 ID、角色和会话安全状态,两种登录方式不得产生不同权限;
8. 登录失败统一返回“用户名、邮箱或密码错误”,不得泄露账户、邮箱或角色是否存在;
9. 登录限流必须同时覆盖 IP、规范化登录标识和解析后的用户 ID,不能通过用户名与邮箱交替尝试绕过限制;
10. Web 登录与 SMTP、IMAP、POP3 协议认证应复用同一密码验证服务,但协议是否允许邮箱别名登录需要单独配置和测试;
11. 数据库需要保存不可变用户 ID 与主邮箱的明确关联,不能只依赖当前域名配置临时拼接邮箱地址。
### 16.5 密码修改和重置边界
1. 管理员和普通用户通过 Web 修改自己的密码时,必须验证当前密码;超级管理员不得使用该 Web 接口;
2. 超级管理员密码不得使用公开的“忘记密码”页面重置;
3. 超级管理员密码的修改和恢复只保留部署主机专用维护能力;
4. 超级管理员可以不配置离线恢复码;需要重置密码时,必须先在部署主机运行固定的 Smail 重置命令,由该命令请求开启专用重置通道;
5. 专用重置通道必须默认关闭,只能通过部署端命令临时开启,不得通过普通 Web 页面、公共 API、配置文件开关或开发模式自动开启;
6. 专用重置通道只能使用 Unix Domain Socket、Windows Named Pipe 或等效的受保护本机 IPC,不监听公网或局域网 TCP,不注册到普通 HTTP Router,也不得由反向代理公开;
7. 每次开启必须生成绑定目标超级管理员、进程实例、用途和有效期的短时一次性维护凭据;凭据必须在受保护的本机通道传递,不能进入命令行参数、URL、环境变量、普通日志或长期配置;
8. 超级管理员密码修改成功、维护凭据消费、失败达到阈值、维护进程退出或时限到期后,专用重置通道必须自动关闭并拒绝重放;
9. 超级管理员密码修改后必须使该账户全部旧会话、恢复凭据和长期登录状态失效;
10. 管理员和普通用户可以通过登录页面启动“忘记密码”流程;本轮启用的路径要求同时完成密保问答,以及离线恢复码或 WebAuthn 安全密钥中的至少一种验证;
11. 超级管理员可以重置管理员和普通用户的密码,但必须重新验证超级管理员当前密码;
12. 超级管理员执行重置时,应生成短时一次性重置凭据或临时密码,目标用户下次登录必须设置新密码;
13. 管理员可以重置普通用户密码,但必须使用独立能力、近期重新认证或 WebAuthn 二次确认,并复用完整的凭据撤销、通知和审计事务;管理员不得重置管理员或超级管理员;
14. 超级管理员重置目标用户密码时,必须撤销目标用户全部 WebAuthn 凭据、全部旧离线恢复码、全部登录 Session、未完成恢复流程和未消费重置票据;
15. 超级管理员重置目标用户密码时,必须递增 Session、Security 和 Credential 版本;目标用户下次登录必须生成新的离线恢复码,并收到重新绑定 WebAuthn 的明确提示;
16. WebAuthn 私钥只能由用户认证器生成,系统不得自动生成或代替用户重新绑定安全密钥;
17. 超级管理员重置目标用户密码后,应向已经验证的外部安全邮箱发送安全通知;通知投递暂时不可用或发送失败不得恢复已撤销的凭据;
18. 所有密码修改和重置成功后必须递增会话版本,使目标用户全部旧会话失效;
19. 密码重置请求、结果、操作者、撤销范围和通知结果必须写入安全审计日志,但不得记录新旧密码、密保答案、恢复码或完整重置凭据;
20. 部署端重置命令、专用重置通道及其跨平台安全测试未完成前,本轮配置系统重构不得通过最终验收。
### 16.6 密保问题和答案
管理员和普通用户使用“忘记密码”前,必须在已登录状态下自行设置密保问题和答案。密保问答只能作为辅助验证,不能作为允许密码重置的唯一恢复凭据。
密保要求:
1. 每个用户至少设置三个互不相同的密保问题和答案;
2. 设置、修改或删除密保信息时必须验证当前密码;
3. 密保信息必须绑定不可变用户 ID,同时关联规范化用户名和主邮箱;
4. 用户名或主邮箱变更时,必须原子更新密保绑定关系,并使正在进行的密码恢复流程失效;
5. 找回密码时,每次随机选择不少于两个已设置问题,全部回答正确后才能继续;
6. 用户自定义的问题需要使用经过认证的可逆加密保存,避免数据库泄露后直接暴露个人信息;
7. 密保答案不得可逆加密保存,必须使用不可逆密码哈希;
8. 每条密保答案必须使用独立随机盐,并使用服务端密钥进行域隔离,不能与登录密码哈希直接复用同一输入域;
9. 密保答案建议使用 Argon2id 或项目统一批准的抗暴力破解算法,并保存算法版本和参数;
10. 不得为每个用户随机选择未知或未经审计的加密算法;所谓“随机加密”必须落实为固定安全算法配合随机盐、随机数和可迁移的算法版本;
11. 密保答案采用大小写不敏感的固定规范化:去除首尾空格、执行固定 Unicode 规范化、英文字符统一小写并合并连续空白;设置和验证必须使用完全相同的版本化规则;
12. 任何角色都不得通过 API、管理页面、日志或数据库导出功能读取密保答案原文;
13. 超级管理员和管理员不得代替用户查看、设置或修改密保答案;
14. 密保连续验证失败必须触发按用户、登录标识、IP 和设备维度的限流与冷却;
15. 密保问题属于低熵恢复凭据,不得单独用于签发密码重置凭据;
16. 本轮启用的自助找回路径必须在密保问答之外,再验证用户预先生成的离线恢复码或预先绑定的 WebAuthn 安全密钥;
17. 外部安全邮箱验证码作为本轮正式恢复路径实现,不与密保问答组合;模块未通过完整安全验收、SMTP 配置无效或功能未显式启用时,该路径必须失败关闭;
18. 用户没有可用离线恢复码且未绑定可用 WebAuthn 安全密钥时,不得仅凭密保问答自助重置密码;可以选择已经验证并已启用的外部安全邮箱验证码路径,或由具备权限的上级角色执行受审计的跨用户重置;
19. 问题与答案均由用户自行设置,但系统必须拒绝空问题、重复问题、过短答案和明显弱答案。
### 16.7 离线恢复码
离线恢复码是管理员和普通用户默认可用的强恢复凭据。超级管理员可以不配置离线恢复码,也不进入离线恢复码生成、提示和 Web 找回流程;超级管理员密码只能通过部署主机运行重置命令后临时开启的专用重置通道修改。恢复码不得作为日常登录密码、长期会话凭据或插件访问凭据。
首次提示要求:
1. 管理员和普通用户首次成功登录后,系统必须在进入主界面的第一时间弹出离线恢复码安全提示;超级管理员不显示该提示;
2. 对功能上线前已经存在的账户,只要尚未生成有效恢复码,也必须在功能上线后的首次成功登录时弹出提示;
3. 弹窗必须说明恢复码的用途、一次性特征、离线保存要求,以及遗失恢复码且未启用 WebAuthn 时无法自助找回密码的风险;
4. 弹窗至少提供“立即生成”和“稍后处理”操作;用户选择“稍后处理”后可以继续使用系统,但在生成并确认已安全保存有效恢复码前,每次新登录会话建立后都必须再次提示;
5. 恢复码生成后,用户必须主动确认“已安全保存”;在确认前,账户安全状态应标记为“恢复码未确认保存”;
6. 用户未确认保存就关闭一次性展示页面时,系统不得再次展示原恢复码;下一次登录必须提示用户前往设置页面重新生成并安全保存;
7. 未生成或未确认保存恢复码时,不得提供“永久不再提醒”或等效的永久关闭选项;
8. 弹窗只负责提示和进入生成流程,不得在未重新确认用户操作时自动生成、下载或打印恢复码;
9. 恢复码弹窗不得影响登录会话安全检查,不得通过弹窗参数、前端路由或浏览器存储泄露恢复码原文。
生成和存储要求:
1. 恢复码必须由密码学安全随机数生成器生成,每个恢复码必须具有足够的随机熵,不能由用户信息、时间、序号或可预测随机数派生;
2. 系统应一次生成一组多个恢复码,并明确显示总数量、一次性使用规则和安全保存说明;
3. 恢复码原文只允许在生成或重新生成成功后展示一次,并提供复制、下载和打印能力;
4. 用户离开一次性展示页面后,任何页面、接口、管理员操作或数据库导出都不得再次返回恢复码原文;
5. 服务端只能保存经过项目统一批准的不可逆校验值、状态和必要元数据,不得保存恢复码明文或可逆密文;
6. 恢复码校验必须绑定不可变用户 ID 和专用用途域,不能跨用户、跨环境或跨用途复用;
7. 每个恢复码只能成功使用一次,验证和标记已使用必须在同一原子事务中完成,避免并发重复消费;
8. 恢复码比较必须使用恒定时间比较或等效防护,接口必须具有账户、登录标识、IP 和设备维度的限流与冷却;
9. 日志、错误信息、指标和审计记录中最多显示恢复码的脱敏标识,不得记录完整恢复码或不可逆校验值;
10. 恢复码生成、下载、打印、使用、重新生成和全部撤销必须写入脱敏安全审计日志。
设置页面要求:
1. 设置页面必须提供“账户安全 → 离线恢复码”入口;
2. 设置页面只能显示是否已生成、是否已确认保存、剩余可用数量、最近生成时间、最近使用时间和安全状态,不得显示历史恢复码原文;
3. 用户可以在设置页面重新生成恢复码或撤销全部恢复码;
4. 重新生成或撤销全部恢复码前必须验证当前密码,并要求当前登录会话处于近期认证状态;
5. 重新生成新恢复码后,全部旧恢复码必须立即失效;
6. 用户剩余恢复码数量低于安全阈值时,系统应在登录后和设置页面提示重新生成;
7. 用户没有可用恢复码但已绑定 WebAuthn 安全密钥时,可以继续使用 WebAuthn 完成自助找回;两种凭据都不可用时,只能联系超级管理员执行受审计的重置。
高风险操作前置要求:
1. 管理员和普通用户必须已经生成恢复码、确认安全保存,并且至少存在一个未使用、未撤销、与当前凭据版本匹配的有效恢复码,才能执行被标记为需要恢复保障的高风险操作;
2. 超级管理员不受离线恢复码前置条件限制;数据库名称迁移和配置回滚仍必须要求超级管理员近期重新认证或完成 WebAuthn 二次确认,并通过能力授权、审计和事务保护;
3. 角色变更时,目标用户为管理员或普通用户的,必须检查目标用户已经配置有效恢复码,避免角色变化后目标账户缺少可用的离线恢复保障;目标用户为超级管理员时不要求恢复码;
4. 恢复码前置检查必须由后端在授权阶段执行,前端隐藏或禁用按钮不能代替后端校验;
5. 管理员、普通用户或适用的目标用户未满足条件时,接口必须拒绝操作并返回稳定错误码,引导对应用户先进入账户安全页面生成或重新生成恢复码;
6. 该前置检查只验证是否存在有效恢复码,不消费恢复码原文,也不得在请求中要求上传恢复码;
7. 恢复码前置条件不能替代近期重新认证、WebAuthn 二次确认、角色能力校验、对象级授权、安全审计或事务保护;
8. 系统必须始终允许管理员和普通用户进入自己的恢复码设置页面完成生成或重新生成,不能因高风险操作被阻止而同时阻断恢复码配置入口;
9. 超级管理员密码恢复不得因为没有离线恢复码而降级为公开 Web 找回,必须使用部署端重置命令开启专用重置通道。
### 16.8 WebAuthn 安全密钥
WebAuthn 安全密钥由用户自行选择是否开启,默认不得替用户自动绑定。未开启 WebAuthn 不得影响正常登录和业务使用,但用户必须理解此时离线恢复码是唯一可用的强恢复凭据。
功能要求:
1. 设置页面必须提供“账户安全 → WebAuthn 安全密钥”入口;
2. 用户可以自行启用、添加、重命名和移除自己的 WebAuthn 安全密钥;
3. 启用或新增安全密钥前必须验证当前密码,并要求当前登录会话处于近期认证状态;
4. 系统应支持同一用户绑定多个安全密钥,并展示用户自定义名称、绑定时间、最近使用时间和状态;
5. 安全密钥私钥必须始终保留在认证器中,服务端只保存 WebAuthn 公开凭据、凭据 ID、签名计数器和验证所需元数据;
6. 注册和验证必须校验一次性 Challenge、Origin、RP ID、凭据归属、用户状态和协议返回结果,Challenge 必须短时有效且使用后立即失效;
7. WebAuthn 凭据必须绑定不可变用户 ID、部署环境和预期 RP ID,不能跨用户、跨站点或跨环境复用;
8. 密码恢复中的 WebAuthn 验证必须要求用户验证能力;部署条件不支持用户验证时,不得将该凭据用于密码恢复;
9. 删除安全密钥前必须重新验证当前密码或使用另一个已绑定且满足用户验证要求的安全密钥;
10. 删除最后一个可用 WebAuthn 安全密钥时,页面必须确认用户仍持有有效离线恢复码;没有有效恢复码时,应先引导生成恢复码,防止用户失去自助恢复能力;
11. WebAuthn 注册、验证、失败、重命名和移除操作必须限流并写入脱敏安全审计日志;
12. 管理员和超级管理员不得读取用户认证器秘密、代替用户注册安全密钥或将自己的安全密钥绑定到其他用户;
13. 超级管理员的公开忘记密码入口仍保持禁用,即使超级管理员自行绑定了 WebAuthn 安全密钥,也不得绕过部署主机本地密码维护流程。
### 16.9 忘记密码流程
本轮启用路径 A:
```text
输入用户名或用户邮箱
→ 返回统一响应
→ 完成人机验证和恢复限流检查
→ 随机展示密保问题
→ 验证密保答案
→ 验证一个未使用的离线恢复码或已绑定的 WebAuthn 安全密钥
→ 签发短时、一次性密码重置凭据
→ 设置新密码
→ 递增会话版本并撤销全部旧会话
→ 记录脱敏审计日志
```
本轮正式实现、完成安全验收后受控启用路径 B:
```text
输入用户名或用户邮箱
→ 返回统一响应
→ 完成人机验证和恢复限流检查
→ 向用户已经验证的外部安全邮箱发送验证码
→ 验证用途、恢复会话、有效期和单次消费状态
→ 签发短时、一次性密码重置凭据
→ 设置新密码
→ 递增会话版本并撤销全部旧会话
→ 记录脱敏审计日志
```
流程要求:
1. 查询账户和提交密保答案时均不得通过状态码、响应时间或提示文本泄露账户是否存在;
2. 路径 A 中,密保答案,以及离线恢复码或 WebAuthn 安全密钥中的一种均验证成功后,不得直接在同一个请求中修改密码,必须签发高强度随机、短时、一次性的重置凭据;
3. 重置凭据必须绑定用户 ID、用途、签发时间和过期时间,使用后立即失效;
4. 重置凭据不得写入日志、URL 查询参数、浏览器长期存储或分析系统;
5. 路径 A 中,密保、离线恢复码和 WebAuthn 安全密钥未设置、被冻结、不可用或验证失败时,不得绕过验证直接重置密码;
6. 外部安全邮箱验证码模块完成并显式启用前,未设置密保,或者离线恢复码与 WebAuthn 安全密钥均不可用的管理员、普通用户,只能联系超级管理员执行受审计的密码重置;
7. 超级管理员账户进入该流程时必须统一拒绝,并引导使用部署主机本地维护方式;
8. 新密码必须通过与正常修改密码相同的强度、长度和泄露密码检查;
9. 重置成功后必须撤销该用户尚未使用的其他重置凭据;
10. 密保验证和密码重置接口必须设置请求体大小限制、CSRF 或等效来源保护、频率限制和并发保护;
11. 使用离线恢复码完成验证时,必须先原子标记该恢复码已使用,再签发密码重置凭据;后续流程失败也不得恢复该恢复码的可用状态;
12. 使用 WebAuthn 完成验证时,必须为本次密码恢复签发独立 Challenge,不得复用登录或安全密钥注册流程中的 Challenge;
13. 页面必须允许用户在离线恢复码和 WebAuthn 安全密钥之间主动选择,不得因为某一种验证失败就自动降级绕过另一种凭据的正常校验;
14. 路径 B 必须是独立验证路径,不得要求用户先回答密保问题,也不得把登录邮箱自动视为外部安全邮箱;
15. 验证码功能关闭、尚未通过安全验收、配置无效或投递失败时,路径 B 必须保持不可用,不得回退为仅邮箱、仅密保或其他弱验证;
16. 两条路径签发的重置凭据必须进入相同的新密码策略、Session 撤销、安全版本更新和审计边界。
### 16.10 邮箱验证码正式实施边界
本轮正式实现外部安全邮箱验证码的配置、数据、服务、SMTP 投递、登录二次验证、密码恢复、管理页面、运营数据和定期清理。验证码任务至少绑定:
- 不可变用户 ID;
- 已验证的外部安全邮箱,不能与登录邮箱概念混用;
- 验证用途;
- 恢复会话;
- 签发时间和有效期;
- 单次消费状态;
- 功能开关和策略版本。
正式接口要求:
1. 功能开关默认关闭,只有验证码模块完整实现、完成安全测试并由超级管理员显式启用后才能开放恢复路由;
2. 接口形状不得让前端绕过恢复状态机直接签发重置凭据;
3. 数字验证码、验证码校验值和完整验证码任务不得进入任何持久化介质,只能保存在签发认证进程的受限内存中;内存校验值使用进程临时 HMAC 密钥,服务重启后全部未完成验证码立即失效;
4. 验证码不得写入日志、审计详情、URL、浏览器长期存储或分析系统;
5. 发送和验证必须具备账户、外部邮箱、IP、设备、恢复会话和用途维度的限流与防重放;
6. 登录邮箱用于账户标识和登录,外部安全邮箱用于独立安全通知与验证码恢复,两者均绑定不可变用户 ID;
7. 超级管理员始终禁止进入公开 Web 找回密码流程,包括外部安全邮箱验证码路径。
---
## 17. 超级管理员配置 API 需求
### 17.1 推荐接口
```text
GET /api/v1/config/status
GET /api/v1/config/{section}
POST /api/v1/config/{section}/validate
PUT /api/v1/config/{section}
POST /api/v1/config/{section}/apply
POST /api/v1/config/test/{target}
GET /api/v1/config/backups
POST /api/v1/config/rollback
GET /api/v1/config/audit
GET /api/v1/config/audit/export
POST /api/v1/config/restart
POST /api/v1/config/database/migration/preview
POST /api/v1/config/database/migration/start
GET /api/v1/config/database/migration/{operationId}
```
允许的 `section`:
```text
base
smtp
email
ssl
plugins
```
### 17.2 通用安全要求
所有超级管理员配置接口必须:
1. 验证登录 Session;
2. 验证超级管理员权限;
3. 验证 CSRF;
4. 限制请求体大小;
5. 严格解析 JSON;
6. 拒绝未知字段;
7. 限制请求频率;
8. 记录审计日志;
9. 对敏感字段脱敏;
10. 使用统一中文错误响应;
11. 不允许通过请求参数指定任意文件路径;
12. 不允许管理员或普通用户访问;
13. 管理员需要的运行状态、健康检查和脱敏信息必须通过独立的运维接口提供,不能复用可修改全局配置的接口。
### 17.3 用户插件设置接口
当前登录用户修改自己的插件设置时使用:
```text
GET /api/v1/plugins/{id}/settings
PUT /api/v1/plugins/{id}/settings
POST /api/v1/plugins/{id}/settings/test
```
用户 ID 必须从当前 Session 获取,不允许信任请求中的任意用户 ID。
管理员和超级管理员跨用户管理时必须使用独立接口:
```text
GET /api/v1/plugins/{id}/users/{userId}
PUT /api/v1/plugins/{id}/users/{userId}
POST /api/v1/plugins/{id}/users/{userId}/test
POST /api/v1/plugins/{id}/users/batch/preview
PUT /api/v1/plugins/{id}/users/batch
```
跨用户接口要求:
1. 普通用户不得访问跨用户接口;
2. 管理员的目标用户只能是普通用户;
3. 超级管理员可以操作所有角色用户,但仍需通过字段校验、资源版本校验和审计;
4. 批量接口只允许超级管理员调用,必须先生成预览结果,再携带短时预览票据、近期重新认证凭据和明确的覆盖策略提交;
5. 批量操作不得使用隐式通配符静默覆盖全部用户,不得默认覆盖用户已经保存的个性化配置;
6. 批量结果必须逐用户返回成功、跳过或失败状态,但不得泄露操作者无权查看的用户信息或敏感字段;
7. 单用户和批量更新都必须使用不可变用户 ID,不能以用户名或邮箱作为更新主键。
### 17.4 超级管理员配置审计接口
配置审计接口只允许超级管理员访问,管理员只能通过独立接口查看职责范围内的脱敏运行事件。审计范围至少包括:
- 基础配置和 `setupState` 变化;
- 数据库名称迁移;
- SMTP 和 Relay 配置;
- 邮箱策略及未来验证码策略;
- SSL 上传、续期、切换和回滚;
- 插件启停、重启、全局配置、用户批量配置和网络白名单;
- 配置备份、恢复和回滚;
- 受控应用重启;
- 角色和安全策略;
- 超级管理员重置用户密码;
- WebAuthn、恢复码、恢复流程和 Session 撤销。
接口返回至少包含时间、操作编号、操作者用户名、操作者不可变 ID、角色、脱敏来源 IP、截断 Session 标识、配置分区、目标、结果、配置代次、是否需要重启、是否已经重启和脱敏差异摘要。
Secret 差异只能显示“已设置”“已修改”“已清除”,不得展示密码、Token、密文、哈希、恢复码、密保答案、SSL 私钥或 WebAuthn 私有材料。CSV 或 JSON 导出必须脱敏,导出行为本身也必须写入审计。
---
## 18. 管理页面需求
### 18.1 页面结构
管理员设置页面建议分为:
```text
系统状态
基础设置
SMTP 设置
邮箱策略
SSL 设置
插件管理
配置审计
```
### 18.2 通用交互要求
1. 所有显示文字使用中文,确需保留的协议名和产品名除外;
2. Secret 字段默认显示“已配置”或“未配置”;
3. Secret 不允许通过查看按钮读取服务器中的原文;
4. 保存前进行前端基础校验;
5. 后端必须重新执行完整校验;
6. 需要重启的配置必须明确提示;
7. 保存失败不得清空用户输入的非敏感字段;
8. 配置已经被其他操作修改时提示刷新;
9. 测试连接按钮必须显示测试范围和结果;
10. 危险配置修改需要二次确认;
11. 页面不得展示数据库完整 DSN、SMTP 密码和插件 Token;
12. 页面需要显示当前配置代次和最近更新时间。
13. 需要重启时,页面提供明确的“重启 Smail”按钮;点击后调用受控服务管理器,不得由 Web 进程执行任意命令;
14. 数据库名称迁移页面必须先展示预览、源和目标摘要、预计影响、维护模式提示和回退条件;
15. SSL 页面只提供默认受控目录和自定义上传托管两种选择,不提供服务器路径输入框。
### 18.3 插件页面
插件页面至少显示:
- 插件名称;
- 插件逻辑 ID;
- 当前版本;
- 启用状态;
- 运行状态;
- 健康状态;
- 网络权限;
- 全局配置;
- Secret 是否已设置;
- 测试连接;
- 重启插件;
- 最近一次错误。
### 18.4 账户安全页面
管理员和普通用户的个人设置必须提供“账户安全”页面,至少包含:
```text
登录密码
密保问题
离线恢复码
WebAuthn 安全密钥
登录会话
```
页面要求:
1. 离线恢复码入口必须始终可见,并展示是否已生成、剩余可用数量和风险状态;
2. WebAuthn 安全密钥入口必须始终可见,但是否启用和绑定由用户自行决定;
3. 页面不得展示密保答案、恢复码历史原文、WebAuthn 私钥或完整凭据标识;
4. 生成恢复码、重新生成恢复码、撤销恢复码、绑定安全密钥和移除安全密钥必须使用独立确认流程;
5. 一次性展示恢复码时,应要求用户确认已经复制、下载或打印,并明确说明离开后无法再次查看;
6. 用户直接关闭恢复码一次性展示页面时,系统不得再次返回同一组原文,必须保留“未确认保存”状态,并在下一次登录时引导用户重新生成;
7. 账户安全页面及首次登录弹窗必须在桌面端和移动端完整可用,不得因页面滚动、遮挡或弹窗关闭异常导致用户无法保存恢复码;
8. 所有安全状态均由后端返回,前端不得根据本地存储自行判断恢复码或 WebAuthn 是否可用。
### 18.5 超级管理员配置审计页面
页面采用推荐的完整审计视图,后续可以按实际运维需求调整。页面必须:
1. 支持按时间、操作者、角色、配置分区、事件类型、结果和操作编号筛选;
2. 展示操作者、目标、配置代次、重启状态和脱敏差异摘要;
3. 对 Secret 仅显示“已设置”“已修改”“已清除”;
4. 支持脱敏 CSV 和 JSON 导出,并对导出操作再次审计;
5. 审计记录至少保留 365 天并采用追加写入;
6. 普通管理员不能删除审计记录,超级管理员也不能通过普通 Web API 删除单条记录;
7. 配置回滚前先展示预览并要求近期重新认证,回滚生成新配置代次,不能覆盖历史记录;
8. 密码、角色、已消费恢复码、已撤销 WebAuthn 凭据和已经执行的数据库写入不得提供一键回滚。
---
## 19. 配置生效方式
### 19.1 生效类型
API 必须返回以下一种生效方式:
```text
immediate
service_restart
application_restart
pending
```
含义:
| 类型 | 含义 |
|---|---|
| `immediate` | 已立即生效 |
| `service_restart` | 需要重启相关服务或插件 |
| `application_restart` | 需要重启整个 Smail |
| `pending` | 已保存为候选配置,尚未正式应用 |
### 19.2 建议分类
| 配置 | 生效方式 |
|---|---|
| 日志级别 | 立即生效 |
| 垃圾邮件过滤等级 | 立即生效 |
| 邮箱验证码策略 | 立即生效 |
| 插件普通设置 | 插件重新配置或重启 |
| 插件启停 | 插件启动或停止 |
| SMTP Relay 模式 | 重启发送模块或应用 |
| SSL 证书 | 重启 HTTPS 服务 |
| HTTP、HTTPS 端口 | 重启应用 |
| 主域名 | 重启应用并重新检查 SSL、DKIM |
| 数据库配置 | 候选配置加应用重启 |
### 19.3 受控重启
需要重启时,由超级管理员在页面点击重启按钮,后端向受控服务管理器提交一次性重启请求。受控重启必须:
1. 要求超级管理员权限、CSRF、防重放和近期重新认证;
2. 只允许固定的 Smail 服务或已授权插件实例,不接受命令、参数、脚本或任意服务名;
3. 先确认候选配置已经完整验证并持久化;
4. 返回操作编号并允许页面查询停止、启动、健康检查和回退结果;
5. Windows 使用受控 Windows Service,Ubuntu 使用受控 systemd 服务;
6. 重启失败时保留旧有效配置或执行明确回退,不得循环重启;
7. 请求、执行者、目标、配置代次和结果全部写入审计。
---
## 20. 数据库配置修改需求
数据库配置属于高风险配置。初始化继续支持 MySQL、PostgreSQL 和 SQLite;其中 MySQL、PostgreSQL 使用结构化字段,SQLite 使用独立本地模式。
初始化要求:
1. 页面提供数据库类型下拉选择;
2. MySQL 和 PostgreSQL 默认填写主机地址、用户名和密码,端口按类型自动填写并允许在高级设置修改;
3. 数据库名称和全部表结构由系统自动创建;
4. SQLite 不显示网络连接字段,数据库文件位置由后端在受控数据目录内生成;
5. 初始化前测试服务器连接、账户权限、数据库版本和创建数据库能力;
6. 数据库密码加密保存,日志和 API 不输出密码、密文或后端生成的完整 DSN。
超级管理员在线修改仅限数据库名称,并必须满足:
1. 只有超级管理员可以操作,要求近期重新认证和二次确认;
2. 仅允许同一数据库类型、服务器、端口和账户内迁移,不能借此修改主机、端口、用户名、密码或 SQLite 文件位置;
3. 先生成迁移预览并进入维护模式,暂停业务写入;
4. 在同一服务器创建目标数据库和完整表结构;
5. 分批复制旧数据库业务数据,并保存可恢复进度;
6. 对记录数量、关键索引、约束和业务摘要执行一致性校验;
7. 校验成功后原子切换结构化配置中的数据库名称,再通过受控服务管理器重启;
8. 任一步失败都继续使用旧数据库,目标数据库保留为失败现场但不得被业务使用;
9. 旧数据库数据必须保留,系统不得自动删除或覆盖;
10. 全流程记录操作者、源和目标数据库脱敏标识、操作编号、阶段、结果和配置代次;
11. SQLite 数据库名称迁移不纳入在线修改入口;需要变更本地文件时作为独立离线维护任务处理。
---
## 21. 插件运行配置需求
### 21.1 插件配置下发
插件启动流程:
```text
读取 plugins.json
→ 校验插件配置
→ 校验可执行文件
→ 创建插件沙箱
→ 启动插件
→ 等待通信端点
→ 获取插件能力
→ 验证配置
→ 下发当前插件配置
→ 执行健康检查
→ 注册邮件 Hook
```
### 21.2 推荐插件能力
```go
type PluginCapabilities struct {
Configurable bool `json:"configurable"`
UserSettings bool `json:"userSettings"`
Network bool `json:"network"`
HealthCheck bool `json:"healthCheck"`
}
```
### 21.3 推荐插件端点
```text
/Capabilities
/ValidateConfig
/Configure
/Health
```
### 21.4 插件隔离要求
1. 插件只获得自己的配置;
2. 不将完整 `plugins.json` 复制到插件沙箱;
3. 不将 `config.json` 复制到插件沙箱;
4. 不向插件提供数据库 DSN;
5. 网络默认拒绝;
6. 网络权限按插件授权;
7. 插件退出后必须注销 Hook;
8. 插件配置失败时必须停止插件;
9. 一个插件失败不得影响其他插件和主程序;
10. 生产环境必须执行文件权限、所有者和沙箱检查。
---
## 22. 配置迁移需求
### 22.1 迁移来源
旧 `config.json` 中以下内容需要迁移:
| 旧配置 | 新位置 |
|---|---|
| 数据库、域名、端口、日志 | `config.json` |
| `dkimPrivateKeyPath` | `smtp.json` |
| `spamFilterLevel` | `smtp.json` |
| SSL 类型和证书路径 | `ssl.json` |
| 微信推送配置 | `plugins.json` |
| Telegram 全局配置 | `plugins.json` |
| Web Push 配置 | `plugins.json` 或对应独立插件配置 |
| `pluginAllowList` | `plugins.json` 中的 `enabled` |
| `isInit` | `setupState` |
### 22.2 迁移原则
1. 迁移前备份旧配置;
2. 迁移过程必须可重复执行;
3. 迁移失败不得覆盖旧配置;
4. 新配置完整校验通过后才切换;
5. 敏感字段迁移后必须使用当前凭据机制加密;
6. 不继续引入旧的弱加密算法;
7. 迁移日志不得包含敏感字段;
8. 迁移成功后记录配置版本;
9. 未知旧字段必须报告,不应静默丢弃;
10. 是否删除旧配置文件需要单独获得用户许可。
---
## 23. 审计日志需求
需要记录:
- 操作管理员;
- 操作时间;
- 来源 IP;
- 配置分区;
- 变更字段名称;
- 旧配置代次;
- 新配置代次;
- 验证结果;
- 应用结果;
- 是否需要重启。
不得记录:
- 数据库密码;
- 数据库完整 DSN;
- SMTP 密码;
- Bot Token;
- 微信 Secret;
- 验证码签名密钥;
- SSL 私钥;
- Session Cookie;
- CSRF Token。
---
## 24. 错误处理需求
### 24.1 启动错误
| 错误 | 处理方式 |
|---|---|
| 主入口不存在 | 进入初始化模式 |
| 主入口损坏 | 进入安全恢复或终止启动 |
| 数据库配置无效 | 不启动正式服务 |
| SMTP 配置损坏 | 不启动邮件服务,进入降级模式 |
| SSL 配置损坏 | 不启动 HTTPS,禁止不安全远程管理回退 |
| 插件配置损坏 | 禁用插件,不影响核心服务 |
| 单个插件启动失败 | 禁用该插件,其他服务继续运行 |
### 24.2 管理 API 错误
错误信息应当:
- 使用中文;
- 能指出配置区和字段类型;
- 不返回内部文件绝对路径;
- 不返回敏感字段;
- 不返回数据库或第三方服务的完整底层错误;
- 在服务器日志中记录脱敏后的详细信息。
---
## 25. 性能和可靠性需求
1. 配置读取主要发生在启动和更新时,不允许每次业务请求都读取磁盘;
2. 运行时读取应使用内存快照;
3. 配置更新不得长时间阻塞邮件处理;
4. 外部连接测试必须有超时;
5. 插件健康检查不得阻塞主程序启动过久;
6. 配置文件必须采用原子写入;
7. 配置目录和文件必须具有安全权限;
8. 服务异常退出后不得留下被误认为正式配置的临时文件;
9. 配置损坏时应优先恢复最近有效配置;
10. 不允许因为可选插件配置损坏导致数据库和管理后台不可用。
---
## 26. 兼容性需求
1. 支持 Windows 开发模式;
2. 支持 Ubuntu 22.04;
3. 支持 Ubuntu 24.04;
4. 配置文件统一使用 UTF-8 无 BOM;
5. 路径处理使用跨平台安全方法;
6. Windows 和 Linux 使用相同插件逻辑 ID;
7. Windows 可执行文件扩展名不得进入业务配置 ID;
8. 不依赖 Docker;
9. 不要求生产系统安装额外脚本解释器;
10. 配置迁移不得破坏当前支持的 MySQL、PostgreSQL 和 SQLite。
---
## 27. 测试需求
### 27.1 配置加载测试
- 主入口正常加载;
- 分区配置正常加载;
- 缺少可选配置时使用安全行为;
- 缺少必需配置时拒绝启动正式服务;
- 未知字段被拒绝;
- 重复字段被拒绝;
- 超大配置被拒绝;
- 非法配置版本被拒绝;
- 配置路径穿越被拒绝;
- 符号链接配置文件被拒绝。
### 27.2 敏感信息测试
- 数据库凭据不以明文落盘;
- SMTP 密码不以明文落盘;
- 插件 Secret 不以明文落盘;
- API 不返回 Secret;
- 日志不包含 Secret;
- 密文篡改后配置加载失败;
- Secret 保留、更新和清除行为正确。
### 27.3 更新和回滚测试
- 配置保存成功后代次递增;
- 旧代次请求不能覆盖新配置;
- 校验失败不写入文件;
- 写入失败不修改内存配置;
- 应用失败恢复旧配置;
- 重启后配置与运行时一致;
- 并发保存不会损坏配置文件。
### 27.4 初始化状态测试
- `new` 只启动初始化服务;
- `bootstrap` 只启动安全管理服务;
- `ready` 启动完整服务;
- `degraded` 不启动存在风险的邮件服务;
- 非法状态拒绝启动;
- 状态转换必须通过完整校验。
### 27.5 插件测试
- 禁用插件不启动;
- 插件只获得自己的配置;
- 插件无法读取数据库 DSN;
- 插件无法读取其他插件 Secret;
- 插件配置错误不注册 Hook;
- 单个插件失败不影响其他插件;
- 插件网络权限按插件生效;
- Telegram 用户设置只能由当前用户访问;
- 超级管理员可以启用、禁用插件和修改插件全局配置;
- 超级管理员可以修改所有用户的用户级插件配置;
- 管理员只能修改普通用户的用户级插件配置;
- 普通用户只能修改自己的用户级插件配置;
- 管理员访问超级管理员或其他管理员插件配置时被拒绝;
- 跨用户插件配置修改产生完整且脱敏的审计记录。
### 27.6 登录和密码恢复测试
- 用户名和完整用户邮箱均能登录到同一个用户 ID 和角色;
- 未绑定邮箱、禁用邮箱、冲突邮箱和未授权别名不能登录;
- 不能通过伪造域名或简单删除邮箱域名绕过账户匹配;
- 用户名和邮箱交替登录不能绕过账户级限流;
- 登录失败和找回密码响应不泄露账户是否存在;
- 超级管理员不能使用公开的忘记密码流程;
- 超级管理员本地密码维护接口默认关闭且不能从公共网络访问;
- 超级管理员本地维护凭据短时、一次性并在成功后失效;
- 设置和修改密保问题时必须验证当前密码;
- 密保问题加密落盘,密保答案只保存不可逆哈希;
- 每条密保答案使用独立随机盐和统一批准的算法参数;
- 密保失败触发用户、登录标识、IP 和设备维度限流;
- 仅密保问答验证成功时不能签发密码重置凭据;
- 密保问答和离线恢复码均验证成功后才能签发短时一次性重置凭据;
- 密保问答和 WebAuthn 安全密钥均验证成功后才能签发短时一次性重置凭据;
- TOTP 和未纳入需求的其他恢复方式不能被注册或用于密码恢复;
- 未生成有效恢复码的管理员和普通用户首次登录后立即看到安全提示;
- 用户选择“稍后处理”后仍可进入系统,但下一次新登录会话建立后会再次提示;
- 用户生成恢复码但未确认保存就关闭页面时,下一次登录会收到重新生成提示;
- 生成恢复码并确认已经安全保存后不再显示首次提示,剩余数量低于阈值时显示补充提醒;
- 恢复码原文只展示一次,设置页面无法再次读取历史原文;
- 恢复码服务端仅保存不可逆校验值,日志和审计中不包含完整恢复码;
- 恢复码不能跨用户、跨环境或跨用途使用;
- 同一恢复码并发提交时最多只有一次成功,使用后不能再次使用;
- 重新生成恢复码后全部旧恢复码立即失效;
- 设置页面可以查看恢复码状态、剩余数量并执行重新生成或全部撤销;
- WebAuthn 默认不启用,用户不绑定安全密钥时仍能正常登录和使用系统;
- 用户可以在设置页面绑定多个、重命名和移除自己的 WebAuthn 安全密钥;
- WebAuthn 注册和恢复验证会拒绝错误 Challenge、Origin、RP ID、用户归属和过期请求;
- WebAuthn 私钥不会发送或保存到服务端;
- WebAuthn 凭据不能跨用户、跨站点或跨环境复用;
- 没有有效恢复码时,移除最后一个可用 WebAuthn 安全密钥会被阻止并引导生成恢复码;
- 超级管理员不能代替其他用户注册 WebAuthn 安全密钥;
- 重置凭据不能重复使用、不能跨用户使用且过期后失效;
- 密码重置后所有旧会话和其他重置凭据失效;
- 超级管理员可以重置管理员和普通用户密码;
- 管理员可以重置普通用户密码,但不能重置管理员或超级管理员;
- 普通用户只能修改或恢复自己的密码;
- 用户名或主邮箱变更后,进行中的密码恢复流程失效;
- 日志和审计记录不包含密码、密保答案或完整重置凭据。
---
## 28. 验收标准
### 28.1 配置结构
- [ ] `config.json` 成为唯一主入口;
- [ ] SMTP、邮箱、SSL、插件配置完成拆分;
- [ ] 数据库主模型使用结构化字段,支持 MySQL、PostgreSQL 和 SQLite;
- [ ] 业务模块不直接读取配置文件;
- [ ] 插件不直接读取主配置;
- [ ] 配置具有明确版本和代次;
- [ ] 未知字段不会被静默忽略。
### 28.2 初始化和启动
- [ ] 初始化流程可以自动建立数据库、表结构、第一个超级管理员、主域名和 SSL;
- [ ] 引导模式不会启动未配置的邮件服务;
- [ ] 超级管理员可以安全登录并继续配置;
- [ ] 完整预检通过后才能进入正式运行状态;
- [ ] 配置损坏时可以进入可恢复状态。
### 28.3 安全
- [ ] 所有敏感凭据均加密落盘;
- [ ] 所有全局配置接口均验证超级管理员权限和 CSRF;
- [ ] API 和日志不泄露敏感字段;
- [ ] 数据库配置修改具有测试和回退机制;
- [ ] 配置文件权限和符号链接检查通过;
- [ ] 插件不能访问主数据库凭据;
- [ ] 超级管理员可以管理插件启用状态、全局配置和所有用户插件配置;
- [ ] 管理员只能操作普通用户的用户级插件配置;
- [ ] 普通用户只能操作自己的用户级插件设置;
- [ ] 用户名和完整用户邮箱均可安全登录,且不能绕过统一限流;
- [ ] 超级管理员密码只能通过部署主机本地维护接口修改;
- [ ] 本轮启用的路径要求管理员和普通用户完成密保问答,以及离线恢复码或 WebAuthn 安全密钥中的一种验证后才能自助找回密码;
- [ ] 仅凭密保问题与答案不能签发密码重置凭据;
- [ ] 密保答案不以明文或可逆密文保存;
- [ ] 未生成有效恢复码的管理员和普通用户在首次登录后立即收到弹窗提示,选择稍后处理后下次登录继续提示;
- [ ] 恢复码未确认保存时保持风险状态,下一次登录继续提示并引导重新生成;
- [ ] 管理员或普通用户未配置有效恢复码时,后端拒绝其执行需要恢复保障的高风险操作;角色变更时检查适用的目标用户;超级管理员明确豁免恢复码前置条件;
- [ ] 设置页面提供离线恢复码入口,并且只能查看状态、剩余数量及管理操作,不能再次读取历史恢复码原文;
- [ ] 离线恢复码只展示一次、一次性使用、不可逆保存,重新生成后旧恢复码全部失效;
- [ ] WebAuthn 安全密钥由用户自行选择是否开启,未开启时不影响正常登录和业务使用;
- [ ] WebAuthn 注册和验证完整校验 Challenge、Origin、RP ID、用户归属和用户验证结果;
- [ ] TOTP 和未明确纳入需求的其他恢复方式不能用于自助找回密码;
- [ ] 密码重置后旧会话和重置凭据全部失效。
- [ ] 外部安全邮箱验证码恢复接口默认关闭,未通过安全验收或未启用时不能绕过现有恢复验证;
- [ ] 超级管理员重置用户密码后,目标用户旧 WebAuthn、恢复码、Session 和恢复票据全部撤销;
- [ ] 插件网络目标白名单默认拒绝未授权主机、端口和协议;
- [ ] 插件 Secret 加密存入数据库,插件不能访问主配置和主数据库;
### 28.4 配置应用
- [ ] 每项配置明确立即生效或需要重启;
- [ ] 配置保存失败不会修改运行状态;
- [ ] 配置应用失败可以恢复;
- [ ] 配置代次可以阻止并发覆盖;
- [ ] 管理页面能够显示配置状态和应用结果。
- [ ] 超级管理员可以通过固定目标的受控服务管理器执行重启;
- [ ] 配置审计页面显示脱敏差异、操作者、结果、重启和回滚记录;
- [ ] 数据库名称迁移失败时继续使用旧数据库,且旧数据库数据保留。
### 28.5 平台兼容
- [ ] Windows 开发模式验证通过;
- [ ] Ubuntu 22.04 验证通过;
- [ ] Ubuntu 24.04 验证通过;
- [ ] MySQL 验证通过;
- [ ] PostgreSQL 验证通过;
- [ ] SQLite 验证通过。
---
## 29. 建议实施阶段
### 第一阶段:需求和安全边界确认
- 复审已确认的初始化方案;
- 复审主入口和结构化数据库模型;
- 复审分区配置结构;
- 复审敏感字段和插件数据库 Secret 边界;
- 复审受控重启和数据库名称迁移边界;
- 移除需求文档中的真实凭据。
### 第二阶段:统一配置管理器
- 实现主入口加载;
- 实现分区配置加载;
- 实现严格解析;
- 实现内存快照;
- 实现原子保存;
- 实现凭据保护;
- 实现配置代次。
### 第三阶段:拆分 SSL 和插件配置
- 迁移 SSL 配置并实现默认目录与自定义上传托管双模式;
- 迁移插件配置;
- 改造插件启动流程;
- 实现插件配置 RPC;
- 实现插件级网络权限和目标主机强制白名单;
- 实现超级管理员、管理员和普通用户的插件配置权限;
- 实现跨用户插件配置变更审计。
### 第四阶段:拆分 SMTP 配置
- 迁移垃圾邮件和 DKIM 配置;
- 定义 SMTP Relay 模型;
- 实现 SMTP Relay 测试和应用;
- 完成密码保护。
### 第五阶段:拆分邮箱策略配置
- 实现邮箱策略模型;
- 实现超级管理员配置页面;
- 实现外部安全邮箱验证码配置、仅内存验证码服务、SMTP 投递、登录二次验证和密码恢复;
- 实现外部安全邮箱管理页面、非敏感运营数据、默认关闭的功能开关和每 14 天定期清理。
### 第六阶段:分级管理页面
- 超级管理员基础设置;
- 超级管理员 SMTP、邮箱策略和 SSL 设置;
- 超级管理员插件全局管理和跨用户插件配置;
- 管理员普通用户管理和普通用户插件配置;
- 普通用户个人插件设置;
- 管理员和普通用户账户安全页面;
- 登录后离线恢复码首次提示弹窗;
- 分角色配置状态和审计展示。
- 超级管理员配置审计完整页面;
- 数据库名称迁移预览和进度页面;
- 受控重启按钮和状态反馈。
### 第七阶段:认证和初始化流程
- 将 `is_admin` 迁移为明确的三级角色;
- 实现用户名和完整用户邮箱登录;
- 实现密保问题、密保答案和一次性密码重置凭据;
- 实现离线恢复码生成、一次性展示、不可逆保存、单次消费、重新生成和撤销;
- 实现用户自选启用的 WebAuthn 安全密钥注册、管理和恢复验证;
- 实现密保问答与离线恢复码或 WebAuthn 安全密钥的统一恢复流程;
- 实现外部安全邮箱验证码独立恢复分支;该分支默认关闭,完整功能和安全验收通过后由超级管理员受控启用,且不得弱化现有路径;
- 实现超级管理员部署主机本地密码维护接口;
- 引入配置状态机;
- 缩减初始化页面;
- 增加安全引导管理模式;
- 完成完整启动预检。
### 第八阶段:完整安全复审
- 配置安全测试;
- 插件隔离测试;
- 管理权限测试;
- 登录标识冲突和限流绕过测试;
- 密保答案存储和密码恢复测试;
- 离线恢复码首次提示、单次展示、并发消费和重新生成失效测试;
- WebAuthn Challenge、Origin、RP ID、用户归属和用户验证测试;
- 外部安全邮箱验证码功能关闭、未通过安全验收和投递失败时的降级绕过测试;
- 超级管理员重置后 WebAuthn、恢复码、Session 和恢复票据撤销测试;
- 数据库名称迁移一致性、失败回退和旧数据保留测试;
- 配置审计脱敏、导出、回滚和受控重启测试;
- 超级管理员本地维护接口暴露检查;
- 敏感信息泄露检查;
- 配置回滚验证;
- 跨平台验证。
---
## 30. 产品决定
### 30.1 已确认决定
1. 初始化阶段继续配置主域名和 SSL;
2. 使用 `setupState` 替代 `isInit`;
3. 数据库使用结构化字段,继续支持 MySQL、PostgreSQL 和 SQLite;
4. 初始化只要求必要连接字段,数据库名称和表由系统自动创建;
5. 仅超级管理员可以在线修改数据库名称,并采用维护模式、数据复制、一致性校验、原子切换和失败回退;
6. SMTP Relay 纳入本轮;
7. 外部安全邮箱验证码本轮完整实现,包含验证码服务、SMTP 投递、登录邮箱二次验证、外部邮箱密码恢复、外部邮箱管理页面、运营数据和定期清理;功能开关仅用于验收后的受控启停;
8. SSL 使用默认受控目录和自定义上传后托管双模式;
9. 插件逻辑 ID 与可执行文件名分离,Telegram 用户设置保存在数据库;
10. 插件网络首版实施目标主机、端口和协议强制白名单;
11. 插件关键信息加密存入数据库,主加密密钥不与密文存放在同一数据库;
12. 配置备份每 7 天一次,最长保留 30 天,最多 4 份,并始终保留至少一个有效版本;
13. 提供超级管理员配置审计页面,采用本需求第 17.4 和 18.5 节推荐范围;
14. SSL 成功前初始化范围允许 HTTP,SSL 成功后生产环境强制 HTTPS;
15. Web Push 作为插件能力管理;
16. 需要重启时由超级管理员点击按钮,通过受控服务管理器自动重启;
17. 密保答案大小写不敏感,使用固定规范化、Argon2id、独立随机盐和版本参数校验;
18. 超级管理员重置用户密码后撤销旧 WebAuthn、恢复码、Session 和恢复票据,并要求用户重新生成和绑定安全凭据;
19. 管理员和普通用户未配置有效离线恢复码时,禁止其执行需要恢复保障的高风险操作;角色变更时检查适用的目标用户;超级管理员可以不配置恢复码,数据库名称迁移和配置回滚改用近期重新认证或 WebAuthn 二次确认保护;
20. 超级管理员密码只能通过部署端 `systemctl start smail-admin` 启动短时一次性服务,经受保护本机 IPC 完成重置;该程序、systemd 安全交互、平台适配器和安全测试均属于本轮正式实施范围,未完成前不得最终验收。
### 30.2 高风险操作的恢复码前置条件
1. 超级管理员可以不配置离线恢复码,不显示恢复码提示,也不能使用恢复码或任何公开 Web 流程找回密码;
2. 数据库名称迁移和配置回滚不要求超级管理员配置恢复码,但必须要求近期重新认证或 WebAuthn 二次确认,并继续执行能力授权、审计和事务保护;
3. 管理员和普通用户执行被标记为需要恢复保障的高风险操作时,必须已经配置有效恢复码;角色变更时,目标用户为管理员或普通用户的,也必须已经配置有效恢复码;
4. 有效状态至少包括已经确认安全保存、存在未使用且未撤销的恢复码,并与当前凭据版本一致;
5. 检查只验证恢复能力是否已经建立,不消费恢复码,也不允许使用恢复码替代近期重新认证或 WebAuthn 二次确认;
6. 不满足条件时必须拒绝适用的高风险操作,但仍允许管理员和普通用户进入自己的账户安全页面生成或重新生成恢复码;
7. 超级管理员需要重置自己的密码时,必须在部署主机运行固定重置命令,由命令通过受保护本机 IPC 开启短时、一次性的专用重置通道;
8. 专用重置通道必须正式实现,不得用普通 Web API 临时代替;Linux 固定使用 `systemctl start smail-admin`,通过 `systemd-ask-password` 或等效安全机制获取不回显的新密码,并经 Unix Domain Socket 调用主程序;Windows 使用等价服务启动语义和 Named Pipe;任一平台未完成验证前不得通过最终验收。
---
## 31. 评审记录
| 日期 | 评审人 | 结论 | 修改说明 |
|---|---|---|---|
| 2026-08-25 | 待填写 | 草案 | 创建初始需求文档 |
| 2026-08-25 | 待填写 | 草案优化 | 增加三级角色插件权限、双标识登录、密保找回和分角色密码重置要求 |
| 2026-08-25 | 待填写 | 草案优化 | 强恢复凭据统一为离线恢复码和 WebAuthn,增加首次登录提示、账户安全入口及用户自选启用要求 |
| 2026-08-25 | 待填写 | 草案优化 | 明确超级管理员仅能通过本地通道改密,拆分本人、跨用户和批量插件设置接口 |
| 2026-08-25 | 项目负责人(对话确认) | 产品决定确认 | 确认结构化三数据库、SSL 双模式、配置备份、外部邮箱验证码初始规划、完整审计页面、受控重启及超级管理员重置后的安全凭据撤销边界;验证码范围随后修订为本轮完整实施 |
| 2026-08-25 | 项目负责人(对话确认) | 产品决定全部确认 | 确认管理员和普通用户的恢复码前置条件,并明确超级管理员豁免恢复码、仅通过部署端命令开启专用重置通道 |
| 2026-08-25 | 项目负责人(对话确认) | 产品决定修订 | 将完整邮箱验证码纳入本轮正式开发,统一 `systemctl start smail-admin`,并确认超级管理员、管理员和普通用户的密码重置权限矩阵 |
| 2026-08-25 | 文档复审 | 技术复审通过 | 关闭完整验证码范围、正式命令、角色矩阵、跨文档依赖和统一密码服务依赖顺序问题 |
---
## 32. 最终确认
完成需求优化后,需要至少确认以下结果:
- [x] 配置主入口结构确认;
- [x] 配置分区结构确认;
- [x] 初始化范围确认;
- [x] 配置状态机确认;
- [x] 敏感字段清单确认;
- [x] 配置生效方式确认;
- [x] 超级管理员、管理员和普通用户权限边界确认;
- [x] 插件全局配置和用户配置边界确认;
- [x] 用户名和完整用户邮箱登录规则确认;
- [x] 超级管理员部署主机本地密码维护方式确认;
- [x] 管理员和普通用户密保问答与离线恢复码或 WebAuthn 安全密钥组合流程确认;
- [x] 离线恢复码首次登录弹窗、设置入口、单次展示和单次使用规则确认;
- [x] WebAuthn 安全密钥由用户自行选择是否开启的规则确认;
- [x] SMTP Relay 开发范围确认;
- [x] 外部安全邮箱验证码完整服务、SMTP 投递、登录二次验证、外部邮箱恢复、管理页面、运营数据和定期清理范围确认;
- [x] 迁移和回退策略确认;
- [x] 验收标准确认;
- [x] 管理员和普通用户未配置有效离线恢复码时禁止适用的高风险操作,超级管理员明确豁免;
- [x] 超级管理员部署端正式入口固定为 `systemctl start smail-admin`,短时服务、安全凭据交互、本机 IPC 和跨平台测试均列为最终验收阻塞项;
- [x] 密码重置权限矩阵确认:超级管理员重置管理员和普通用户,管理员重置普通用户,普通用户仅重置本人。
产品决定和技术复审已经通过。后续按照 `docs/配置系统重构实施任务清单.md` 的 CG 父任务和 `docs/超级管理员重置与邮箱验证码实施任务清单.md` 的 AD 子任务进入编码、安全测试和分阶段复审;文档评审通过不代表编码任务已经完成。