From 2994d8f2e7103edec08e54aadaa9c6f3a84d5c00 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 31 Jul 2026 14:07:23 +0800 Subject: [PATCH] fix: #1407 --- .../providers/ucloud-ussl/ucloud_ussl.go | 88 ++++++++++++++++--- .../ucloud/ussl/api_download_certificate.go | 3 +- .../ussl/api_get_certificate_detail_info.go | 1 + .../ucloud/ussl/api_get_certificate_list.go | 1 + .../ussl/api_upload_normal_certificate.go | 1 + pkg/sdk3rd/ucloud/ussl/types.go | 9 +- 6 files changed, 84 insertions(+), 19 deletions(-) diff --git a/pkg/core/certmgr/providers/ucloud-ussl/ucloud_ussl.go b/pkg/core/certmgr/providers/ucloud-ussl/ucloud_ussl.go index 0172edeac..646cdbf84 100644 --- a/pkg/core/certmgr/providers/ucloud-ussl/ucloud_ussl.go +++ b/pkg/core/certmgr/providers/ucloud-ussl/ucloud_ussl.go @@ -1,13 +1,17 @@ package ucloudussl import ( + "archive/zip" + "bytes" "context" "crypto/md5" "crypto/x509" "encoding/base64" "encoding/hex" "fmt" + "io" "log/slog" + "net/http" "strings" "time" @@ -125,9 +129,10 @@ func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM string) // 查询用户证书列表 // REF: https://docs.ucloud.cn/api/usslcertificate-api/get_certificate_list + // REF: https://docs.ucloud.cn/api/usslcertificate-api/get_certificate_detail_info // REF: https://docs.ucloud.cn/api/usslcertificate-api/download_certificate getCertificateListPage := 1 - getCertificateListLimit := 1000 + getCertificateListPageSize := 1000 for { select { case <-ctx.Done(): @@ -140,7 +145,7 @@ func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM string) getCertificateListReq.Domain = ucloud.String(certX509.Subject.CommonName) getCertificateListReq.Sort = ucloud.String("2") getCertificateListReq.Page = ucloud.Int(getCertificateListPage) - getCertificateListReq.PageSize = ucloud.Int(getCertificateListLimit) + getCertificateListReq.PageSize = ucloud.Int(getCertificateListPageSize) getCertificateListResp, err := c.sdkClient.GetCertificateList(getCertificateListReq) c.logger.Debug("sdk request 'ussl.GetCertificateList'", slog.Any("request", getCertificateListReq), slog.Any("response", getCertificateListResp)) if err != nil { @@ -153,15 +158,10 @@ func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM string) continue } - // 对比证书颁发者 - if len(certX509.Issuer.Organization) == 0 || certItem.Brand != certX509.Issuer.Organization[0] { - continue - } - // 对比证书有效期 - if certX509.NotBefore.UnixMilli() != int64(certItem.NotBefore) { + if certX509.NotBefore.UnixMilli() != certItem.NotBefore { continue - } else if certX509.NotAfter.UnixMilli() != int64(certItem.NotAfter) { + } else if certX509.NotAfter.UnixMilli() != certItem.NotAfter { continue } @@ -213,6 +213,23 @@ func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM string) continue } + // 对比证书内容 + downloadCertificateReq := c.sdkClient.NewDownloadCertificateRequest() + downloadCertificateReq.CertificateID = ucloud.Int(certItem.CertificateID) + downloadCertificateResp, err := c.sdkClient.DownloadCertificate(downloadCertificateReq) + c.logger.Debug("sdk request 'ussl.DownloadCertificate'", slog.Any("request", downloadCertificateReq), slog.Any("response", downloadCertificateResp)) + if err != nil { + return nil, false, fmt.Errorf("failed to execute sdk request 'ussl.DownloadCertificate': %w", err) + } else { + oldCertPEM, err := downloadCertificateFromUCloud(downloadCertificateResp.CertificateUrl) + if err != nil { + c.logger.Warn("could not download certificate from ucloud", slog.String("url", downloadCertificateResp.CertificateUrl), slog.Any("error", err)) + } + if oldCertPEM != nil && !xcert.EqualCertificatesFromPEM(certPEM, string(oldCertPEM)) { + continue + } + } + return &UploadResult{ CertId: fmt.Sprintf("%d", certItem.CertificateID), CertName: certItem.Name, @@ -222,7 +239,8 @@ func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM string) }, true, nil } - if len(getCertificateListResp.CertificateList) < getCertificateListLimit { + if len(getCertificateListResp.CertificateList) < getCertificateListPageSize || + getCertificateListPage*getCertificateListPageSize >= getCertificateListResp.TotalCount { break } @@ -259,3 +277,53 @@ func createSDKClient(privateKey, publicKey, projectId, endpoint string) (*ucloud client := ucloudsdk.NewClient(&cfg, &credential) return client, nil } + +func downloadCertificateFromUCloud(url string) ([]byte, error) { + url = strings.ReplaceAll(url, "\\u0026", "&") + + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + contentType := resp.Header.Get("Content-Type") + if !strings.HasPrefix(contentType, "application/zip") { + return nil, fmt.Errorf("unexpected content type: %s", contentType) + } + + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + return nil, err + } + + const targetFileName = "Nginx/public.pem" + var pemData []byte + + for _, f := range reader.File { + if strings.EqualFold(f.Name, "ALL/public.crt") || strings.EqualFold(f.Name, "Nginx/public.pem") { + rc, err := f.Open() + if err != nil { + return nil, err + } + defer rc.Close() + + pemData, err = io.ReadAll(rc) + if err != nil { + return nil, err + } + break + } + } + + if len(pemData) == 0 { + return nil, fmt.Errorf("could not find the certificate file in the zip archive") + } + + return pemData, nil +} diff --git a/pkg/sdk3rd/ucloud/ussl/api_download_certificate.go b/pkg/sdk3rd/ucloud/ussl/api_download_certificate.go index d9e6cc0dd..fa2c061b6 100644 --- a/pkg/sdk3rd/ucloud/ussl/api_download_certificate.go +++ b/pkg/sdk3rd/ucloud/ussl/api_download_certificate.go @@ -15,8 +15,6 @@ type DownloadCertificateResponse struct { response.CommonBase CertificateUrl string - CertCA *CertificateDownloadInfo - Certificate *CertificateDownloadInfo } func (c *USSLClient) NewDownloadCertificateRequest() *DownloadCertificateRequest { @@ -25,6 +23,7 @@ func (c *USSLClient) NewDownloadCertificateRequest() *DownloadCertificateRequest c.Client.SetupRequest(req) req.SetRetryable(true) + req.SetEncoder(request.NewJSONEncoder(c.GetConfig(), c.GetCredential())) return req } diff --git a/pkg/sdk3rd/ucloud/ussl/api_get_certificate_detail_info.go b/pkg/sdk3rd/ucloud/ussl/api_get_certificate_detail_info.go index 0c191247e..89740f97b 100644 --- a/pkg/sdk3rd/ucloud/ussl/api_get_certificate_detail_info.go +++ b/pkg/sdk3rd/ucloud/ussl/api_get_certificate_detail_info.go @@ -23,6 +23,7 @@ func (c *USSLClient) NewGetCertificateDetailInfoRequest() *GetCertificateDetailI c.Client.SetupRequest(req) req.SetRetryable(true) + req.SetEncoder(request.NewJSONEncoder(c.GetConfig(), c.GetCredential())) return req } diff --git a/pkg/sdk3rd/ucloud/ussl/api_get_certificate_list.go b/pkg/sdk3rd/ucloud/ussl/api_get_certificate_list.go index 30b7e8a79..8058d055a 100644 --- a/pkg/sdk3rd/ucloud/ussl/api_get_certificate_list.go +++ b/pkg/sdk3rd/ucloud/ussl/api_get_certificate_list.go @@ -31,6 +31,7 @@ func (c *USSLClient) NewGetCertificateListRequest() *GetCertificateListRequest { c.Client.SetupRequest(req) req.SetRetryable(true) + req.SetEncoder(request.NewJSONEncoder(c.GetConfig(), c.GetCredential())) return req } diff --git a/pkg/sdk3rd/ucloud/ussl/api_upload_normal_certificate.go b/pkg/sdk3rd/ucloud/ussl/api_upload_normal_certificate.go index 1a99e8394..c070bd7f0 100644 --- a/pkg/sdk3rd/ucloud/ussl/api_upload_normal_certificate.go +++ b/pkg/sdk3rd/ucloud/ussl/api_upload_normal_certificate.go @@ -28,6 +28,7 @@ func (c *USSLClient) NewUploadNormalCertificateRequest() *UploadNormalCertificat c.Client.SetupRequest(req) req.SetRetryable(false) + req.SetEncoder(request.NewJSONEncoder(c.GetConfig(), c.GetCredential())) return req } diff --git a/pkg/sdk3rd/ucloud/ussl/types.go b/pkg/sdk3rd/ucloud/ussl/types.go index 2826f2cb3..024c90f15 100644 --- a/pkg/sdk3rd/ucloud/ussl/types.go +++ b/pkg/sdk3rd/ucloud/ussl/types.go @@ -9,8 +9,8 @@ type CertificateListItem struct { Brand string ValidityPeriod int Type string - NotBefore int - NotAfter int + NotBefore int64 + NotAfter int64 AlarmState int State string StateCode string @@ -54,8 +54,3 @@ type CertificateInfo struct { IssuedDate int ExpiredDate int } - -type CertificateDownloadInfo struct { - FileData string - FileName string -}