From 4fcf3e11cdebbc52f7275f2d5567d96d86116430 Mon Sep 17 00:00:00 2001 From: CityFun <31820853+zhengkunwang223@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:52:10 +0800 Subject: [PATCH] fix: Resolve issue where bulk certificate setup creates duplicate server certificates (#11371) --- agent/app/service/website.go | 58 +-------------------------- agent/app/service/website_op.go | 11 +++++ agent/app/service/website_utils.go | 64 ++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 57 deletions(-) diff --git a/agent/app/service/website.go b/agent/app/service/website.go index bf1386f9b..8b348e560 100644 --- a/agent/app/service/website.go +++ b/agent/app/service/website.go @@ -3,9 +3,7 @@ package service import ( "bytes" "context" - "crypto/x509" "encoding/base64" - "encoding/pem" "errors" "fmt" "net" @@ -975,64 +973,10 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH websiteSSL = *websiteModel } if req.Type == constant.SSLManual { - var ( - certificate string - privateKey string - ) - switch req.ImportType { - case "paste": - certificate = req.Certificate - privateKey = req.PrivateKey - case "local": - fileOp := files.NewFileOp() - if !fileOp.Stat(req.PrivateKeyPath) { - return nil, buserr.New("ErrSSLKeyNotFound") - } - if !fileOp.Stat(req.CertificatePath) { - return nil, buserr.New("ErrSSLCertificateNotFound") - } - if content, err := fileOp.GetContent(req.PrivateKeyPath); err != nil { - return nil, err - } else { - privateKey = string(content) - } - if content, err := fileOp.GetContent(req.CertificatePath); err != nil { - return nil, err - } else { - certificate = string(content) - } - } - - privateKeyCertBlock, _ := pem.Decode([]byte(privateKey)) - if privateKeyCertBlock == nil { - return nil, buserr.New("ErrSSLKeyFormat") - } - - certBlock, _ := pem.Decode([]byte(certificate)) - if certBlock == nil { - return nil, buserr.New("ErrSSLCertificateFormat") - } - cert, err := x509.ParseCertificate(certBlock.Bytes) + websiteSSL, err = getManualWebsiteSSL(req) if err != nil { return nil, err } - websiteSSL.ExpireDate = cert.NotAfter - websiteSSL.StartDate = cert.NotBefore - websiteSSL.Type = cert.Issuer.CommonName - if len(cert.Issuer.Organization) > 0 { - websiteSSL.Organization = cert.Issuer.Organization[0] - } else { - websiteSSL.Organization = cert.Issuer.CommonName - } - if len(cert.DNSNames) > 0 { - websiteSSL.PrimaryDomain = cert.DNSNames[0] - websiteSSL.Domains = strings.Join(cert.DNSNames, ",") - } - websiteSSL.Provider = constant.Manual - websiteSSL.PrivateKey = privateKey - websiteSSL.Pem = certificate - websiteSSL.Status = constant.SSLReady - res.SSL = websiteSSL } diff --git a/agent/app/service/website_op.go b/agent/app/service/website_op.go index 864d33180..aca767896 100644 --- a/agent/app/service/website_op.go +++ b/agent/app/service/website_op.go @@ -91,6 +91,17 @@ func (w WebsiteService) BatchSetHttps(ctx context.Context, req request.BatchWebs HttpsPorts: req.HttpsPorts, Http3: req.Http3, } + if req.Type == constant.SSLManual { + websiteSSL, err := getManualWebsiteSSL(websiteHttpsOp) + if err != nil { + return err + } + if err = websiteSSLRepo.Create(ctx, &websiteSSL); err != nil { + return err + } + websiteHttpsOp.Type = constant.SSLExisted + websiteHttpsOp.WebsiteSSLID = websiteSSL.ID + } opWebsiteTask := func(t *task.Task) error { for _, web := range websites { if web.Type == constant.Stream { diff --git a/agent/app/service/website_utils.go b/agent/app/service/website_utils.go index 97d759db0..3746dfc1e 100644 --- a/agent/app/service/website_utils.go +++ b/agent/app/service/website_utils.go @@ -2,7 +2,9 @@ package service import ( "context" + "crypto/x509" "encoding/json" + "encoding/pem" "fmt" "log" "net" @@ -1707,3 +1709,65 @@ func getNginxUpstreamServers(upstreamServers []*components.UpstreamServer) []dto } return servers } + +func getManualWebsiteSSL(req request.WebsiteHTTPSOp) (model.WebsiteSSL, error) { + var websiteSSL model.WebsiteSSL + var ( + certificate string + privateKey string + ) + switch req.ImportType { + case "paste": + certificate = req.Certificate + privateKey = req.PrivateKey + case "local": + fileOp := files.NewFileOp() + if !fileOp.Stat(req.PrivateKeyPath) { + return websiteSSL, buserr.New("ErrSSLKeyNotFound") + } + if !fileOp.Stat(req.CertificatePath) { + return websiteSSL, buserr.New("ErrSSLCertificateNotFound") + } + if content, err := fileOp.GetContent(req.PrivateKeyPath); err != nil { + return websiteSSL, err + } else { + privateKey = string(content) + } + if content, err := fileOp.GetContent(req.CertificatePath); err != nil { + return websiteSSL, err + } else { + certificate = string(content) + } + } + + privateKeyCertBlock, _ := pem.Decode([]byte(privateKey)) + if privateKeyCertBlock == nil { + return websiteSSL, buserr.New("ErrSSLKeyFormat") + } + + certBlock, _ := pem.Decode([]byte(certificate)) + if certBlock == nil { + return websiteSSL, buserr.New("ErrSSLCertificateFormat") + } + cert, err := x509.ParseCertificate(certBlock.Bytes) + if err != nil { + return websiteSSL, err + } + websiteSSL.ExpireDate = cert.NotAfter + websiteSSL.StartDate = cert.NotBefore + websiteSSL.Type = cert.Issuer.CommonName + if len(cert.Issuer.Organization) > 0 { + websiteSSL.Organization = cert.Issuer.Organization[0] + } else { + websiteSSL.Organization = cert.Issuer.CommonName + } + if len(cert.DNSNames) > 0 { + websiteSSL.PrimaryDomain = cert.DNSNames[0] + websiteSSL.Domains = strings.Join(cert.DNSNames, ",") + } + websiteSSL.Provider = constant.Manual + websiteSSL.PrivateKey = privateKey + websiteSSL.Pem = certificate + websiteSSL.Status = constant.SSLReady + return websiteSSL, nil +}