22 KiB
远程服务器测试记录
范围
2026 年 9 月 16 日,用户指定在 47.108.78.12 测试,并授权清理测试数据库。远程部署目录为 /opt/smail,服务为 smail.service,网页为 https://mail.solit.cn/。
本轮应用运行、自动测试二进制执行和业务验收均针对远程服务器。本机只进行源码操作、编译、SSH 连接和远程网页浏览;没有启动本机 Smail 或本机开发服务器。此前《清库部署测试记录》的本机结果属于历史记录,不作为本轮远程通过依据。
任务状态
- [✓] 批量已读事务原子性修复已编译为 Linux amd64,并部署到 47 服务器;服务版本指纹和二进制摘要核对通过。
- [✓] 批量已读部署前完成主程序及两份 SQLite 备份,备份数据库完整性校验通过;部署过程中未清理账号、配置或历史邮件。
- [!] 批量已读网页实机登录受测试账号密码已失效阻塞;未通过数据库改密或其他方式绕过登录边界。代码自动测试已覆盖混合归属拒绝、更新失败回滚、重复 ID 和非法 ID。
- [✓] 新部署版本在远程
127.0.0.1:25完成内部 SMTP 回归,五项用例均完成真实 SQLite 归属核对。 - [✓] 核实仅使用两份 SQLite,备份校验后清空数据库对象,保留数据库文件及 inode。
- [✓] 清库后通过独立浏览器上下文完成首次安装、超级管理员登录与安全引导确认。
- [✓] 修复首次安装完成后未生成分区配置,实际生成五份配置文件,配置管理页面可正常读取。
- [✓] 重启远程服务后,无缓存刷新仍保持登录,已确认的安全引导不重复出现。
- [✓] 浏览器创建普通用户,普通用户可登录;密码长度不符时返回中文错误。
- [✓] 修复收件人、抄送、密送输入后直接回车未选中候选的问题,远程浏览器逐项复测通过。
- [✓] 主界面使用中文组件语言,空列表、关闭对话框、关闭标签、数值按钮均有实际页面证据。
- [✓] 配置、安装及管理员恢复相关 Linux 测试包在远程执行通过。
- [✓] 恢复 socket 为
smail:smail 0600;非授权服务账号直接运行恢复工具被拒绝。 - [✓] 内部 25 端口真实收信、中文正文、多收件人、中文附件及下载内容通过。
- [✓] 普通用户不能读取管理员专属邮件或下载其真实附件。
- [!] 网页按 MX 路由的实际投递未通过:网络连接与证书信任阻塞,未绕过校验;按最新要求不再要求公网 25 端口连通。
- [✓] 修复异步发信提前显示成功:网页提交显示正在投递,列表先显示待投递,手动刷新后显示实际失败。
- [✓] 修复 587 端口误用隐式 TLS,远程 STARTTLS 已进入证书校验阶段。
- [!] 当前仍使用原有定时与手动刷新机制;快速状态轮询、进程中断后的待投递恢复未验收。
- [!] 正式
systemctl start smail-admin密码代理交互、新密码登录及旧会话失效闭环未完成。 - [!] 外部邮箱验证码恢复未完成,需要确定实际可接收验证码的测试邮箱。
- [!] 受信任 TLS、移动端及全部业务模块验收未完成。
已部署修复
3ae8ecb 修复批量已读事务原子性:批量 ID 去重并校验,事务内先确认全部邮件属于当前用户,任一邮件不属于当前用户或任一更新失败时整批拒绝并回滚;新增混合归属、更新失败回滚、重复 ID 和非法 ID 自动测试。
2026 年 9 月 17 日 00:34,47 服务器部署该提交对应的 Linux amd64 主程序。源码指纹为 fd6737820921cb382743ab2537fe7de72a1c47084e974368a47fde966fff0447,版本日志为 remote-fd6737820921,远程 /opt/smail/smail SHA-256 为 5422129011db2fa9faaef5fd65bb022628e084dd6c0e0f1f5cbed4fea35f3696。部署后 smail.service 为 active,主进程退出状态为 0,25、80、443 正常监听;两份 SQLite 的 PRAGMA integrity_check 均为 ok。
部署前备份保留于 /var/backups/smail-before-batch-read-20260917-003225,包含原主程序、smail.db 和 smail-state.db。首次错误格式产物曾短暂触发 systemd Exec format error,已立即用备份恢复并确认服务 active,随后使用明确 GOOS=linux GOARCH=amd64 CGO_ENABLED=0 的 ELF 产物重新部署;错误格式文件未继续运行,数据库和配置未受影响。
3d5c94e 修复首次安装完成后未启用分区配置管理。首次完成安装时通过现有迁移校验发布分区配置,失败不直接标记初始化完成;不强制迁移已经正常运行的旧版实例。
b93ea9d 修复收件人回车选择并统一主界面组件中文。地址选择器启用默认候选,主应用通过组件配置提供中文语言。
49ab24b 修复异步邮件投递状态与 587 端口加密协议。邮件与用户关联先以既有待投递状态入库;列表接口返回真实状态,页面不再将错误文本为空当作成功;587 使用 STARTTLS,保留证书校验及禁止明文回退的边界。
416b849 修复标准 MIME 中文附件名称解析。原正则无法识别 RFC 2231 的 filename*=,导致真实收信附件名变成 no_name_file;改为使用现有 go-message 参数解析器,保留 Content-Type name 优先级,新增普通名称、带分号名称、UTF-8 扩展参数、分段参数、编码词、旧式名称、优先级、缺省及非法参数共九个用例。
两次清库安装后,前端修复及邮件状态修复均采用备份后保留数据库的升级部署,用于同轮故障回归和验证会话、配置保持,不宣称这些版本又进行了一轮全新清库安装。
最终 Smail 二进制 SHA-256:
e0455f8156f4bc0ff25136ffb39e42566b0b154165eb3ce8eb4fb937ba6fe1f6
远程服务在部署后保持 active,HTTP 80、HTTPS 443 正常监听。config.json、email.json、plugins.json、smtp.json、ssl.json 均为 smail:smail 0600。
邮件与证书证据
从超级管理员网页向新建普通用户发送中文测试邮件。发件页面提交后返回列表,最初显示发送成功,但收件账号的收件箱和广告箱均未见该邮件。服务器 20:44 日志记录:
- 连接
47.108.78.12:25超时。 - 587 回退使用隐式 TLS,返回
first record does not look like a TLS handshake;代码与当前 STARTTLS 端口语义不一致,需要单独整改。 - 465 投递被
x509: certificate signed by unknown authority拒绝。
发件箱手动刷新后显示发送失败,说明最终错误已落库;最初成功提示来自异步投递前的状态,不能作为投递成功依据。
21:05 对 49ab24b 进行真实网页回归:向同一测试用户提交“投递状态远程回归 2104”,页面提示“邮件已提交,正在投递”,发件箱立即显示“待投递”。21:05:32 日志记录 25 端口超时后,587 STARTTLS 因证书不受信任终止,不再出现原来的 TLS 协议错误。21:06 手动刷新后,列表仅显示“发送失败”,无横向溢出。没有宣称自动刷新时效已经通过验证。
从 47 服务器执行 openssl s_client -starttls smtp -connect mail.solit.cn:587 -servername mail.solit.cn -verify_return_error -brief,已进入证书验证并返回 self-signed certificate,未关闭证书校验、未发送邮件内容。
原证书仅覆盖 *.solit.cn,安装校验因不覆盖主域名 solit.cn 而拒绝。测试改用服务器已有的 custom.crt、custom.key,覆盖主域名和通配域名,但属于自签名证书。当前公网服务仍使用该测试证书,浏览器提示证书不受信任。需要提供覆盖所需域名的受信任证书,不能将本轮功能检查当作生产 TLS 验收。
安装向导公网 IP 检测未成功;远程访问 api.ipify.org:443 失败,未修改外部 DNS,也未使用网页 DNS 解析结果冒充探测结果。
自动验证与限制
setup.test、config.test在远程以smail身份执行通过。adminreset.test在远程以smail身份执行全部通过,覆盖调用身份、一次性挑战、防重放、过期、socket 权限、重置事务与凭据撤销。email.test、send.test、smtp.test在远程以smail身份执行全部通过,新增实际持久化函数待投递状态、关联写入失败回滚、列表接口三种状态回归。测试使用隔离内存数据库,不写部署业务库。parsemail.test在远程以smail身份执行全部通过,包含九个新增附件名称用例以及既有正文、隐私和 XSS 用例。- 配置测试曾因从
/root继承工作目录而失败,改在服务账号可访问的测试目录执行后通过,没有放宽权限。 - 前端生产构建与 Linux Go 编译通过;构建有编辑器块超过 500 kB 的提示。
- 本次没有重新执行全部后端包、竞态测试或前端自动测试,不能沿用此前本机全量测试作为远程全量结论。
- 桌面浏览器已检查页面快照、截图和发件页控制台,所查控制台没有错误;未进行移动端检查。
- 键盘选择回归仅检查表单行为,未向不存在的选择测试地址发送邮件。
内部 25 端口验收
2026 年 9 月 17 日部署后回归
在最新 3ae8ecb 部署版本上,从 47 服务器本机连接 127.0.0.1:25,没有使用公网 25 端口。运行号为 20260917-003640,结果和本轮双库备份保留于 /var/backups/smail-internal-smtp-20260917-003640/result.json。五项测试均使用 TLS 1.3,SMTP DATA 返回 250,并以真实 SQLite 记录核对结果:
| 用例 | 邮件 ID | 实际结果 |
|---|---|---|
| 中文纯文本 | 20 | 仅普通用户 remotecheck 关联,正文核对一致 |
| HTML 与中文附件、多收件人 | 21 | 管理员和普通用户均关联,附件及字节核对通过 |
| 管理员专属附件 | 22 | 仅管理员关联 |
| 未知本域收件人 | 23 | 当前过滤级别 0,转管理员收件箱 |
| 未认证外域收件人 | 24 | 当前策略转管理员收件箱,无发信记录 |
本轮内部 SMTP 结果只证明远程本机接收链路和实际持久化正常,不代表公网 SMTP 投递、受信任 TLS 或网页发信闭环已通过。
根据用户最新要求,仅从 47 服务器连接 127.0.0.1:25,不要求公网 25 端口连通。测试脚本为 test/tools/internal_smtp_check.py,本机没有执行该脚本。测试客户端显式信任服务器现有测试证书,仍校验 mail.solit.cn 主机名、证书有效期和证书链;没有修改应用证书校验、系统 CA、DNS 或中继配置。
21:26:17 最终一轮五项测试全部完成,全部使用 TLS 1.3,SMTP DATA 返回 250,随后核对真实 SQLite 数据与用户关联,并非仅以协议返回码判定成功:
| 用例 | 邮件 ID | 实际结果 |
|---|---|---|
| 中文纯文本 | 15 | 仅普通用户收件,正文一致 |
| HTML 与中文附件、多收件人 | 16 | 管理员和普通用户均关联,正文、附件名及附件字节一致 |
| 管理员专属附件 | 17 | 仅管理员关联,用于附件越权对照 |
| 未知本域收件人 | 18 | 当前过滤级别 0,转管理员收件箱 |
| 未认证外域收件人 | 19 | 当前策略转管理员收件箱,仅有收信记录,没有发信记录 |
TLS 前未公布 AUTH,主动尝试明文 AUTH 返回 523。未认证外域邮件走收信分支,不调用发信路径;本轮没有公网抓包,不将该检查描述为所有中继场景的完整安全验收。当前未知地址和外域地址均不是在 RCPT 阶段拒绝,管理员兜底行为保持原样。
早期脚本误以为未知收件人必定丢弃,实际只读诊断确认当前过滤级别为 0、SPF 状态为通过、DKIM 状态为未通过,且邮件仅属于管理员。修订脚本显式要求当前过滤级别为 0,再验证准确归属,没有为让测试通过而修改业务策略。
桌面浏览器无缓存刷新后保持普通用户登录,列表可见中文邮件,详情显示中文 HTML 和“中文验收附件.txt”。附件 12 的下载内容与发送字节一致。管理员专属附件 17 在管理员会话中返回正确内容,在普通用户会话中返回业务错误“附件不可用”,没有附件数据。普通用户访问管理员邮件详情 13 返回“读取邮件失败”,自己的详情 12 正常返回。权限对照使用正常 CSRF 请求头;首次缺少该头的来源校验拒绝不作为用户隔离证据。
以上拒绝接口当前 HTTP 状态仍为 200,应依据业务错误码和无数据结果判断,不能仅看 HTTP 状态。详情页面未发现横向溢出。本轮未进行移动端验收,也未重新执行完整清库安装:保留同轮故障邮件和会话,完成备份后升级回归。
本轮内部 SMTP 结果及双库备份保留于 /var/backups/smail-internal-smtp-20260916-212617,目录内 result.json 可复核。本轮通过的是内部接收链路,不代表网页按 MX 路由发信闭环或公网受信任 TLS 已通过。
备份与保留
以下目录均位于远程服务器,包含敏感运行数据,不提交仓库:
/var/backups/smail-before-reset-20260916-201834:第一轮清库前备份。/var/backups/smail-before-reset-20260916-202943:第二轮清库前备份。/var/backups/smail-before-reset-20260916-205033:前端修复升级前备份,本次未执行清库。/var/backups/smail-before-reset-20260916-210318:邮件状态及 STARTTLS 修复升级前备份,本次未执行清库。/var/backups/smail-before-reset-20260916-212132:中文附件解析修复升级前完整备份,本次未执行清库。
备份均对完整归档进行比较与 SHA 校验。两份数据库 inode 保持为 smail.db=915735、smail-state.db=915727。旧配置及迁移源已归档,没有删除其他项目文件,没有操作同机 Scert、MySQL 或 PostgreSQL 数据。
最新备份归档 SHA-256:
9f712cb881db6acdcdefb1c20c5244524107529409196be810f8bb4d4c832c58
测试用户与失败邮件保留用于后续复核,密码、密钥及会话凭据不写入记录。
2026 年 9 月 17 日后续批量已读验收审查
本轮继续只在 47.108.78.12 执行远程验收,没有启动本机 Smail 服务,也没有修改远程账号密码、伪造会话或清理数据库。远程环境复核结果如下:
smail.service为active,主进程退出状态为 0;远程/opt/smail/smailSHA-256 仍为5422129011db2fa9faaef5fd65bb022628e084dd6c0e0f1f5cbed4fea35f3696。- 远程运行文件确认为 Linux x86-64 ELF;25、80、443 及邮件协议端口均保持监听。
smail.db与smail-state.db的PRAGMA integrity_check均返回ok,已有批量已读部署前备份及内部 SMTP 测试备份仍保留。- 从 47 服务器本机通过 HTTPS 回环访问登录页返回 200;未认证访问
/api/v1/user/info和/api/v1/email/list均返回业务错误码 403“登录已过期”。 - 未认证调用
POST /api/v1/email/read,请求 ID 为[20,21],返回业务错误码 403;调用前后相关user_email.is_read值均为2:20:0,1:21:0,2:21:0,没有越权修改。 - 继续尝试了当前数据库中的
admin、remotecheck账号和已有候选密码,均返回“账号或密码错误”;没有可用的授权网页测试会话。 - Chrome DevTools 访问远程站点时被现有自签名证书拦截,停留在证书错误页;这与此前记录的受信任 TLS 阻塞一致,不能据此宣称网页渲染或真实点击验收通过。
因此,本轮审查确认服务、部署产物、数据库完整性及未认证接口边界正常;批量已读的真实网页登录、选择邮件、点击“标记为已读”、刷新页面和混合归属网页请求仍保持阻塞,待提供有效测试账号及受信任测试证书后继续。数据库没有执行清理,历史测试邮件和备份继续保留。
2026 年 9 月 17 日生产整改升级回归
本节记录后续生产整改版本,不覆盖前文历史证据。本轮应用及测试二进制仍只在 47.108.78.12 运行;本机仅进行源码检查、前端构建、Linux 交叉编译和 SSH 操作。本轮采用备份后保留双库升级,没有清库,不作为重新安装验收。
整改内容
- 测试及部署脚本统一读取环境变量中的 SSH 凭据,校验已知主机密钥,不再自动信任未知主机。网页安装及 SMTP 示例密码也改为环境变量输入。
- 网页发信在同一事务内保存邮件、用户关联及每收件人的持久投递任务。进程重启后,尚未尝试的任务可以继续;已在途任务及旧版无队列的待投递邮件标记为“投递结果待核对”,不盲目重投。
- 临时网络、DNS 或 SMTP 4xx 失败最多尝试五次,间隔为 1、2、4、8 分钟。明确拒绝、证书错误、私网目标和 DATA 结果不确定均不自动重试。
- MX 按优先级排序并去重,支持备用 MX、无 MX 时使用域名自身及 Null MX 拒绝;保留既有安全端口回退。邮件头保留完整收件信息,队列任务只投递当前收件人的 SMTP 信封。
- SMTP DATA 最终 250 后的 QUIT 异常不再误判失败;发送 DATA 后失去明确结果的任务暂停核对。结果写库失败只重试数据库写入,不重复调用 SMTP。
- 后台投递接入在线数据库迁移排空边界;停机等待投递结束,不提前关闭仍在使用的数据库。投递状态更新不恢复已放入回收站的用户关联。
自动测试
七个相关 Linux 测试包在远程以 smail 账号执行,使用隔离内存或临时数据库,不改部署业务库。共 132 个顶层测试用例通过,日志保留在 /var/tmp/smail-review-20260917/*.result.log。
| 测试包 | 顶层用例数 | 结果 |
|---|---|---|
outbox |
10 | 通过 |
utils-send |
11 | 通过 |
utils-smtp |
8 | 通过 |
controllers-email |
12 | 通过 |
db-migration |
26 | 通过 |
res_init |
14 | 通过 |
services-dbmigration |
51 | 通过 |
新增覆盖包括部分投递成功、防重复领取、退避及重试上限、DATA 不确定结果、结果写库故障、读取失败、旧待投递记录、重启恢复、停机超时、回收站状态、队列插入失败整事务回滚和迁移等待后台投递。这里的测试通过不等于真实网页登录发信闭环已通过。
前端生产构建和 Linux amd64 编译通过,仍有编辑器分块超过 500 kB 的构建提示。没有重新执行全部后端包、竞态检测、移动端、真实 MySQL 或 PostgreSQL 验证。
部署证据
2026 年 9 月 17 日 10:06 完成双程序升级,版本为 remote-13bcad90e832,源码指纹为 13bcad90e832a9be78604854a1c91f72cfaf2a21770481c627e50ac361ce3b70。
| 项目 | 结果 |
|---|---|
/opt/smail/smail SHA-256 |
a3b4a0b0e75213bb7997fa55f789d98bca027e879c9dbfe986f7b1ee8c8230d9 |
/opt/smail/smail-admin SHA-256 |
16e48a16d3f47ab78b42fb1aa854dfc32ec2ccd3a95694c6ccb93fc1da075e34 |
| 数据库迁移版本 | 23 |
| 两份 SQLite 完整性 | 均为 ok |
| 服务状态 | active/running,NRestarts=0,ExecMainStatus=0 |
| 本地恢复 socket | /run/smail/admin-control.sock,smail:smail 0600 |
| HTTPS 首页 | 显式测试 CA、主机名校验下返回 200 |
| 未认证用户信息、邮件列表接口 | 均返回业务码 403,无业务数据 |
| 本次检查时段日志 | 25 条 journal 记录,未发现 error、fatal 或 panic 标记 |
完整停服备份为 /var/backups/smail-before-outbox-20260917-100608,归档 SHA-256 为 a2ed56666e9e691a63dfc6734ebe2a1e9c7bf2fe4ceb81cb55028e66ea52d016;包含原主程序、管理员工具、双库及完整部署归档。归档比对和数据库备份完整性检查通过,没有删除历史文件。此次部署成功,未实际演练失败回滚或异机恢复。
内部 SMTP 回归
运行号 20260917-100912,仅从远程连接 127.0.0.1:25。五项均使用 TLS 1.3,DATA 返回 250,并核对真实数据库归属、正文和附件字节:
| 用例 | 邮件 ID | 结果 |
|---|---|---|
| 中文纯文本 | 27 | 仅普通用户关联,正文一致 |
| HTML、中文附件及多收件人 | 28 | 管理员和普通用户关联,附件一致 |
| 管理员专属附件 | 29 | 仅管理员关联 |
| 未知本域收件人 | 30 | 过滤级别 0 下转管理员收件箱 |
| 未认证外域收件人 | 31 | 转管理员收件箱,无发信记录 |
结果及测试前双库备份位于 /var/backups/smail-internal-smtp-20260917-100912。没有修改过滤策略、系统 CA、证书验证或 DNS;客户端仅显式信任已有测试证书。内部接收链路通过,不代表网页发信、外部投递或生产 TLS 验收通过。
结论与限制
- [✓] 本轮指定的七包测试、部署产物核对、双库完整性、内部 SMTP 和未认证接口边界复审通过。
- 凭据硬编码清理完成;工作区已知旧 SSH 密码扫描零命中,但旧密码仍有效,Git 历史仍含旧凭据,不能视为泄露处置完成。
- [!] 新队列尚未完成真实网页登录发信闭环;部署后的队列表为空,不能用入站 SMTP 回归代替出站队列业务验收。
- [!] 当前队列按单实例、单工作器运行,未压测。结果落库持续失败时保留在途任务,需要告警和受控重启后转为待核对;不得人工直接改回排队状态。
- [!] 受信任 TLS、凭据轮换、正式管理员恢复交互、新密码登录与旧会话撤销、灾备恢复及全量兼容性验证仍未完成。
当前结论仍为:适合继续受控远程验收,不建议直接用于正式生产。后续门槛见《生产整改验收清单》。