This commit is contained in:
Fu Diwei
2026-07-31 14:07:23 +08:00
committed by RHQYZ
parent 293fc75a9d
commit 2994d8f2e7
6 changed files with 84 additions and 19 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}