fix(agent,acme,cert,web): 修 frps 安装 404 与 nginx 探测两处,证书颁发机构用 LiteSSL 替换 Buypass(v1.2.14)
CI / verify (push) Canceled after 0s
CI / verify (push) Canceled after 0s
- frps 安装/升级一直 404:frp 官方校验文件名始终是 frp_sha256_checksums.txt(不带版本号),代码却拼 frp_<版本>_sha256sums.txt;现按候选名依次尝试并在失败时列出尝试项。同一条 bug 也存在于本机下载 frpc 的路径,一并修复(SHA-256 校验逻辑未改) - nginx 探测(agent):nginxPath() 不再回落到配置里的裸名字 nginx(否则「未安装」被误报为配置校验失败,且一键安装入口永不出现);vhost 目录探测不再要求被加载文件带 .conf 后缀(Debian 的 sites-enabled/default 不带,导致只剩主配置目录可试,报「均无法放置完整 server 配置」),失败信息补上具体原因 - 证书 CA:LiteSSL(亚数 TrustAsia,90 天,支持单域名/通配符/多域名)替换 Buypass。LiteSSL 目录 meta.externalAccountRequired=true,强制 EAB——在 FreeSSL 创建后填 Kid/HMAC 即可,HMAC 只回掩码;Buypass 保留常量与展示元数据但不再可选 - 前端申请证书弹窗的颁发机构卡片改为前端可控清单(原先后端 /api/certs/options 的结果不参与渲染,后端改了弹窗不变) - 测试:internal/frp 校验文件候选名与 sha256sum 解析;internal/acme LiteSSL 目录/别名/通配符/Buypass 停用提示。gofmt / go build / go vet / go test / vue-tsc / vite build 全绿 - AgentVersion 0.12.4 → 0.12.7,双架构二进制已重编:VPS 上需点「升级 Agent」
This commit is contained in:
+13
-2
@@ -12,13 +12,14 @@ const (
|
||||
CALetsEncryptStaging = "letsencrypt-staging"
|
||||
CAZeroSSL = "zerossl"
|
||||
CABuypass = "buypass"
|
||||
// CALiteSSL 亚数 TrustAsia 的公益免费证书(90 天,支持单域名/通配符/多域名,强制 EAB)
|
||||
CALiteSSL = "litessl"
|
||||
)
|
||||
|
||||
// caRetired 记录已停止签发的 CA:仍然认识这些值(历史证书记录里可能存着,用于展示与清理),
|
||||
// 但不允许再用来申请——否则用户只会看到一个难懂的 ACME 报错而不是「这家 CA 不干了」。
|
||||
// 否则用户只会看到一个难懂的 ACME 报错。
|
||||
var caRetired = map[string]string{
|
||||
CABuypass: "Buypass 已于 2025-10-15 停止签发证书(ACME 服务 2026-04-15 终止),请改用 Let's Encrypt 或 ZeroSSL",
|
||||
CABuypass: "Buypass 已于 2025-10-15 停止签发证书(ACME 服务 2026-04-15 终止),请改用 Let's Encrypt、LiteSSL 或 ZeroSSL",
|
||||
}
|
||||
|
||||
// CAUnavailableReason 返回该 CA 已停用的原因;可用的 CA 返回空字符串。
|
||||
@@ -29,6 +30,8 @@ func CAUnavailableReason(ca string) string {
|
||||
const (
|
||||
zeroSSLDirectoryURL = "https://acme.zerossl.com/v2/DV90"
|
||||
buypassDirectoryURL = "https://api.buypass.com/acme/directory"
|
||||
// liteSSLDirectoryURL 实测 2026-09-27 可访问,目录里 meta.externalAccountRequired = true
|
||||
liteSSLDirectoryURL = "https://acme.litessl.com/acme/v2/directory"
|
||||
)
|
||||
|
||||
func NormalizeCA(ca string) string {
|
||||
@@ -41,6 +44,8 @@ func NormalizeCA(ca string) string {
|
||||
return CAZeroSSL
|
||||
case CABuypass, "buypass-go":
|
||||
return CABuypass
|
||||
case CALiteSSL, "trustasia":
|
||||
return CALiteSSL
|
||||
default:
|
||||
return ca
|
||||
}
|
||||
@@ -56,6 +61,8 @@ func DirectoryURL(ca string) (string, error) {
|
||||
return zeroSSLDirectoryURL, nil
|
||||
case CABuypass:
|
||||
return buypassDirectoryURL, nil
|
||||
case CALiteSSL:
|
||||
return liteSSLDirectoryURL, nil
|
||||
default:
|
||||
return "", fmt.Errorf("不支持的颁发机构:%s", ca)
|
||||
}
|
||||
@@ -71,6 +78,8 @@ func CALabel(ca string) string {
|
||||
return "ZeroSSL"
|
||||
case CABuypass:
|
||||
return "Buypass"
|
||||
case CALiteSSL:
|
||||
return "LiteSSL"
|
||||
default:
|
||||
if ca == "" {
|
||||
return "手动导入"
|
||||
@@ -84,6 +93,8 @@ func ValidateCA(ca string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// ValidateCADomains 校验各 CA 自己的限制。
|
||||
// LiteSSL 官方支持单域名 / 通配符 / 多域名,因此这里不额外限制。
|
||||
func ValidateCADomains(ca string, domains []string) error {
|
||||
switch NormalizeCA(ca) {
|
||||
case CABuypass:
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// LiteSSL 接替 Buypass 的位置:目录地址实测可用,且强制 EAB。
|
||||
func TestLiteSSLDirectoryAndLabel(t *testing.T) {
|
||||
url, err := DirectoryURL(CALiteSSL)
|
||||
if err != nil {
|
||||
t.Fatalf("LiteSSL 目录地址解析失败:%v", err)
|
||||
}
|
||||
if url != "https://acme.litessl.com/acme/v2/directory" {
|
||||
t.Fatalf("LiteSSL 目录地址不对:%q", url)
|
||||
}
|
||||
if label := CALabel(CALiteSSL); label != "LiteSSL" {
|
||||
t.Fatalf("LiteSSL 展示名不对:%q", label)
|
||||
}
|
||||
// 别名与归一化
|
||||
if got := NormalizeCA("trustasia"); got != CALiteSSL {
|
||||
t.Fatalf("别名 trustasia 应归一化为 %s,实际 %q", CALiteSSL, got)
|
||||
}
|
||||
if reason := CAUnavailableReason(CALiteSSL); reason != "" {
|
||||
t.Fatalf("LiteSSL 是可用的 CA,不该有停用原因:%q", reason)
|
||||
}
|
||||
}
|
||||
|
||||
// LiteSSL 支持通配符与多域名,因此 ValidateCADomains 不应拦它。
|
||||
func TestValidateCADomainsLiteSSLAllowsWildcard(t *testing.T) {
|
||||
domains := []string{"*.36800.cc", "a.com", "b.com", "c.com", "d.com", "e.com", "f.com"}
|
||||
if err := ValidateCADomains(CALiteSSL, domains); err != nil {
|
||||
t.Fatalf("LiteSSL 应允许通配符与多域名:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Buypass 保留在停用表里(历史记录要能展示),但提示里应给出可用的替代。
|
||||
func TestBuypassIsRetiredWithAlternatives(t *testing.T) {
|
||||
reason := CAUnavailableReason(CABuypass)
|
||||
if reason == "" {
|
||||
t.Fatal("Buypass 应仍被标记为已停用")
|
||||
}
|
||||
if !strings.Contains(reason, "LiteSSL") {
|
||||
t.Fatalf("停用提示里应包含 LiteSSL 这个替代项:%q", reason)
|
||||
}
|
||||
// 旧记录仍能正常取到目录地址(不报「不支持的颁发机构」)
|
||||
if _, err := DirectoryURL(CABuypass); err != nil {
|
||||
t.Fatalf("历史 Buypass 记录的目录地址仍应可解析:%v", err)
|
||||
}
|
||||
}
|
||||
@@ -416,6 +416,27 @@ func (s *Service) registerACMEAccount(ctx context.Context, client *lego.Client,
|
||||
Kid: kid,
|
||||
HmacEncoded: hmac,
|
||||
})
|
||||
case CALiteSSL:
|
||||
// LiteSSL 的目录里 meta.externalAccountRequired = true:必须带 EAB。
|
||||
// 与 ZeroSSL 不同,不经过厂商 API 换取,而是用户在 FreeSSL 平台自建 EAB 后直接填 kid/hmac。
|
||||
kid, err := s.settings.Get(ctx, settings.KeyLiteSSLEABKid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hmac, err := s.settings.Get(ctx, settings.KeyLiteSSLEABHMAC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kid = strings.TrimSpace(kid)
|
||||
hmac = strings.TrimSpace(hmac)
|
||||
if kid == "" || hmac == "" {
|
||||
return nil, fmt.Errorf("LiteSSL 要求 EAB 凭据:请在设置里填写 EAB Kid 与 EAB HMAC(在 FreeSSL 的「证书自动化 → EAB 管理」创建后原样粘贴)")
|
||||
}
|
||||
return client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||
TermsOfServiceAgreed: true,
|
||||
Kid: kid,
|
||||
HmacEncoded: hmac,
|
||||
})
|
||||
default:
|
||||
return client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user