diff --git a/internal/deployer/tencent_cdn.go b/internal/deployer/tencent_cdn.go index a0a44b6a..f5230910 100644 --- a/internal/deployer/tencent_cdn.go +++ b/internal/deployer/tencent_cdn.go @@ -101,9 +101,9 @@ func (d *TencentCDNDeployer) Deploy(ctx context.Context) error { } temp := make([]string, 0) - for _, aliInstanceId := range tcInstanceIds { - if !slices.Contains(deployedDomains, aliInstanceId) { - temp = append(temp, aliInstanceId) + for _, tcInstanceId := range tcInstanceIds { + if !slices.Contains(deployedDomains, tcInstanceId) { + temp = append(temp, tcInstanceId) } } tcInstanceIds = temp diff --git a/internal/domains/deploy.go b/internal/domains/deploy.go index c9df14d3..8b24c263 100644 --- a/internal/domains/deploy.go +++ b/internal/domains/deploy.go @@ -3,13 +3,22 @@ package domains import ( "context" "fmt" + "strings" "time" + "crypto/rsa" + "crypto/ecdsa" + "github.com/pocketbase/pocketbase/models" + "golang.org/x/exp/slices" + "github.com/usual2970/certimate/internal/applicant" "github.com/usual2970/certimate/internal/deployer" + "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/utils/app" + + "github.com/usual2970/certimate/internal/pkg/utils/x509" ) type Phase string @@ -45,7 +54,10 @@ func deploy(ctx context.Context, record *models.Record) error { cert := currRecord.GetString("certificate") expiredAt := currRecord.GetDateTime("expiredAt").Time() - if cert != "" && time.Until(expiredAt) > time.Hour*24*10 && currRecord.GetBool("deployed") { + // 检查证书是否包含设置的所有域名 + changed := isCertChanged(cert, currRecord) + + if cert != "" && time.Until(expiredAt) > time.Hour*24*10 && currRecord.GetBool("deployed") && !changed { app.GetApp().Logger().Info("证书在有效期内") history.record(checkPhase, "证书在有效期内且已部署,跳过", &RecordInfo{ Info: []string{fmt.Sprintf("证书有效期至 %s", expiredAt.Format("2006-01-02"))}, @@ -60,7 +72,7 @@ func deploy(ctx context.Context, record *models.Record) error { // ############2.申请证书 history.record(applyPhase, "开始申请", nil) - if cert != "" && time.Until(expiredAt) > time.Hour*24 { + if cert != "" && time.Until(expiredAt) > time.Hour*24 && !changed { history.record(applyPhase, "证书在有效期内,跳过", &RecordInfo{ Info: []string{fmt.Sprintf("证书有效期至 %s", expiredAt.Format("2006-01-02"))}, }) @@ -121,3 +133,69 @@ func deploy(ctx context.Context, record *models.Record) error { return nil } + +func isCertChanged(certificate string, record *models.Record) bool { + // 如果证书为空,直接返回true + if certificate == "" { + return true + } + + // 解析证书 + cert, err := x509.ParseCertificateFromPEM(certificate) + if err != nil { + app.GetApp().Logger().Error("解析证书失败", "err", err) + return true + } + + // 遍历域名列表,检查是否都在证书中,找到第一个不存在证书中域名时提前返回true + for _, domain := range strings.Split(record.GetString("domain"), ";") { + if !slices.Contains(cert.DNSNames, domain) && !slices.Contains(cert.DNSNames, "*."+removeLastSubdomain(domain)) { + return true + } + } + + // 解析applyConfig + applyConfig := &domain.ApplyConfig{} + record.UnmarshalJSONField("applyConfig", applyConfig) + + + // 检查证书加密算法是否变更 + switch pubkey := cert.PublicKey.(type) { + case *rsa.PublicKey: + bitSize := pubkey.N.BitLen() + switch bitSize { + case 2048: + // RSA2048 + if applyConfig.KeyAlgorithm != "" && applyConfig.KeyAlgorithm != "RSA2048" { return true } + case 3072: + // RSA3072 + if applyConfig.KeyAlgorithm != "RSA3072" { return true } + case 4096: + // RSA4096 + if applyConfig.KeyAlgorithm != "RSA4096" { return true } + case 8192: + // RSA8192 + if applyConfig.KeyAlgorithm != "RSA8192" { return true } + } + case *ecdsa.PublicKey: + bitSize := pubkey.Curve.Params().BitSize + switch bitSize { + case 256: + // EC256 + if applyConfig.KeyAlgorithm != "EC256" { return true } + case 384: + // EC384 + if applyConfig.KeyAlgorithm != "EC384" { return true } + } + } + + return false +} + +func removeLastSubdomain(domain string) string { + parts := strings.Split(domain, ".") + if len(parts) > 1 { + return strings.Join(parts[1:], ".") + } + return domain +}