From 6cca047246e9fbd55a3762119e3b56f07e187ba1 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 12 Jun 2026 15:12:01 +0800 Subject: [PATCH 1/9] fix: #1323 --- .../providers/aliyun-alb/aliyun_alb.go | 47 +++++++++++-------- .../tencentcloud-ga2/tencentcloud_ga2.go | 4 +- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go b/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go index 684fcbe2..570d0014 100644 --- a/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go +++ b/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go @@ -294,7 +294,7 @@ func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerI // 查询监听证书列表 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlistenercertificates - listenerCertificates := make([]alialb.ListListenerCertificatesResponseBodyCertificates, 0) + listenerExtCertificates := make([]alialb.ListListenerCertificatesResponseBodyCertificates, 0) listListenerCertificatesToken := (*string)(nil) for { select { @@ -319,8 +319,20 @@ func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerI break } - for _, listenerCertificate := range listListenerCertificatesResp.Body.Certificates { - listenerCertificates = append(listenerCertificates, *listenerCertificate) + for _, certItem := range listListenerCertificatesResp.Body.Certificates { + if tea.BoolValue(certItem.IsDefault) { + continue + } + + if !strings.EqualFold(tea.StringValue(certItem.CertificateType), "Server") { + continue + } + + if !strings.EqualFold(tea.StringValue(certItem.Status), "Associated") { + continue + } + + listenerExtCertificates = append(listenerExtCertificates, *certItem) } if len(listListenerCertificatesResp.Body.Certificates) == 0 || listListenerCertificatesResp.Body.NextToken == nil { @@ -335,19 +347,11 @@ func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerI // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-getcertificatedetail certificateIsAlreadyAssociated := false certificateIdsToDissociate := make([]string, 0) - if len(listenerCertificates) > 0 { - d.logger.Info("found listener certificates to deploy", slog.Any("listenerCertificates", listenerCertificates)) + if len(listenerExtCertificates) > 0 { + d.logger.Info("found listener certificates in used", slog.Any("certificates", listenerExtCertificates)) var errs []error - for _, listenerCertificate := range listenerCertificates { - if tea.BoolValue(listenerCertificate.IsDefault) { - continue - } - - if !strings.EqualFold(tea.StringValue(listenerCertificate.Status), "Associated") { - continue - } - + for _, listenerCertificate := range listenerExtCertificates { certIdWithRegion := tea.StringValue(listenerCertificate.CertificateId) if certIdWithRegion == cloudCertId { certificateIsAlreadyAssociated = true @@ -376,14 +380,15 @@ func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerI errs = append(errs, fmt.Errorf("failed to execute sdk request 'cas.GetCertificateDetail': %w", err)) continue } else { - certSANDiff, _ := lo.Difference(tea.StringSliceValue(getCertificateDetailResp.Body.SubjectAlternativeNames), cloudCertSANs) - if len(certSANDiff) == 0 { // 同域名证书需要删除 + // 注意,虽然文档中存在 SubjectAlternativeNames 字段,但实际返回的数据结构中不包含 + certSANMatched := lo.ElementsMatch(strings.Split(tea.StringValue(getCertificateDetailResp.Body.Domain), ","), cloudCertSANs) + if certSANMatched && lo.Contains(cloudCertSANs, d.config.Domain) { // 同域名证书需要删除 certificateIdsToDissociate = append(certificateIdsToDissociate, certIdWithRegion) continue } certNotAfter := time.Unix(tea.Int64Value(getCertificateDetailResp.Body.NotAfter)/1000, 0) - if certNotAfter.Before(time.Now()) { // 过期证书需要删除 + if !certNotAfter.IsZero() && certNotAfter.Before(time.Now()) { // 过期证书需要删除 certificateIdsToDissociate = append(certificateIdsToDissociate, certIdWithRegion) continue } @@ -420,9 +425,7 @@ func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerI // 解除关联监听和扩展证书 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-dissociateadditionalcertificatesfromlistener if !certificateIsAlreadyAssociated && len(certificateIdsToDissociate) > 0 { - if err := d.waitForListenerReady(ctx, cloudListenerId); err != nil { - return err - } + d.logger.Info("found listener certificates to dissociate", slog.Any("certificateIds", certificateIdsToDissociate)) const MAX_CERT_PER_REQUEST = 10 certIdChunks := lo.Chunk(certificateIdsToDissociate, MAX_CERT_PER_REQUEST) @@ -431,6 +434,10 @@ func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerI case <-ctx.Done(): return ctx.Err() default: + if err := d.waitForListenerReady(ctx, cloudListenerId); err != nil { + return err + } + dissociateAdditionalCertificatesFromListenerReq := &alialb.DissociateAdditionalCertificatesFromListenerRequest{ ListenerId: tea.String(cloudListenerId), Certificates: lo.Map(certIds, func(certId string, _ int) *alialb.DissociateAdditionalCertificatesFromListenerRequestCertificates { diff --git a/pkg/core/deployer/providers/tencentcloud-ga2/tencentcloud_ga2.go b/pkg/core/deployer/providers/tencentcloud-ga2/tencentcloud_ga2.go index 4e990026..34a8e3ad 100644 --- a/pkg/core/deployer/providers/tencentcloud-ga2/tencentcloud_ga2.go +++ b/pkg/core/deployer/providers/tencentcloud-ga2/tencentcloud_ga2.go @@ -184,8 +184,8 @@ func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudAccelerat return fmt.Errorf("failed to execute sdk request 'ssl.DescribeCertificate': %w", err) } else { - certSANDiff, _ := lo.Difference(lo.FromSlicePtr(describeCertificateResp.Response.SubjectAltName), cloudCertSANs) - if len(certSANDiff) == 0 { // 同域名证书需要删除 + certSANMatched := lo.ElementsMatch(lo.FromSlicePtr(describeCertificateResp.Response.SubjectAltName), cloudCertSANs) + if certSANMatched { // 同域名证书需要删除 continue } From dbccb8bcf8673169048177c521e8ea4f14a7a1be Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Sat, 13 Jun 2026 10:37:19 +0800 Subject: [PATCH 2/9] fix(ui): fix WorkflowList layout issue --- ui/src/pages/workflows/WorkflowList.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui/src/pages/workflows/WorkflowList.tsx b/ui/src/pages/workflows/WorkflowList.tsx index 7572e1b3..696df268 100644 --- a/ui/src/pages/workflows/WorkflowList.tsx +++ b/ui/src/pages/workflows/WorkflowList.tsx @@ -55,9 +55,11 @@ const WorkflowList = () => { render: (_, record) => (
{record.name || "\u00A0"} - - {record.description} - + {record.description && ( + + {record.description} + + )}
), }, From a0bd17590d806e8cf3015ab4d988fee69f2f4ae7 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Sat, 13 Jun 2026 11:45:38 +0800 Subject: [PATCH 3/9] fix: #1337 --- .../challengers/http01/ftp/internal/lego.go | 27 +++++++--- .../challengers/http01/s3/internal/lego.go | 6 +++ .../challengers/http01/ssh/internal/ssh.go | 24 +++++++-- .../certifier/challengers/http01/ssh/ssh.go | 1 + pkg/utils/filepath/path.go | 52 +++++++++++++++---- 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/pkg/core/certifier/challengers/http01/ftp/internal/lego.go b/pkg/core/certifier/challengers/http01/ftp/internal/lego.go index c037ffcd..7810c450 100644 --- a/pkg/core/certifier/challengers/http01/ftp/internal/lego.go +++ b/pkg/core/certifier/challengers/http01/ftp/internal/lego.go @@ -3,12 +3,15 @@ package internal import ( "context" "fmt" + "log/slog" "path/filepath" "github.com/go-acme/lego/v5/challenge" "github.com/go-acme/lego/v5/challenge/http01" + "github.com/go-acme/lego/v5/log" "github.com/certimate-go/certimate/internal/tools/ftp" + xfilepath "github.com/certimate-go/certimate/pkg/utils/filepath" ) var _ challenge.Provider = (*HTTPProvider)(nil) @@ -48,10 +51,14 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("ftp: failed to create FTP client: %w", err) } - defer client.Quit() + log.Info("ftp: ftp connected") + defer func() { + client.Quit() + log.Info("ftp: ftp closed") + }() - challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) - challengeDir := filepath.Dir(challengePath) + challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) + challengeDir := xfilepath.Dir(challengePath) challengeFile := filepath.Base(challengePath) if err := client.MkdirAll(ctx, challengeDir); err != nil { return fmt.Errorf("ftp: failed to create the \".well-known\" directory: %w", err) @@ -63,6 +70,8 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("ftp: failed to write file for HTTP challenge: %w", err) } + log.Info("ftp: authz file uploaded", slog.String("path", challengePath)) + return nil } @@ -72,10 +81,14 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("ftp: failed to create FTP client: %w", err) } - defer client.Quit() + log.Info("ftp: ftp connected") + defer func() { + client.Quit() + log.Info("ftp: ftp closed") + }() - challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) - challengeDir := filepath.Dir(challengePath) + challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) + challengeDir := xfilepath.Dir(challengePath) challengeFile := filepath.Base(challengePath) if err := client.ChangeDir(ctx, challengeDir); err != nil { return fmt.Errorf("ftp: failed to change to the \".well-known\" directory: %w", err) @@ -84,6 +97,8 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("ftp: failed to remove file after HTTP challenge: %w", err) } + log.Info("ftp: authz file removed", slog.String("path", challengePath)) + return nil } diff --git a/pkg/core/certifier/challengers/http01/s3/internal/lego.go b/pkg/core/certifier/challengers/http01/s3/internal/lego.go index 7a7df404..5106c94b 100644 --- a/pkg/core/certifier/challengers/http01/s3/internal/lego.go +++ b/pkg/core/certifier/challengers/http01/s3/internal/lego.go @@ -3,10 +3,12 @@ package internal import ( "context" "fmt" + "log/slog" "strings" "github.com/go-acme/lego/v5/challenge" "github.com/go-acme/lego/v5/challenge/http01" + "github.com/go-acme/lego/v5/log" "github.com/certimate-go/certimate/internal/tools/s3" ) @@ -52,6 +54,8 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("s3: failed to upload file for HTTP challenge: %w", err) } + log.Info("s3: authz file uploaded", slog.String("bucket", p.config.Bucket), slog.String("object", objectKey)) + return nil } @@ -66,6 +70,8 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("s3: failed to remove file after HTTP challenge: %w", err) } + log.Info("s3: authz file removed", slog.String("bucket", p.config.Bucket), slog.String("object", objectKey)) + return nil } diff --git a/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go b/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go index 998646ec..74bcdc7a 100644 --- a/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go +++ b/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go @@ -3,12 +3,14 @@ package internal import ( "context" "fmt" - "path/filepath" + "log/slog" "github.com/go-acme/lego/v5/challenge" "github.com/go-acme/lego/v5/challenge/http01" + "github.com/go-acme/lego/v5/log" "github.com/certimate-go/certimate/internal/tools/ssh" + xfilepath "github.com/certimate-go/certimate/pkg/utils/filepath" xssh "github.com/certimate-go/certimate/pkg/utils/ssh" ) @@ -51,13 +53,19 @@ func (p *HTTPProvider) Present(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("ssh: failed to create SSH client: %w", err) } - defer client.Close() + log.Info("ssh: ssh connected") + defer func() { + client.Close() + log.Info("ssh: ssh closed") + }() - challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) + challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) if err := xssh.WriteRemoteString(client.RawClient(), challengePath, keyAuth, p.config.UseSCP); err != nil { return fmt.Errorf("ssh: failed to write file for HTTP challenge: %w", err) } + log.Info("ssh: authz file uploaded", slog.String("path", challengePath)) + return nil } @@ -67,14 +75,20 @@ func (p *HTTPProvider) CleanUp(ctx context.Context, domain, token, keyAuth strin return fmt.Errorf("ssh: failed to create SSH client: %w", err) } - defer client.Close() + log.Info("ssh: ssh connected") + defer func() { + client.Close() + log.Info("ssh: ssh closed") + }() // 删除质询文件 - challengePath := filepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) + challengePath := xfilepath.Join(p.config.WebRootPath, http01.ChallengePath(token)) if err := xssh.RemoveRemote(client.RawClient(), challengePath, p.config.UseSCP); err != nil { return fmt.Errorf("ssh: failed to remove file after HTTP challenge: %w", err) } + log.Info("ssh: authz file removed", slog.String("path", challengePath)) + return nil } diff --git a/pkg/core/certifier/challengers/http01/ssh/ssh.go b/pkg/core/certifier/challengers/http01/ssh/ssh.go index a7b0738e..059773c0 100644 --- a/pkg/core/certifier/challengers/http01/ssh/ssh.go +++ b/pkg/core/certifier/challengers/http01/ssh/ssh.go @@ -65,6 +65,7 @@ func NewChallenger(config *ChallengerConfig) (core.ACMEChallenger, error) { } providerConfig.JumpServers = append(providerConfig.JumpServers, jumpServerCfg) } + providerConfig.WebRootPath = config.WebRootPath provider, err := internal.NewHTTPProviderConfig(providerConfig) if err != nil { diff --git a/pkg/utils/filepath/path.go b/pkg/utils/filepath/path.go index 78c847aa..9497dfc7 100644 --- a/pkg/utils/filepath/path.go +++ b/pkg/utils/filepath/path.go @@ -5,6 +5,11 @@ import ( "strings" ) +const ( + separatorOnWindows = "\\" + separatorOnUnix = "/" +) + // 与标准库中的 [filepath.Dir] 类似,但会尝试保留原有的路径分隔符。 // // 入参: @@ -13,21 +18,46 @@ import ( // 出参: // - 目录路径。 func Dir(path string) string { - const SEP_WIN = "\\" - const SEP_UNIX = "/" - - sep := SEP_UNIX - if strings.Contains(path, SEP_WIN) && !strings.Contains(path, SEP_UNIX) { - sep = SEP_WIN + sep := string(stdfilepath.Separator) + if strings.Contains(path, separatorOnWindows) && !strings.Contains(path, separatorOnUnix) { + sep = separatorOnWindows + } else if strings.Contains(path, separatorOnUnix) && !strings.Contains(path, separatorOnWindows) { + sep = separatorOnUnix } dir := stdfilepath.Dir(path) + return normalizePath(sep, dir) +} - if sep != SEP_UNIX && strings.Contains(dir, SEP_UNIX) { - dir = strings.ReplaceAll(dir, SEP_UNIX, sep) - } else if sep != SEP_WIN && strings.Contains(dir, SEP_WIN) { - dir = strings.ReplaceAll(dir, SEP_WIN, sep) +// 与标准库中的 [filepath.Join] 类似,但会尝试保留原有的路径分隔符。 +// +// 入参: +// - elem: 路径元素。 +// +// 出参: +// - 连接后的路径。 +func Join(elem ...string) string { + sep := string(stdfilepath.Separator) + for _, e := range elem { + if strings.Contains(e, separatorOnWindows) && !strings.Contains(e, separatorOnUnix) { + sep = separatorOnWindows + break + } else if strings.Contains(e, separatorOnUnix) && !strings.Contains(e, separatorOnWindows) { + sep = separatorOnUnix + break + } } - return dir + path := stdfilepath.Join(elem...) + return normalizePath(sep, path) +} + +func normalizePath(separator, path string) string { + if separator != separatorOnUnix && strings.Contains(path, separatorOnUnix) { + path = strings.ReplaceAll(path, separatorOnUnix, separator) + } else if separator != separatorOnWindows && strings.Contains(path, separatorOnWindows) { + path = strings.ReplaceAll(path, separatorOnWindows, separator) + } + + return path } From ceb05629e995ed774bad75e0f6801c6a0e394732 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 17 Jun 2026 10:08:27 +0800 Subject: [PATCH 4/9] fix: enforce webroot path be mandatory in http-01 providers --- .../certifier/challengers/http01/ftp/internal/lego.go | 4 ++++ pkg/core/certifier/challengers/http01/local/local.go | 4 ++++ .../certifier/challengers/http01/ssh/internal/ssh.go | 9 ++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pkg/core/certifier/challengers/http01/ftp/internal/lego.go b/pkg/core/certifier/challengers/http01/ftp/internal/lego.go index 7810c450..49ffbdf6 100644 --- a/pkg/core/certifier/challengers/http01/ftp/internal/lego.go +++ b/pkg/core/certifier/challengers/http01/ftp/internal/lego.go @@ -40,6 +40,10 @@ func NewHTTPProviderConfig(config *Config) (*HTTPProvider, error) { return nil, fmt.Errorf("the configuration of the acme challenge provider is nil") } + if config.WebRootPath == "" { + return nil, fmt.Errorf("ftp: webroot path must be set") + } + return &HTTPProvider{ config: config, }, nil diff --git a/pkg/core/certifier/challengers/http01/local/local.go b/pkg/core/certifier/challengers/http01/local/local.go index 861be77d..5d0783cc 100644 --- a/pkg/core/certifier/challengers/http01/local/local.go +++ b/pkg/core/certifier/challengers/http01/local/local.go @@ -18,6 +18,10 @@ func NewChallenger(config *ChallengerConfig) (core.ACMEChallenger, error) { return nil, fmt.Errorf("the configuration of the acme challenge provider is nil") } + if config.WebRootPath == "" { + return nil, fmt.Errorf("local: webroot path must be set") + } + provider, err := webroot.NewHTTPProvider(config.WebRootPath) if err != nil { return nil, err diff --git a/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go b/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go index 74bcdc7a..d52218f5 100644 --- a/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go +++ b/pkg/core/certifier/challengers/http01/ssh/internal/ssh.go @@ -27,9 +27,8 @@ func NewDefaultConfig() *Config { defaultCfg := ssh.NewDefaultConfig() return &Config{ - Config: *defaultCfg, - UseSCP: false, - WebRootPath: "/var/www/html", + Config: *defaultCfg, + UseSCP: false, } } @@ -42,6 +41,10 @@ func NewHTTPProviderConfig(config *Config) (*HTTPProvider, error) { return nil, fmt.Errorf("the configuration of the acme challenge provider is nil") } + if config.WebRootPath == "" { + return nil, fmt.Errorf("ssh: webroot path must be set") + } + return &HTTPProvider{ config: config, }, nil From 30acdbf4b66fbeb1b8f64096faf739380b502862 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 17 Jun 2026 10:08:28 +0800 Subject: [PATCH 5/9] fix: #1342 --- cmd/intercmd.go | 2 +- cmd/version.go | 2 +- cmd/winsc_nonwindows.go | 2 +- cmd/winsc_windows.go | 2 +- main.go | 2 +- pkg/sdk3rd-forked | 1 + 6 files changed, 6 insertions(+), 5 deletions(-) create mode 160000 pkg/sdk3rd-forked diff --git a/cmd/intercmd.go b/cmd/intercmd.go index 900038a4..3281ca90 100644 --- a/cmd/intercmd.go +++ b/cmd/intercmd.go @@ -20,7 +20,7 @@ import ( func NewInternalCommand(app core.App) *cobra.Command { command := &cobra.Command{ Use: "intercmd", - Short: "[INTERNAL] Internal dedicated for Certimate", + Short: "[RESERVED] PLEASE DO NOT USE!", } command.AddCommand(internalCertApplyCommand(app)) diff --git a/cmd/version.go b/cmd/version.go index 77202809..8a95d211 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -13,7 +13,7 @@ import ( func NewVersionCommand(_ core.App) *cobra.Command { command := &cobra.Command{ Use: "version", - Short: "Print the version information", + Short: "Prints version information", Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Certimate v%s\n", app.AppVersion) fmt.Printf("Build with %s on %s_%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH) diff --git a/cmd/winsc_nonwindows.go b/cmd/winsc_nonwindows.go index 7908ee96..9baf441c 100644 --- a/cmd/winsc_nonwindows.go +++ b/cmd/winsc_nonwindows.go @@ -11,7 +11,7 @@ import ( func NewWinscCommand(app core.App) *cobra.Command { command := &cobra.Command{ Use: "winsc", - Short: "Install/Uninstall Windows service (Not supported on non-Windows OS)", + Short: "Manages Windows service (Not supported on non-Windows OS)", } return command diff --git a/cmd/winsc_windows.go b/cmd/winsc_windows.go index 4b790d3f..1c8e3d3b 100644 --- a/cmd/winsc_windows.go +++ b/cmd/winsc_windows.go @@ -23,7 +23,7 @@ const winscName = "certimate" func NewWinscCommand(app core.App) *cobra.Command { command := &cobra.Command{ Use: "winsc", - Short: "Install/Uninstall Windows service", + Short: "Manages Windows service", } command.AddCommand(winscInstallCommand(app)) diff --git a/main.go b/main.go index 48f3f706..0c267e36 100644 --- a/main.go +++ b/main.go @@ -48,7 +48,7 @@ func main() { pb.RootCmd.AddCommand(cmd.NewWinscCommand(pb)) switch os.Args[1] { - case "serve": + case "serve", "superuser": { pb.OnServe().BindFunc(func(e *core.ServeEvent) error { scheduler.Setup() diff --git a/pkg/sdk3rd-forked b/pkg/sdk3rd-forked new file mode 160000 index 00000000..ad292586 --- /dev/null +++ b/pkg/sdk3rd-forked @@ -0,0 +1 @@ +Subproject commit ad2925860f15794f131bff0aef60d738100d1a93 From 3e4bb32fe45b94925846001d562d336c77201ba7 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 17 Jun 2026 10:08:28 +0800 Subject: [PATCH 6/9] fix: correct webhook Content-Type validation --- .../deployer/providers/webhook/webhook.go | 46 ++++++++++++------- .../notifier/providers/webhook/webhook.go | 46 ++++++++++++------- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/pkg/core/deployer/providers/webhook/webhook.go b/pkg/core/deployer/providers/webhook/webhook.go index 2437cb75..0646e7d6 100644 --- a/pkg/core/deployer/providers/webhook/webhook.go +++ b/pkg/core/deployer/providers/webhook/webhook.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "log/slog" + "mime" "net/http" "net/url" "strings" @@ -48,6 +49,26 @@ type Deployer struct { var _ Provider = (*Deployer)(nil) +const ( + contentTypeJson = "application/json" + contentTypeForm = "application/x-www-form-urlencoded" + contentTypeMultipart = "multipart/form-data" +) + +var allowedContentTypes = map[string]bool{ + contentTypeJson: true, + contentTypeForm: true, + contentTypeMultipart: true, +} + +var allowedMethods = map[string]bool{ + http.MethodGet: true, + http.MethodPost: true, + http.MethodPut: true, + http.MethodPatch: true, + http.MethodDelete: true, +} + func NewDeployer(config *DeployerConfig) (*Deployer, error) { if config == nil { return nil, fmt.Errorf("the configuration of the deployer provider is nil") @@ -104,11 +125,7 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep webhookMethod := strings.ToUpper(d.config.Method) if webhookMethod == "" { webhookMethod = http.MethodPost - } else if webhookMethod != http.MethodGet && - webhookMethod != http.MethodPost && - webhookMethod != http.MethodPut && - webhookMethod != http.MethodPatch && - webhookMethod != http.MethodDelete { + } else if !allowedMethods[webhookMethod] { return nil, fmt.Errorf("unsupported webhook request method '%s'", webhookMethod) } @@ -119,16 +136,11 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep } // 处理 Webhook 请求内容类型 - const CONTENT_TYPE_JSON = "application/json" - const CONTENT_TYPE_FORM = "application/x-www-form-urlencoded" - const CONTENT_TYPE_MULTIPART = "multipart/form-data" webhookContentType := webhookHeaders.Get("Content-Type") if webhookContentType == "" { - webhookContentType = CONTENT_TYPE_JSON - webhookHeaders.Set("Content-Type", CONTENT_TYPE_JSON) - } else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) && - strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) && - strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) { + webhookContentType = contentTypeJson + webhookHeaders.Set("Content-Type", contentTypeJson) + } else if mediaType, _, err := mime.ParseMediaType(webhookContentType); err != nil || !allowedContentTypes[mediaType] { return nil, fmt.Errorf("unsupported webhook content type '%s'", webhookContentType) } @@ -146,7 +158,7 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep return nil, fmt.Errorf("failed to unmarshal webhook data: %w", err) } - if webhookMethod == http.MethodGet || webhookContentType == CONTENT_TYPE_FORM || webhookContentType == CONTENT_TYPE_MULTIPART { + if webhookMethod == http.MethodGet || webhookContentType == contentTypeForm || webhookContentType == contentTypeMultipart { temp := make(map[string]string) jsonb, err := json.Marshal(webhookData) if err != nil { @@ -186,11 +198,11 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep req.SetQueryParams(webhookData.(map[string]string)) } else { switch webhookContentType { - case CONTENT_TYPE_JSON: + case contentTypeJson: req.SetBody(webhookData) - case CONTENT_TYPE_FORM: + case contentTypeForm: req.SetFormData(webhookData.(map[string]string)) - case CONTENT_TYPE_MULTIPART: + case contentTypeMultipart: req.SetMultipartFormData(webhookData.(map[string]string)) } } diff --git a/pkg/core/notifier/providers/webhook/webhook.go b/pkg/core/notifier/providers/webhook/webhook.go index 0d5b1aa2..69f42368 100644 --- a/pkg/core/notifier/providers/webhook/webhook.go +++ b/pkg/core/notifier/providers/webhook/webhook.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "log/slog" + "mime" "net/http" "net/url" "strings" @@ -46,6 +47,26 @@ type Notifier struct { var _ Provider = (*Notifier)(nil) +const ( + contentTypeJson = "application/json" + contentTypeForm = "application/x-www-form-urlencoded" + contentTypeMultipart = "multipart/form-data" +) + +var allowedContentTypes = map[string]bool{ + contentTypeJson: true, + contentTypeForm: true, + contentTypeMultipart: true, +} + +var allowedMethods = map[string]bool{ + http.MethodGet: true, + http.MethodPost: true, + http.MethodPut: true, + http.MethodPatch: true, + http.MethodDelete: true, +} + func NewNotifier(config *NotifierConfig) (*Notifier, error) { if config == nil { return nil, fmt.Errorf("the configuration of the notifier provider is nil") @@ -90,11 +111,7 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) ( webhookMethod := strings.ToUpper(n.config.Method) if webhookMethod == "" { webhookMethod = http.MethodPost - } else if webhookMethod != http.MethodGet && - webhookMethod != http.MethodPost && - webhookMethod != http.MethodPut && - webhookMethod != http.MethodPatch && - webhookMethod != http.MethodDelete { + } else if !allowedMethods[webhookMethod] { return nil, fmt.Errorf("unsupported webhook request method '%s'", webhookMethod) } @@ -105,16 +122,11 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) ( } // 处理 Webhook 请求内容类型 - const CONTENT_TYPE_JSON = "application/json" - const CONTENT_TYPE_FORM = "application/x-www-form-urlencoded" - const CONTENT_TYPE_MULTIPART = "multipart/form-data" webhookContentType := webhookHeaders.Get("Content-Type") if webhookContentType == "" { - webhookContentType = CONTENT_TYPE_JSON - webhookHeaders.Set("Content-Type", CONTENT_TYPE_JSON) - } else if strings.HasPrefix(webhookContentType, CONTENT_TYPE_JSON) && - strings.HasPrefix(webhookContentType, CONTENT_TYPE_FORM) && - strings.HasPrefix(webhookContentType, CONTENT_TYPE_MULTIPART) { + webhookContentType = contentTypeJson + webhookHeaders.Set("Content-Type", contentTypeJson) + } else if mediaType, _, err := mime.ParseMediaType(webhookContentType); err != nil || !allowedContentTypes[mediaType] { return nil, fmt.Errorf("unsupported webhook content type '%s'", webhookContentType) } @@ -131,7 +143,7 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) ( return nil, fmt.Errorf("failed to unmarshal webhook data: %w", err) } - if webhookMethod == http.MethodGet || webhookContentType == CONTENT_TYPE_FORM || webhookContentType == CONTENT_TYPE_MULTIPART { + if webhookMethod == http.MethodGet || webhookContentType == contentTypeForm || webhookContentType == contentTypeMultipart { temp := make(map[string]string) jsonb, err := json.Marshal(webhookData) if err != nil { @@ -161,11 +173,11 @@ func (n *Notifier) Notify(ctx context.Context, subject string, message string) ( req.SetQueryParams(webhookData.(map[string]string)) } else { switch webhookContentType { - case CONTENT_TYPE_JSON: + case contentTypeJson: req.SetBody(webhookData) - case CONTENT_TYPE_FORM: + case contentTypeForm: req.SetFormData(webhookData.(map[string]string)) - case CONTENT_TYPE_MULTIPART: + case contentTypeMultipart: req.SetMultipartFormData(webhookData.(map[string]string)) } } From 3cef9be669ed5dae5a653dda238461d693a69a07 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 19 Jun 2026 09:45:23 +0800 Subject: [PATCH 7/9] fix: calling `app.GetLogger()` in non-serve mode triggers a panic --- main.go | 109 +++++++++++++++++++++++++++----------------------------- 1 file changed, 53 insertions(+), 56 deletions(-) diff --git a/main.go b/main.go index 0c267e36..375be36d 100644 --- a/main.go +++ b/main.go @@ -31,15 +31,7 @@ func main() { return } - var flagHttp string - pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError) - pflag.CommandLine.Parse(os.Args[2:]) // skip the first two arguments: "main.go serve" - pflag.StringVar(&flagHttp, "http", "127.0.0.1:8090", "HTTP server address") - pflag.Parse() - migratecmd.MustRegister(pb, pb.RootCmd, migratecmd.Config{ - // enable auto creation of migration files when making collection changes in the Admin UI - // (the isGoRun check is to enable it only during development) Automigrate: strings.HasPrefix(os.Args[0], os.TempDir()), }) @@ -47,65 +39,70 @@ func main() { pb.RootCmd.AddCommand(cmd.NewVersionCommand(pb)) pb.RootCmd.AddCommand(cmd.NewWinscCommand(pb)) - switch os.Args[1] { - case "serve", "superuser": - { - pb.OnServe().BindFunc(func(e *core.ServeEvent) error { - scheduler.Setup() - workflow.Setup() - routes.BindRouter(e.Router) + isServeCmd := os.Args[1] == "serve" + + if isServeCmd { + var flagHttp string + pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError) + pflag.CommandLine.Parse(os.Args[2:]) // skip the first two arguments: "main.go serve" + pflag.StringVar(&flagHttp, "http", "127.0.0.1:8090", "HTTP server address") + pflag.Parse() + + pb.OnServe().BindFunc(func(e *core.ServeEvent) error { + scheduler.Setup() + workflow.Setup() + routes.BindRouter(e.Router) + return e.Next() + }) + + pb.OnServe().Bind(&hook.Handler[*core.ServeEvent]{ + Func: func(e *core.ServeEvent) error { + e.Router. + GET("/{path...}", apis.Static(ui.DistDirFS, false)). + Bind(apis.Gzip()) return e.Next() - }) + }, + Priority: 999, + }) - pb.OnServe().Bind(&hook.Handler[*core.ServeEvent]{ - Func: func(e *core.ServeEvent) error { - e.Router. - GET("/{path...}", apis.Static(ui.DistDirFS, false)). - Bind(apis.Gzip()) - return e.Next() - }, - Priority: 999, - }) + pb.OnServe().BindFunc(func(e *core.ServeEvent) error { + slog.Info("[CERTIMATE] Visit the website: http://" + flagHttp) + return e.Next() + }) - pb.OnServe().BindFunc(func(e *core.ServeEvent) error { - slog.Info("[CERTIMATE] Visit the website: http://" + flagHttp) - return e.Next() - }) + pb.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error { + err := e.Next() + if err != nil { + return err + } - pb.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error { - err := e.Next() - if err != nil { + settings := pb.Settings() + if !settings.Batch.Enabled { + settings.Batch.Enabled = true + settings.Batch.MaxRequests = 1000 + settings.Batch.Timeout = 30 + if err := pb.Save(settings); err != nil { return err } + } - settings := pb.Settings() - if !settings.Batch.Enabled { - settings.Batch.Enabled = true - settings.Batch.MaxRequests = 1000 - settings.Batch.Timeout = 30 - if err := pb.Save(settings); err != nil { - return err - } - } + return nil + }) - return nil - }) - - pb.OnTerminate().BindFunc(func(e *core.TerminateEvent) error { + pb.OnTerminate().BindFunc(func(e *core.TerminateEvent) error { + if pb.IsBootstrapped() { workflow.Teardown() - return e.Next() - }) - - if err := cmd.Serve(pb); err != nil { - slog.Error("[CERTIMATE] Serve failed.", slog.Any("error", err)) } - } - default: - { - if err := pb.Execute(); err != nil { - slog.Error("[CERTIMATE] Start failed.", slog.Any("error", err)) - } + return e.Next() + }) + } + + if err := cmd.Serve(pb); err != nil { + if isServeCmd { + slog.Error("[CERTIMATE] Serve failed.", slog.Any("error", err)) + } else { + slog.Error("[CERTIMATE] Start failed.", slog.Any("error", err)) } } } From d52b11508cc9fcc84a4a7095bf2d443919fac9f2 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 19 Jun 2026 09:45:23 +0800 Subject: [PATCH 8/9] fix: #1346 --- pkg/core/certmgr/providers/1panel/1panel.go | 24 +++------- pkg/sdk3rd/1panel/api_website_ssl_get.go | 50 --------------------- pkg/sdk3rd/1panel/v2/api_website_ssl_get.go | 50 --------------------- 3 files changed, 6 insertions(+), 118 deletions(-) delete mode 100644 pkg/sdk3rd/1panel/api_website_ssl_get.go delete mode 100644 pkg/sdk3rd/1panel/v2/api_website_ssl_get.go diff --git a/pkg/core/certmgr/providers/1panel/1panel.go b/pkg/core/certmgr/providers/1panel/1panel.go index bb826ca1..136c7b09 100644 --- a/pkg/core/certmgr/providers/1panel/1panel.go +++ b/pkg/core/certmgr/providers/1panel/1panel.go @@ -134,18 +134,11 @@ func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, pri switch sdkClient := c.sdkClient.(type) { case *onepanelsdk.Client: { - // 获取证书详情 - websiteSSLGetResp, err := sdkClient.WebsiteSSLGetWithContext(ctx, sslId) - c.logger.Debug("sdk request 'WebsiteSSLGet'", slog.Int64("params.sslId", sslId), slog.Any("response", websiteSSLGetResp)) - if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'WebsiteSSLGet': %w", err) - } - // 更新证书 websiteSSLUploadReq := &onepanelsdk.WebsiteSSLUploadRequest{ SSLID: sslId, Type: "paste", - Description: websiteSSLGetResp.Data.Description, + Description: "upload from certimate", Certificate: certPEM, PrivateKey: privkeyPEM, } @@ -158,18 +151,11 @@ func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, pri case *onepanelsdk2.Client: { - // 获取证书详情 - websiteSSLGetResp, err := sdkClient.WebsiteSSLGetWithContext(ctx, sslId) - c.logger.Debug("sdk request 'WebsiteSSLGet'", slog.Int64("params.sslId", sslId), slog.Any("response", websiteSSLGetResp)) - if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'WebsiteSSLGet': %w", err) - } - // 更新证书 websiteSSLUploadReq := &onepanelsdk2.WebsiteSSLUploadRequest{ SSLID: sslId, Type: "paste", - Description: websiteSSLGetResp.Data.Description, + Description: "upload from certimate", Certificate: certPEM, PrivateKey: privkeyPEM, } @@ -228,7 +214,8 @@ func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM, privkey } } - if len(websiteSSLSearchResp.Data.Items) < int(websiteSSLSearchResp.Data.Total) { + if len(websiteSSLSearchResp.Data.Items) < searchWebsiteSSLPageSize || + searchWebsiteSSLPage*searchWebsiteSSLPageSize >= int(websiteSSLSearchResp.Data.Total) { break } @@ -277,7 +264,8 @@ func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM, privkey } } - if len(websiteSSLSearchResp.Data.Items) < int(websiteSSLSearchResp.Data.Total) { + if len(websiteSSLSearchResp.Data.Items) < searchWebsiteSSLPageSize || + searchWebsiteSSLPage*searchWebsiteSSLPageSize >= int(websiteSSLSearchResp.Data.Total) { break } diff --git a/pkg/sdk3rd/1panel/api_website_ssl_get.go b/pkg/sdk3rd/1panel/api_website_ssl_get.go deleted file mode 100644 index b1540a8b..00000000 --- a/pkg/sdk3rd/1panel/api_website_ssl_get.go +++ /dev/null @@ -1,50 +0,0 @@ -package onepanel - -import ( - "context" - "fmt" - "net/http" -) - -type WebsiteSSLGetResponse struct { - sdkResponseBase - - Data *struct { - ID int64 `json:"id"` - Provider string `json:"provider"` - Description string `json:"description"` - PrimaryDomain string `json:"primaryDomain"` - Domains string `json:"domains"` - Type string `json:"type"` - Organization string `json:"organization"` - Status string `json:"status"` - StartDate string `json:"startDate"` - ExpireDate string `json:"expireDate"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` - } `json:"data,omitempty"` -} - -func (c *Client) WebsiteSSLGet(sslId int64) (*WebsiteSSLGetResponse, error) { - return c.WebsiteSSLGetWithContext(context.Background(), sslId) -} - -func (c *Client) WebsiteSSLGetWithContext(ctx context.Context, sslId int64) (*WebsiteSSLGetResponse, error) { - if sslId == 0 { - return nil, fmt.Errorf("sdkerr: bad request: unset sslId") - } - - httpreq, err := c.newRequest(http.MethodGet, fmt.Sprintf("/websites/ssl/%d", sslId)) - if err != nil { - return nil, err - } else { - httpreq.SetContext(ctx) - } - - result := &WebsiteSSLGetResponse{} - if _, err := c.doRequestWithResult(httpreq, result); err != nil { - return result, err - } - - return result, nil -} diff --git a/pkg/sdk3rd/1panel/v2/api_website_ssl_get.go b/pkg/sdk3rd/1panel/v2/api_website_ssl_get.go deleted file mode 100644 index efdc0ed6..00000000 --- a/pkg/sdk3rd/1panel/v2/api_website_ssl_get.go +++ /dev/null @@ -1,50 +0,0 @@ -package v2 - -import ( - "context" - "fmt" - "net/http" -) - -type WebsiteSSLGetResponse struct { - sdkResponseBase - - Data *struct { - ID int64 `json:"id"` - Provider string `json:"provider"` - Description string `json:"description"` - PrimaryDomain string `json:"primaryDomain"` - Domains string `json:"domains"` - Type string `json:"type"` - Organization string `json:"organization"` - Status string `json:"status"` - StartDate string `json:"startDate"` - ExpireDate string `json:"expireDate"` - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` - } `json:"data,omitempty"` -} - -func (c *Client) WebsiteSSLGet(sslId int64) (*WebsiteSSLGetResponse, error) { - return c.WebsiteSSLGetWithContext(context.Background(), sslId) -} - -func (c *Client) WebsiteSSLGetWithContext(ctx context.Context, sslId int64) (*WebsiteSSLGetResponse, error) { - if sslId == 0 { - return nil, fmt.Errorf("sdkerr: bad request: unset sslId") - } - - httpreq, err := c.newRequest(http.MethodGet, fmt.Sprintf("/websites/ssl/%d", sslId)) - if err != nil { - return nil, err - } else { - httpreq.SetContext(ctx) - } - - result := &WebsiteSSLGetResponse{} - if _, err := c.doRequestWithResult(httpreq, result); err != nil { - return result, err - } - - return result, nil -} From da4c4ee7aa99014f5b259f9c480217b67c036c9b Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 19 Jun 2026 09:45:24 +0800 Subject: [PATCH 9/9] fix(provider): adapt to 1panel v2.2.0+ --- pkg/core/deployer/providers/1panel/1panel.go | 11 ++-- pkg/sdk3rd/1panel/api_website_get.go | 22 +------- pkg/sdk3rd/1panel/api_website_https_get.go | 9 +--- pkg/sdk3rd/1panel/api_website_search.go | 17 +------ pkg/sdk3rd/1panel/api_website_ssl_search.go | 13 +---- pkg/sdk3rd/1panel/models.go | 51 +++++++++++++++++++ pkg/sdk3rd/1panel/v2/api_website_get.go | 22 +------- pkg/sdk3rd/1panel/v2/api_website_https_get.go | 10 +--- pkg/sdk3rd/1panel/v2/api_website_search.go | 30 ++++------- .../1panel/v2/api_website_ssl_search.go | 13 +---- pkg/sdk3rd/1panel/v2/models.go | 21 ++++++++ 11 files changed, 94 insertions(+), 125 deletions(-) create mode 100644 pkg/sdk3rd/1panel/models.go create mode 100644 pkg/sdk3rd/1panel/v2/models.go diff --git a/pkg/core/deployer/providers/1panel/1panel.go b/pkg/core/deployer/providers/1panel/1panel.go index 7d481913..edcaaeb3 100644 --- a/pkg/core/deployer/providers/1panel/1panel.go +++ b/pkg/core/deployer/providers/1panel/1panel.go @@ -1,6 +1,7 @@ package onepanel import ( + "cmp" "context" "crypto/tls" "errors" @@ -339,14 +340,11 @@ func (d *Deployer) updateWebsiteCertificate(ctx context.Context, websiteId int64 Type: "existed", WebsiteSSLID: websiteSSLId, Enable: true, - HttpConfig: websiteHttpsGetResp.Data.HttpConfig, + HttpConfig: cmp.Or(websiteHttpsGetResp.Data.HttpConfig, "HTTPToHTTPS"), SSLProtocol: websiteHttpsGetResp.Data.SSLProtocol, Algorithm: websiteHttpsGetResp.Data.Algorithm, Hsts: websiteHttpsGetResp.Data.Hsts, } - if websiteHttpsPostReq.HttpConfig == "" { - websiteHttpsPostReq.HttpConfig = "HTTPToHTTPS" - } websiteHttpsPostResp, err := sdkClient.WebsiteHttpsPostWithContext(ctx, websiteId, websiteHttpsPostReq) d.logger.Debug("sdk request 'WebsiteHttpsPost'", slog.Int64("params.websiteId", websiteId), slog.Any("request", websiteHttpsPostReq), slog.Any("response", websiteHttpsPostResp)) if err != nil { @@ -373,15 +371,12 @@ func (d *Deployer) updateWebsiteCertificate(ctx context.Context, websiteId int64 Type: "existed", WebsiteSSLID: websiteSSLId, Enable: true, - HttpConfig: websiteHttpsGetResp.Data.HttpConfig, + HttpConfig: cmp.Or(websiteHttpsGetResp.Data.HttpConfig, "HTTPToHTTPS"), SSLProtocol: websiteHttpsGetResp.Data.SSLProtocol, Algorithm: websiteHttpsGetResp.Data.Algorithm, Hsts: websiteHttpsGetResp.Data.Hsts, Http3: websiteHttpsGetResp.Data.Http3, } - if websiteHttpsPostReq.HttpConfig == "" { - websiteHttpsPostReq.HttpConfig = "HTTPToHTTPS" - } websiteHttpsPostResp, err := sdkClient.WebsiteHttpsPostWithContext(ctx, websiteId, websiteHttpsPostReq) d.logger.Debug("sdk request 'WebsiteHttpsPost'", slog.Int64("params.websiteId", websiteId), slog.Any("request", websiteHttpsPostReq), slog.Any("response", websiteHttpsPostResp)) if err != nil { diff --git a/pkg/sdk3rd/1panel/api_website_get.go b/pkg/sdk3rd/1panel/api_website_get.go index cd67ebb1..c86cc900 100644 --- a/pkg/sdk3rd/1panel/api_website_get.go +++ b/pkg/sdk3rd/1panel/api_website_get.go @@ -16,27 +16,7 @@ type WebsiteGetRequest struct { type WebsiteGetResponse struct { sdkResponseBase - Data *struct { - ID int64 `json:"id"` - Alias string `json:"alias"` - PrimaryDomain string `json:"primaryDomain"` - Protocol string `json:"protocol"` - Type string `json:"type"` - Status string `json:"status"` - SitePath string `json:"sitePath"` - Remark string `json:"remark"` - Domains []*struct { - ID int64 `json:"id"` - Domain string `json:"domain"` - Port int32 `json:"port"` - SSL bool `json:"ssl"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"domains"` - WebsiteSSLId int64 `json:"webSiteSSLId"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"data,omitempty"` + Data *WebsiteDetail `json:"data,omitempty"` } func (c *Client) WebsiteGet(websiteId int64) (*WebsiteGetResponse, error) { diff --git a/pkg/sdk3rd/1panel/api_website_https_get.go b/pkg/sdk3rd/1panel/api_website_https_get.go index 6db52d9b..94e7f4ea 100644 --- a/pkg/sdk3rd/1panel/api_website_https_get.go +++ b/pkg/sdk3rd/1panel/api_website_https_get.go @@ -9,14 +9,7 @@ import ( type WebsiteHttpsGetResponse struct { sdkResponseBase - Data *struct { - Enable bool `json:"enable"` - WebsiteSSLID int64 `json:"websiteSSLId"` - HttpConfig string `json:"httpConfig"` - SSLProtocol []string `json:"SSLProtocol"` - Algorithm string `json:"algorithm"` - Hsts bool `json:"hsts"` - } `json:"data,omitempty"` + Data *WebsiteHTTPSConfig `json:"data,omitempty"` } func (c *Client) WebsiteHttpsGet(websiteId int64) (*WebsiteHttpsGetResponse, error) { diff --git a/pkg/sdk3rd/1panel/api_website_search.go b/pkg/sdk3rd/1panel/api_website_search.go index 9112fa16..821e5327 100644 --- a/pkg/sdk3rd/1panel/api_website_search.go +++ b/pkg/sdk3rd/1panel/api_website_search.go @@ -18,21 +18,8 @@ type WebsiteSearchResponse struct { sdkResponseBase Data *struct { - Items []*struct { - ID int64 `json:"id"` - Alias string `json:"alias"` - PrimaryDomain string `json:"primaryDomain"` - Protocol string `json:"protocol"` - Type string `json:"type"` - Status string `json:"status"` - SitePath string `json:"sitePath"` - Remark string `json:"remark"` - SSLStatus string `json:"sslStatus"` - SSLExpireDate string `json:"sslExpireDate"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"items"` - Total int32 `json:"total"` + Items []*Website `json:"items"` + Total int32 `json:"total"` } `json:"data,omitempty"` } diff --git a/pkg/sdk3rd/1panel/api_website_ssl_search.go b/pkg/sdk3rd/1panel/api_website_ssl_search.go index 3dc754f8..3c59c191 100644 --- a/pkg/sdk3rd/1panel/api_website_ssl_search.go +++ b/pkg/sdk3rd/1panel/api_website_ssl_search.go @@ -15,17 +15,8 @@ type WebsiteSSLSearchResponse struct { sdkResponseBase Data *struct { - Items []*struct { - ID int64 `json:"id"` - PEM string `json:"pem"` - PrivateKey string `json:"privateKey"` - Domains string `json:"domains"` - Description string `json:"description"` - Status string `json:"status"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"items"` - Total int32 `json:"total"` + Items []*SSLCertificate `json:"items"` + Total int32 `json:"total"` } `json:"data,omitempty"` } diff --git a/pkg/sdk3rd/1panel/models.go b/pkg/sdk3rd/1panel/models.go new file mode 100644 index 00000000..eba3bdaa --- /dev/null +++ b/pkg/sdk3rd/1panel/models.go @@ -0,0 +1,51 @@ +package onepanel + +type Website struct { + ID int64 `json:"id"` + Alias string `json:"alias"` + PrimaryDomain string `json:"primaryDomain"` + Protocol string `json:"protocol"` + Type string `json:"type"` + Status string `json:"status"` + SitePath string `json:"sitePath"` + Remark string `json:"remark"` + SSLStatus string `json:"sslStatus,omitempty"` + SSLExpireDate string `json:"sslExpireDate,omitempty"` + WebsiteSSLID int64 `json:"webSiteSSLId,omitempty"` + UpdatedAt string `json:"updatedAt"` + CreatedAt string `json:"createdAt"` +} + +type WebsiteDetail struct { + Website + Domains []*WebsiteDomainConfig `json:"domains"` +} + +type WebsiteDomainConfig struct { + ID int64 `json:"id"` + Domain string `json:"domain"` + Port int32 `json:"port"` + SSL bool `json:"ssl"` + UpdatedAt string `json:"updatedAt"` + CreatedAt string `json:"createdAt"` +} + +type WebsiteHTTPSConfig struct { + Enable bool `json:"enable"` + WebsiteSSLID int64 `json:"websiteSSLId"` + HttpConfig string `json:"httpConfig"` + SSLProtocol []string `json:"SSLProtocol"` + Algorithm string `json:"algorithm"` + Hsts bool `json:"hsts"` +} + +type SSLCertificate struct { + ID int64 `json:"id"` + PEM string `json:"pem"` + PrivateKey string `json:"privateKey"` + Domains string `json:"domains"` + Description string `json:"description"` + Status string `json:"status"` + UpdatedAt string `json:"updatedAt"` + CreatedAt string `json:"createdAt"` +} diff --git a/pkg/sdk3rd/1panel/v2/api_website_get.go b/pkg/sdk3rd/1panel/v2/api_website_get.go index 9574ca59..a4e9f952 100644 --- a/pkg/sdk3rd/1panel/v2/api_website_get.go +++ b/pkg/sdk3rd/1panel/v2/api_website_get.go @@ -16,27 +16,7 @@ type WebsiteGetRequest struct { type WebsiteGetResponse struct { sdkResponseBase - Data *struct { - ID int64 `json:"id"` - Alias string `json:"alias"` - PrimaryDomain string `json:"primaryDomain"` - Protocol string `json:"protocol"` - Type string `json:"type"` - Status string `json:"status"` - SitePath string `json:"sitePath"` - Remark string `json:"remark"` - Domains []*struct { - ID int64 `json:"id"` - Domain string `json:"domain"` - Port int32 `json:"port"` - SSL bool `json:"ssl"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"domains,omitempty"` - WebsiteSSLId int64 `json:"webSiteSSLId"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"data,omitempty"` + Data *WebsiteDetail `json:"data,omitempty"` } func (c *Client) WebsiteGet(websiteId int64) (*WebsiteGetResponse, error) { diff --git a/pkg/sdk3rd/1panel/v2/api_website_https_get.go b/pkg/sdk3rd/1panel/v2/api_website_https_get.go index 30261c98..59b2e9a2 100644 --- a/pkg/sdk3rd/1panel/v2/api_website_https_get.go +++ b/pkg/sdk3rd/1panel/v2/api_website_https_get.go @@ -9,15 +9,7 @@ import ( type WebsiteHttpsGetResponse struct { sdkResponseBase - Data *struct { - Enable bool `json:"enable"` - HttpConfig string `json:"httpConfig"` - WebsiteSSLID int64 `json:"websiteSSLId"` - SSLProtocol []string `json:"SSLProtocol"` - Algorithm string `json:"algorithm"` - Hsts bool `json:"hsts"` - Http3 bool `json:"http3"` - } `json:"data,omitempty"` + Data *WebsiteHTTPSConfig `json:"data,omitempty"` } func (c *Client) WebsiteHttpsGet(websiteId int64) (*WebsiteHttpsGetResponse, error) { diff --git a/pkg/sdk3rd/1panel/v2/api_website_search.go b/pkg/sdk3rd/1panel/v2/api_website_search.go index 00d7196c..6943b97f 100644 --- a/pkg/sdk3rd/1panel/v2/api_website_search.go +++ b/pkg/sdk3rd/1panel/v2/api_website_search.go @@ -6,33 +6,21 @@ import ( ) type WebsiteSearchRequest struct { - Name string `json:"name"` - Type string `json:"type"` - Order string `json:"order"` - OrderBy string `json:"orderBy"` - Page int32 `json:"page"` - PageSize int32 `json:"pageSize"` + WebsiteGroupId int64 `json:"websiteGroupId"` + Name string `json:"name"` + Type string `json:"type"` + Order string `json:"order"` + OrderBy string `json:"orderBy"` + Page int32 `json:"page"` + PageSize int32 `json:"pageSize"` } type WebsiteSearchResponse struct { sdkResponseBase Data *struct { - Items []*struct { - ID int64 `json:"id"` - Alias string `json:"alias"` - PrimaryDomain string `json:"primaryDomain"` - Protocol string `json:"protocol"` - Type string `json:"type"` - Status string `json:"status"` - SitePath string `json:"sitePath"` - Remark string `json:"remark"` - SSLStatus string `json:"sslStatus"` - SSLExpireDate string `json:"sslExpireDate"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"items"` - Total int32 `json:"total"` + Items []*Website `json:"items"` + Total int32 `json:"total"` } `json:"data,omitempty"` } diff --git a/pkg/sdk3rd/1panel/v2/api_website_ssl_search.go b/pkg/sdk3rd/1panel/v2/api_website_ssl_search.go index ff9a3ccc..fda36fe9 100644 --- a/pkg/sdk3rd/1panel/v2/api_website_ssl_search.go +++ b/pkg/sdk3rd/1panel/v2/api_website_ssl_search.go @@ -17,17 +17,8 @@ type WebsiteSSLSearchResponse struct { sdkResponseBase Data *struct { - Items []*struct { - ID int64 `json:"id"` - PEM string `json:"pem"` - PrivateKey string `json:"privateKey"` - Domains string `json:"domains"` - Description string `json:"description"` - Status string `json:"status"` - UpdatedAt string `json:"updatedAt"` - CreatedAt string `json:"createdAt"` - } `json:"items"` - Total int32 `json:"total"` + Items []*SSLCertificate `json:"items"` + Total int32 `json:"total"` } `json:"data,omitempty"` } diff --git a/pkg/sdk3rd/1panel/v2/models.go b/pkg/sdk3rd/1panel/v2/models.go new file mode 100644 index 00000000..69b50032 --- /dev/null +++ b/pkg/sdk3rd/1panel/v2/models.go @@ -0,0 +1,21 @@ +package v2 + +import ( + v1 "github.com/certimate-go/certimate/pkg/sdk3rd/1panel" +) + +type Website v1.Website + +type WebsiteDetail struct { + Website + Domains []*WebsiteDomainConfig `json:"domains"` +} + +type WebsiteDomainConfig v1.WebsiteDomainConfig + +type WebsiteHTTPSConfig struct { + v1.WebsiteHTTPSConfig + Http3 bool `json:"http3"` +} + +type SSLCertificate v1.SSLCertificate