Skip to content

fix(ssl): 自动 SSL 初始化前校验空域名 - #372

Merged
Jinnrry merged 2 commits into
Jinnrry:masterfrom
0clickjacking0:fix-acme-empty-domain
Nov 7, 2026
Merged

Jinnrry merged 2 commits into
Jinnrry:masterfrom
0clickjacking0:fix-acme-empty-domain

Conversation

@0clickjacking0

@0clickjacking0 0clickjacking0 commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

问题

首次初始化时,如果域名配置步骤尚未成功保存,config.json 中可能仍是:

{
  "domain": "",
  "domains": [],
  "webDomain": ""
}

但当前前端允许直接点击“下一步”进入 DNS/SSL 初始化,后端初始化接口也允许选择自动 HTTP / 自动 DNS 方式申请 SSL 证书。

此时 generateCertificate() 会构造 ACME 账号联系人:

Email: "i@" + cfg.Domain

由于 cfg.Domain 为空,联系人变成 i@,Let's Encrypt 注册账号失败:

urn:ietf:params:acme:error:invalidContact
unable to parse email address

更关键的是,config.ReadPrivateKey() 在读取不到 ACME 私钥时会先生成并立即持久化 config/ssl/account_private.pem。因此第一次注册虽然失败,私钥文件已经落盘。

用户随后补填域名并再次提交 SSL 初始化时,因为私钥文件已存在,代码会走 ResolveAccountByKey()。但这个 key 从未成功注册到 ACME server,CA 会返回:

urn:ietf:params:acme:error:accountDoesNotExist
No account exists with the provided key

于是实例进入持续坏状态,直到手工删除未注册的 account_private.pem 才能恢复。

修改内容

1. 前端提前拦截

在域名初始化步骤中,smtp_domain 或 web_domain 为空(仅空格也视为空)时:

  • 弹出错误提示;
  • 不发起 /api/setup 请求;
  • 不允许进入后续 DNS/SSL 步骤。

新增中英文提示文案:

  • 中文:SMTP域名和Web域名不能为空!
  • 英文:SMTP domain and web domain cannot be empty!

2. 后端防御性校验

  • 在 SetSSL() 中,选择自动 HTTP / 自动 DNS 且配置域名为空时,直接返回错误,并在写入 SSL 配置前拦截。
  • 手动上传证书模式不依赖域名,保持原逻辑不变。
  • 在 generateCertificate() 中增加同样的防御性校验,避免未来新增调用方绕过 SetSSL() 后仍生成无效的 i@ 联系人。

前端拦截用于提供正确的引导体验;后端校验继续保留,用于覆盖已有坏配置、直接调用 API、以及其他客户端绕过前端的情况。

对于已经处于坏状态的实例,仍然需要删除未成功注册的 config/ssl/account_private.pem 后重试;accountDoesNotExist 的自动自愈可以作为后续单独优化,避免本次改动过大。

测试

后端:

GOTOOLCHAIN=auto go test ./config ./services/setup/ssl
?       github.com/Jinnrry/pmail/config      [no test files]
ok      github.com/Jinnrry/pmail/services/setup/ssl  (cached)

前端:

cd fe
yarn install --frozen-lockfile
yarn build

构建成功;git diff --check 已通过。

@0clickjacking0 0clickjacking0 changed the title fix(ssl): reject automatic setup without a domain fix(ssl): 自动 SSL 初始化前校验空域名 Nov 7, 2026
@Jinnrry
Jinnrry merged commit d6815e4 into Jinnrry:master Nov 7, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants