diff --git a/go.mod b/go.mod
index b7f6e5e60..a1c3eb070 100644
--- a/go.mod
+++ b/go.mod
@@ -43,6 +43,7 @@ require (
github.com/baidubce/bce-sdk-go v0.9.270
github.com/byteplus-sdk/byteplus-go-sdk-v2 v1.0.71
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.71
+ github.com/fsnotify/fsnotify v1.10.1
github.com/go-acme/lego/v5 v5.2.2
github.com/go-cmd/cmd v1.4.3
github.com/go-resty/resty/v2 v2.17.2
@@ -63,7 +64,6 @@ require (
github.com/pocketbase/pocketbase v0.39.6
github.com/povsister/scp v0.0.0-20250701154629-777cf82de5df
github.com/pquerna/otp v1.5.0
- github.com/qiniu/go-sdk/v7 v7.26.15
github.com/samber/lo v1.53.0
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
@@ -122,9 +122,6 @@ require (
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-openapi/jsonreference v0.21.5 // indirect
github.com/go-openapi/swag v0.25.5 // indirect
- github.com/go-playground/locales v0.14.1 // indirect
- github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.30.2 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
@@ -134,7 +131,6 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
- github.com/leodido/go-urn v1.4.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/namedotcom/go/v4 v4.0.2 // indirect
@@ -146,8 +142,6 @@ require (
github.com/peterhellberg/link v1.2.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/qiniu/dyn v1.3.0 // indirect
- github.com/qiniu/x v1.17.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/stretchr/objx v0.5.3 // indirect
@@ -174,7 +168,6 @@ require (
cloud.google.com/go/auth v0.20.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
- github.com/BurntSushi/toml v1.6.0 // indirect
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
@@ -204,7 +197,6 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.19.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
- github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/ganigeorgiev/fexpr v0.5.0 // indirect
github.com/go-acme/alidns-20150109/v5 v5.4.1 // indirect
diff --git a/go.sum b/go.sum
index 7f097ce46..96d0fe879 100644
--- a/go.sum
+++ b/go.sum
@@ -66,8 +66,6 @@ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mo
github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2 h1:RHK7bS+HQMslb1sZpAokUt+zTVmue0hKSs2C791hhzU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
-github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/G-Core/gcorelabscdn-go v1.0.37 h1:IHqiSfnHp3tnuUSU1FIH5+3XepNnSsyJn0JoWgvUYL8=
@@ -417,17 +415,9 @@ github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lE
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
-github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
-github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
-github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
-github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
-github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
-github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ=
-github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc=
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -675,8 +665,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
-github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
-github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -831,13 +819,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/qiniu/dyn v1.3.0 h1:s+xPTeV0H8yikgM4ZMBc7Rrefam8UNI3asBlkaOQg5o=
-github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
-github.com/qiniu/go-sdk/v7 v7.26.15 h1:CaKVcP29ZnOp/pqE7U3RAZxqwL7CmtMTWlV1gAV71H0=
-github.com/qiniu/go-sdk/v7 v7.26.15/go.mod h1:ri7fGwbio0pRDFr8EK5TUpx0DbnpIMJ2bMSDxGWfCbk=
-github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
-github.com/qiniu/x v1.17.0 h1:OsyDKXzYp5vw9Hc7VAe4Cso1Sp50fLKGsBuDteyTevE=
-github.com/qiniu/x v1.17.0/go.mod h1:AiovSOCaRijaf3fj+0CBOpR1457pn24b0Vdb1JpwhII=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
diff --git a/internal/certmgmt/deployers/sp_qiniu_cdn.go b/internal/certmgmt/deployers/sp_qiniu_cdn.go
deleted file mode 100644
index fe71ce8b4..000000000
--- a/internal/certmgmt/deployers/sp_qiniu_cdn.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package deployers
-
-import (
- "fmt"
-
- "github.com/certimate-go/certimate/internal/domain"
- "github.com/certimate-go/certimate/pkg/core"
- dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/qiniu-cdn"
- xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
-)
-
-func init() {
- Registries.MustRegister(domain.DeploymentProviderTypeQiniuCDN, func(options *ProviderFactoryOptions) (core.Deployer, error) {
- credentials := domain.AccessConfigForQiniu{}
- if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
- return nil, fmt.Errorf("failed to populate provider access config: %w", err)
- }
-
- provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
- AccessKey: credentials.AccessKey,
- SecretKey: credentials.SecretKey,
- DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
- Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
- })
- return provider, err
- })
-}
diff --git a/internal/certmgmt/deployers/sp_qiniu_kodo.go b/internal/certmgmt/deployers/sp_qiniu_kodo.go
deleted file mode 100644
index a12e7e7bd..000000000
--- a/internal/certmgmt/deployers/sp_qiniu_kodo.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package deployers
-
-import (
- "fmt"
-
- "github.com/certimate-go/certimate/internal/domain"
- "github.com/certimate-go/certimate/pkg/core"
- dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/qiniu-kodo"
- xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
-)
-
-func init() {
- Registries.MustRegister(domain.DeploymentProviderTypeQiniuKodo, func(options *ProviderFactoryOptions) (core.Deployer, error) {
- credentials := domain.AccessConfigForQiniu{}
- if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
- return nil, fmt.Errorf("failed to populate provider access config: %w", err)
- }
-
- provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
- AccessKey: credentials.AccessKey,
- SecretKey: credentials.SecretKey,
- Bucket: xmaps.GetString(options.ProviderExtendedConfig, "bucket"),
- Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
- })
- return provider, err
- })
-}
diff --git a/internal/certmgmt/deployers/sp_qiniu_pili.go b/internal/certmgmt/deployers/sp_qiniu_pili.go
deleted file mode 100644
index 4a5315e86..000000000
--- a/internal/certmgmt/deployers/sp_qiniu_pili.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package deployers
-
-import (
- "fmt"
-
- "github.com/certimate-go/certimate/internal/domain"
- "github.com/certimate-go/certimate/pkg/core"
- dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/qiniu-pili"
- xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
-)
-
-func init() {
- Registries.MustRegister(domain.DeploymentProviderTypeQiniuPili, func(options *ProviderFactoryOptions) (core.Deployer, error) {
- credentials := domain.AccessConfigForQiniu{}
- if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
- return nil, fmt.Errorf("failed to populate provider access config: %w", err)
- }
-
- provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
- AccessKey: credentials.AccessKey,
- SecretKey: credentials.SecretKey,
- Hub: xmaps.GetString(options.ProviderExtendedConfig, "hub"),
- DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
- Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
- })
- return provider, err
- })
-}
diff --git a/internal/certmgmt/deployers/sp_webhook.go b/internal/certmgmt/deployers/sp_webhook.go
new file mode 100644
index 000000000..d21181857
--- /dev/null
+++ b/internal/certmgmt/deployers/sp_webhook.go
@@ -0,0 +1,51 @@
+package deployers
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/certimate-go/certimate/internal/domain"
+ "github.com/certimate-go/certimate/pkg/core"
+ dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/webhook"
+ xhttp "github.com/certimate-go/certimate/pkg/utils/http"
+ xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
+)
+
+func init() {
+ Registries.MustRegister(domain.DeploymentProviderTypeWebhook, func(options *ProviderFactoryOptions) (core.Deployer, error) {
+ credentials := domain.AccessConfigForWebhook{}
+ if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ mergedHeaders := make(map[string]string)
+ if defaultHeadersString := credentials.HeadersString; defaultHeadersString != "" {
+ h, err := xhttp.ParseHeaders(defaultHeadersString)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
+ }
+ for key := range h {
+ mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
+ }
+ }
+ if extendedHeadersString := xmaps.GetString(options.ProviderExtendedConfig, "headers"); extendedHeadersString != "" {
+ h, err := xhttp.ParseHeaders(extendedHeadersString)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
+ }
+ for key := range h {
+ mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
+ }
+ }
+
+ provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
+ WebhookUrl: credentials.Url,
+ WebhookData: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", credentials.DataString),
+ Method: credentials.Method,
+ Headers: mergedHeaders,
+ Timeout: xmaps.GetInt(options.ProviderExtendedConfig, "timeout"),
+ AllowInsecureConnections: credentials.AllowInsecureConnections,
+ })
+ return provider, err
+ })
+}
diff --git a/pkg/core/certmgr/providers/qiniu-sslcert/qiniu_sslcert.go b/pkg/core/certmgr/providers/qiniu-sslcert/qiniu_sslcert.go
deleted file mode 100644
index 5f4d566d3..000000000
--- a/pkg/core/certmgr/providers/qiniu-sslcert/qiniu_sslcert.go
+++ /dev/null
@@ -1,170 +0,0 @@
-package qiniusslcert
-
-import (
- "context"
- "crypto/x509"
- "fmt"
- "log/slog"
- "slices"
- "strings"
- "time"
-
- "github.com/qiniu/go-sdk/v7/auth"
-
- "github.com/certimate-go/certimate/pkg/core"
- qiniusdk "github.com/certimate-go/certimate/pkg/sdk3rd/qiniu"
- xcert "github.com/certimate-go/certimate/pkg/utils/cert"
-)
-
-type (
- Provider = core.Certmgr
- UploadResult = core.CertmgrUploadResult
- ReplaceResult = core.CertmgrReplaceResult
-)
-
-type CertmgrConfig struct {
- // 七牛云 AccessKey。
- AccessKey string `json:"accessKey"`
- // 七牛云 SecretKey。
- SecretKey string `json:"secretKey"`
-}
-
-type Certmgr struct {
- config *CertmgrConfig
- logger *slog.Logger
- sdkClient *qiniusdk.SslCertManager
-}
-
-var _ Provider = (*Certmgr)(nil)
-
-func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
- if config == nil {
- return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
- }
-
- client, err := createSDKClient(config.AccessKey, config.SecretKey)
- if err != nil {
- return nil, fmt.Errorf("could not create client: %w", err)
- }
-
- return &Certmgr{
- config: config,
- logger: slog.Default(),
- sdkClient: client,
- }, nil
-}
-
-func (c *Certmgr) SetLogger(logger *slog.Logger) {
- if logger == nil {
- c.logger = slog.New(slog.DiscardHandler)
- } else {
- c.logger = logger
- }
-}
-
-func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
- // 解析证书内容
- certX509, err := xcert.ParseCertificateFromPEM(certPEM)
- if err != nil {
- return nil, err
- }
-
- // 生成新证书名(需符合七牛云命名规则)
- certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
-
- // 查询已有证书,避免重复上传
- getSslCertListMarker := ""
- for {
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- default:
- }
-
- getSslCertListResp, err := c.sdkClient.GetSslCertList(ctx, getSslCertListMarker, 200)
- c.logger.Debug("sdk request 'sslcert.GetList'", slog.Any("params.marker", getSslCertListMarker), slog.Any("response", getSslCertListResp))
- if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'sslcert.GetList': %w", err)
- }
-
- for _, sslItem := range getSslCertListResp.Certs {
- // 对比证书通用名称
- if !strings.EqualFold(certX509.Subject.CommonName, sslItem.CommonName) {
- continue
- }
-
- // 对比证书备用名称
- if !slices.Equal(certX509.DNSNames, sslItem.DnsNames) {
- continue
- }
-
- // 对比证书有效期
- if certX509.NotBefore.Unix() != sslItem.NotBefore {
- continue
- } else if certX509.NotAfter.Unix() != sslItem.NotAfter {
- continue
- }
-
- // 对比证书公钥算法
- switch certX509.PublicKeyAlgorithm {
- case x509.RSA:
- if !strings.EqualFold(sslItem.Encrypt, "RSA") {
- continue
- }
- case x509.ECDSA:
- if !strings.EqualFold(sslItem.Encrypt, "ECDSA") {
- continue
- }
- case x509.Ed25519:
- if !strings.EqualFold(sslItem.Encrypt, "Ed25519") {
- continue
- }
- default:
- continue
- }
-
- // 如果以上信息都一致,则视为已存在相同证书,直接返回
- c.logger.Info("ssl certificate already exists")
- return &UploadResult{
- CertId: sslItem.CertID,
- CertName: sslItem.Name,
- }, nil
- }
-
- if len(getSslCertListResp.Certs) == 0 || getSslCertListResp.Marker == "" {
- break
- }
-
- getSslCertListMarker = getSslCertListResp.Marker
- }
-
- // 上传新证书
- // REF: https://developer.qiniu.com/fusion/8593/interface-related-certificate
- uploadSslCertResp, err := c.sdkClient.UploadSslCert(ctx, certName, certX509.Subject.CommonName, certPEM, privkeyPEM)
- c.logger.Debug("sdk request 'sslcert.Upload'", slog.Any("response", uploadSslCertResp))
- if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'sslcert.Upload': %w", err)
- }
-
- return &UploadResult{
- CertId: uploadSslCertResp.CertID,
- CertName: certName,
- }, nil
-}
-
-func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
- return nil, core.ErrUnsupported
-}
-
-func createSDKClient(accessKey, secretKey string) (*qiniusdk.SslCertManager, error) {
- if secretKey == "" {
- return nil, fmt.Errorf("qiniu: invalid access key")
- }
- if secretKey == "" {
- return nil, fmt.Errorf("qiniu: invalid secret key")
- }
-
- credential := auth.New(accessKey, secretKey)
- client := qiniusdk.NewSslCertManager(credential)
- return client, nil
-}
diff --git a/pkg/core/certmgr/providers/qiniu-sslcert/qiniu_sslcert_test.go b/pkg/core/certmgr/providers/qiniu-sslcert/qiniu_sslcert_test.go
deleted file mode 100644
index 966773112..000000000
--- a/pkg/core/certmgr/providers/qiniu-sslcert/qiniu_sslcert_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package qiniusslcert_test
-
-import (
- "testing"
-
- impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/qiniu-sslcert"
- tester "github.com/certimate-go/certimate/pkg/core/certmgr/testing"
-)
-
-var (
- fp = tester.Args("QINIUSSLCERT_")
- fTestCertPath string
- fTestKeyPath string
- fAccessKey string
- fSecretKey string
-)
-
-func init() {
- fp.DefineString(&fTestCertPath, "TESTCERTPATH")
- fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
- fp.DefineString(&fAccessKey, "ACCESSKEY")
- fp.DefineString(&fSecretKey, "SECRETKEY")
-}
-
-/*
-Shell command to run this test:
-
- go test -v ./qiniu_sslcert_test.go -args \
- --QINIUSSLCERT_TESTCERTPATH="/path/to/your-test-cert.pem" \
- --QINIUSSLCERT_TESTKEYPATH="/path/to/your-test-key.pem" \
- --QINIUSSLCERT_ACCESSKEY="your-access-key" \
- --QINIUSSLCERT_SECRETKEY="your-secret-key"
-*/
-func TestProvider(t *testing.T) {
- fp.Parse()
-
- t.Run("Upload", func(t *testing.T) {
- provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
- AccessKey: fAccessKey,
- SecretKey: fSecretKey,
- })
- if err != nil {
- t.Errorf("err: %+v", err)
- return
- }
-
- tester.TestUpload(t, provider, tester.TestUploadArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
- })
-}
diff --git a/pkg/core/deployer/providers/qiniu-cdn/consts.go b/pkg/core/deployer/providers/qiniu-cdn/consts.go
deleted file mode 100644
index a4bbfb19e..000000000
--- a/pkg/core/deployer/providers/qiniu-cdn/consts.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package qiniucdn
-
-const (
- // 匹配模式:精确匹配。
- DOMAIN_MATCH_PATTERN_EXACT = "exact"
- // 匹配模式:通配符匹配。
- DOMAIN_MATCH_PATTERN_WILDCARD = "wildcard"
- // 匹配模式:证书 SAN 匹配。
- DOMAIN_MATCH_PATTERN_CERTSAN = "certsan"
-)
diff --git a/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go b/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go
deleted file mode 100644
index 14b0816c8..000000000
--- a/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go
+++ /dev/null
@@ -1,231 +0,0 @@
-package qiniucdn
-
-import (
- "context"
- "fmt"
- "log/slog"
- "strings"
-
- "github.com/qiniu/go-sdk/v7/auth"
- "github.com/samber/lo"
-
- "github.com/certimate-go/certimate/pkg/core"
- cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/qiniu-sslcert"
- qiniusdk "github.com/certimate-go/certimate/pkg/sdk3rd/qiniu"
- xcerthostname "github.com/certimate-go/certimate/pkg/utils/cert/hostname"
- xloop "github.com/certimate-go/certimate/pkg/utils/loop"
-)
-
-type (
- Provider = core.Deployer
- DeployResult = core.DeployerDeployResult
-)
-
-type DeployerConfig struct {
- // 七牛云 AccessKey。
- AccessKey string `json:"accessKey"`
- // 七牛云 SecretKey。
- SecretKey string `json:"secretKey"`
- // 域名匹配模式。
- // 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
- DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
- // 加速域名(支持泛域名)。
- Domain string `json:"domain"`
-}
-
-type Deployer struct {
- config *DeployerConfig
- logger *slog.Logger
- sdkClient *qiniusdk.CdnManager
- sdkCertmgr core.Certmgr
-}
-
-var _ Provider = (*Deployer)(nil)
-
-func NewDeployer(config *DeployerConfig) (*Deployer, error) {
- if config == nil {
- return nil, fmt.Errorf("the configuration of the deployer provider is nil")
- }
-
- client := qiniusdk.NewCdnManager(auth.New(config.AccessKey, config.SecretKey))
-
- pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
- AccessKey: config.AccessKey,
- SecretKey: config.SecretKey,
- })
- if err != nil {
- return nil, fmt.Errorf("could not create certmgr: %w", err)
- }
-
- return &Deployer{
- config: config,
- logger: slog.Default(),
- sdkClient: client,
- sdkCertmgr: pcertmgr,
- }, nil
-}
-
-func (d *Deployer) SetLogger(logger *slog.Logger) {
- if logger == nil {
- d.logger = slog.New(slog.DiscardHandler)
- } else {
- d.logger = logger
- }
-
- d.sdkCertmgr.SetLogger(logger)
-}
-
-func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
- // 上传证书
- upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
- if err != nil {
- return nil, fmt.Errorf("failed to upload certificate file: %w", err)
- } else {
- d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
- }
-
- // 获取待部署的域名列表
- var domains []string
- switch d.config.DomainMatchPattern {
- case "", DOMAIN_MATCH_PATTERN_EXACT:
- {
- domain := normalizeDomain(d.config.Domain)
- if domain == "" {
- return nil, fmt.Errorf("config `domain` is required")
- }
-
- domains = []string{domain}
- }
-
- case DOMAIN_MATCH_PATTERN_WILDCARD:
- {
- if d.config.Domain == "" {
- return nil, fmt.Errorf("config `domain` is required")
- }
-
- if strings.HasPrefix(d.config.Domain, "*.") {
- domainCandidates, err := d.getAllDomains(ctx)
- if err != nil {
- return nil, err
- }
-
- domains = lo.Filter(domainCandidates, func(domain string, _ int) bool {
- return xcerthostname.IsMatch(d.config.Domain, domain)
- })
- if len(domains) == 0 {
- return nil, fmt.Errorf("could not find any domains matched by wildcard")
- }
- } else {
- domains = []string{d.config.Domain}
- }
- }
-
- case DOMAIN_MATCH_PATTERN_CERTSAN:
- {
- domainCandidates, err := d.getAllDomains(ctx)
- if err != nil {
- return nil, err
- }
-
- domains = lo.Filter(domainCandidates, func(domain string, _ int) bool {
- return xcerthostname.IsMatchByCertificatePEM(certPEM, domain)
- })
- if len(domains) == 0 {
- return nil, fmt.Errorf("could not find any domains matched by certificate")
- }
- }
-
- default:
- return nil, fmt.Errorf("unsupported domain match pattern: '%s'", d.config.DomainMatchPattern)
- }
-
- // 批量更新域名证书
- if len(domains) == 0 {
- d.logger.Info("no cdn domains to deploy")
- } else {
- d.logger.Info("found cdn domains to deploy", slog.Any("domains", domains))
-
- if err := xloop.ForRangeAllWithContext(ctx, domains, func(ctx context.Context, domain string, _ int) error {
- return d.updateDomainCertificate(ctx, domain, upres.CertId)
- }); err != nil {
- return nil, err
- }
- }
-
- return &DeployResult{}, nil
-}
-
-func (d *Deployer) getAllDomains(ctx context.Context) ([]string, error) {
- domains := make([]string, 0)
-
- // 查询域名列表
- // REF: https://developer.qiniu.com/fusion/4246/the-domain-name
- getDomainListMarker := ""
- for {
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- default:
- }
-
- getDomainListResp, err := d.sdkClient.GetDomainList(ctx, getDomainListMarker, 100)
- d.logger.Debug("sdk request 'cdn.GetDomainList'", slog.String("params.marker", getDomainListMarker), slog.Any("response", getDomainListResp))
- if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetDomainList': %w", err)
- }
-
- ignoredStatuses := []string{"frozen", "offlined"}
- for _, domainItem := range getDomainListResp.Domains {
- if lo.Contains(ignoredStatuses, domainItem.OperatingState) {
- continue
- }
-
- domains = append(domains, domainItem.Name)
- }
-
- if len(getDomainListResp.Domains) == 0 || getDomainListResp.Marker == "" {
- break
- }
-
- getDomainListMarker = getDomainListResp.Marker
- }
-
- return domains, nil
-}
-
-func (d *Deployer) updateDomainCertificate(ctx context.Context, domain string, cloudCertId string) error {
- // 获取域名信息
- // REF: https://developer.qiniu.com/fusion/4246/the-domain-name
- getDomainInfoResp, err := d.sdkClient.GetDomainInfo(ctx, domain)
- d.logger.Debug("sdk request 'cdn.GetDomainInfo'", slog.String("params.domain", domain), slog.Any("response", getDomainInfoResp))
- if err != nil {
- return fmt.Errorf("failed to execute sdk request 'cdn.GetDomainInfo': %w", err)
- }
-
- // 判断域名是否已启用 HTTPS
- // 如果已启用,修改域名证书;否则,启用 HTTPS
- // REF: https://developer.qiniu.com/fusion/4246/the-domain-name
- if getDomainInfoResp.Https == nil || getDomainInfoResp.Https.CertID == "" {
- enableDomainHttpsResp, err := d.sdkClient.EnableDomainHttps(ctx, domain, cloudCertId, true, true)
- d.logger.Debug("sdk request 'cdn.EnableDomainHttps'", slog.String("params.domain", domain), slog.String("params.certId", cloudCertId), slog.Any("response", enableDomainHttpsResp))
- if err != nil {
- return fmt.Errorf("failed to execute sdk request 'cdn.EnableDomainHttps': %w", err)
- }
- } else if getDomainInfoResp.Https.CertID != cloudCertId {
- modifyDomainHttpsConfResp, err := d.sdkClient.ModifyDomainHttpsConf(ctx, domain, cloudCertId, getDomainInfoResp.Https.ForceHttps, getDomainInfoResp.Https.Http2Enable)
- d.logger.Debug("sdk request 'cdn.ModifyDomainHttpsConf'", slog.String("params.domain", domain), slog.String("params.certId", cloudCertId), slog.Any("response", modifyDomainHttpsConfResp))
- if err != nil {
- return fmt.Errorf("failed to execute sdk request 'cdn.ModifyDomainHttpsConf': %w", err)
- }
- }
-
- return nil
-}
-
-func normalizeDomain(domain string) string {
- // "*.example.com" → ".example.com",适配七牛云 CDN 的泛域名参数要求
- if strings.HasPrefix(domain, "*.") {
- return strings.TrimPrefix(domain, "*")
- }
- return domain
-}
diff --git a/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn_test.go b/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn_test.go
deleted file mode 100644
index 15a5f0e71..000000000
--- a/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package qiniucdn_test
-
-import (
- "testing"
-
- impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/qiniu-cdn"
- tester "github.com/certimate-go/certimate/pkg/core/deployer/testing"
-)
-
-var (
- fp = tester.Args("QINIUCDN_")
- fTestCertPath string
- fTestKeyPath string
- fAccessKey string
- fSecretKey string
- fDomain string
-)
-
-func init() {
- fp.DefineString(&fTestCertPath, "TESTCERTPATH")
- fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
- fp.DefineString(&fAccessKey, "ACCESSKEY")
- fp.DefineString(&fSecretKey, "SECRETKEY")
- fp.DefineString(&fDomain, "DOMAIN")
-}
-
-/*
-Shell command to run this test:
-
- go test -v ./qiniu_cdn_test.go -args \
- --QINIUCDN_TESTCERTPATH="/path/to/your-test-cert.pem" \
- --QINIUCDN_TESTKEYPATH="/path/to/your-test-key.pem" \
- --QINIUCDN_ACCESSKEY="your-access-key" \
- --QINIUCDN_SECRETKEY="your-secret-key" \
- --QINIUCDN_DOMAIN="example.com"
-*/
-func TestProvider(t *testing.T) {
- fp.Parse()
-
- t.Run("Deploy", func(t *testing.T) {
- provider, err := impl.NewDeployer(&impl.DeployerConfig{
- AccessKey: fAccessKey,
- SecretKey: fSecretKey,
- DomainMatchPattern: impl.DOMAIN_MATCH_PATTERN_EXACT,
- Domain: fDomain,
- })
- if err != nil {
- t.Errorf("err: %+v", err)
- return
- }
-
- tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
- })
-}
diff --git a/pkg/core/deployer/providers/qiniu-kodo/qiniu_kodo.go b/pkg/core/deployer/providers/qiniu-kodo/qiniu_kodo.go
deleted file mode 100644
index e4754f2ff..000000000
--- a/pkg/core/deployer/providers/qiniu-kodo/qiniu_kodo.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package qiniukodo
-
-import (
- "context"
- "fmt"
- "log/slog"
-
- "github.com/qiniu/go-sdk/v7/auth"
-
- "github.com/certimate-go/certimate/pkg/core"
- cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/qiniu-sslcert"
- qiniusdk "github.com/certimate-go/certimate/pkg/sdk3rd/qiniu"
-)
-
-type (
- Provider = core.Deployer
- DeployResult = core.DeployerDeployResult
-)
-
-type DeployerConfig struct {
- // 七牛云 AccessKey。
- AccessKey string `json:"accessKey"`
- // 七牛云 SecretKey。
- SecretKey string `json:"secretKey"`
- // 存储桶名。暂时无用。
- Bucket string `json:"bucket"`
- // 自定义域名(不支持泛域名)。
- Domain string `json:"domain"`
-}
-
-type Deployer struct {
- config *DeployerConfig
- logger *slog.Logger
- sdkClient *qiniusdk.KodoManager
- sdkCertmgr core.Certmgr
-}
-
-var _ Provider = (*Deployer)(nil)
-
-func NewDeployer(config *DeployerConfig) (*Deployer, error) {
- if config == nil {
- return nil, fmt.Errorf("the configuration of the deployer provider is nil")
- }
-
- client := qiniusdk.NewKodoManager(auth.New(config.AccessKey, config.SecretKey))
-
- pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
- AccessKey: config.AccessKey,
- SecretKey: config.SecretKey,
- })
- if err != nil {
- return nil, fmt.Errorf("could not create certmgr: %w", err)
- }
-
- return &Deployer{
- config: config,
- logger: slog.Default(),
- sdkClient: client,
- sdkCertmgr: pcertmgr,
- }, nil
-}
-
-func (d *Deployer) SetLogger(logger *slog.Logger) {
- if logger == nil {
- d.logger = slog.New(slog.DiscardHandler)
- } else {
- d.logger = logger
- }
-
- d.sdkCertmgr.SetLogger(logger)
-}
-
-func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
- if d.config.Domain == "" {
- return nil, fmt.Errorf("config `domain` is required")
- }
-
- // 上传证书
- upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
- if err != nil {
- return nil, fmt.Errorf("failed to upload certificate file: %w", err)
- } else {
- d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
- }
-
- // 绑定空间域名证书
- bindBucketCertResp, err := d.sdkClient.BindBucketCert(ctx, d.config.Domain, upres.CertId)
- d.logger.Debug("sdk request 'kodo.BindCert'", slog.String("params.domain", d.config.Domain), slog.String("params.certId", upres.CertId), slog.Any("response", bindBucketCertResp))
- if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'kodo.BindCert': %w", err)
- }
-
- return &DeployResult{}, nil
-}
diff --git a/pkg/core/deployer/providers/qiniu-kodo/qiniu_kodo_test.go b/pkg/core/deployer/providers/qiniu-kodo/qiniu_kodo_test.go
deleted file mode 100644
index cc514bff0..000000000
--- a/pkg/core/deployer/providers/qiniu-kodo/qiniu_kodo_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package qiniukodo_test
-
-import (
- "testing"
-
- impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/qiniu-kodo"
- tester "github.com/certimate-go/certimate/pkg/core/deployer/testing"
-)
-
-var (
- fp = tester.Args("QINIUKODO_")
- fTestCertPath string
- fTestKeyPath string
- fAccessKey string
- fSecretKey string
- fBucket string
- fDomain string
-)
-
-func init() {
- fp.DefineString(&fTestCertPath, "TESTCERTPATH")
- fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
- fp.DefineString(&fAccessKey, "ACCESSKEY")
- fp.DefineString(&fSecretKey, "SECRETKEY")
- fp.DefineString(&fBucket, "BUCKET")
- fp.DefineString(&fDomain, "DOMAIN")
-}
-
-/*
-Shell command to run this test:
-
- go test -v ./qiniu_kodo_test.go -args \
- --QINIUKODO_TESTCERTPATH="/path/to/your-test-cert.pem" \
- --QINIUKODO_TESTKEYPATH="/path/to/your-test-key.pem" \
- --QINIUKODO_ACCESSKEY="your-access-key" \
- --QINIUKODO_SECRETKEY="your-secret-key" \
- --QINIUKODO_BUCKET="your-bucket" \
- --QINIUKODO_DOMAIN="example.com"
-*/
-func TestProvider(t *testing.T) {
- fp.Parse()
-
- t.Run("Deploy", func(t *testing.T) {
- provider, err := impl.NewDeployer(&impl.DeployerConfig{
- AccessKey: fAccessKey,
- SecretKey: fSecretKey,
- Bucket: fBucket,
- Domain: fDomain,
- })
- if err != nil {
- t.Errorf("err: %+v", err)
- return
- }
-
- tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
- })
-}
diff --git a/pkg/core/deployer/providers/qiniu-pili/consts.go b/pkg/core/deployer/providers/qiniu-pili/consts.go
deleted file mode 100644
index 256a9beeb..000000000
--- a/pkg/core/deployer/providers/qiniu-pili/consts.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package qiniupili
-
-const (
- // 匹配模式:精确匹配。
- DOMAIN_MATCH_PATTERN_EXACT = "exact"
- // 匹配模式:证书 SAN 匹配。
- DOMAIN_MATCH_PATTERN_CERTSAN = "certsan"
-)
diff --git a/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go b/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go
deleted file mode 100644
index 3035c8725..000000000
--- a/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package qiniupili
-
-import (
- "context"
- "fmt"
- "log/slog"
-
- "github.com/qiniu/go-sdk/v7/pili"
- "github.com/samber/lo"
-
- "github.com/certimate-go/certimate/pkg/core"
- cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/qiniu-sslcert"
- xcerthostname "github.com/certimate-go/certimate/pkg/utils/cert/hostname"
- xloop "github.com/certimate-go/certimate/pkg/utils/loop"
-)
-
-type (
- Provider = core.Deployer
- DeployResult = core.DeployerDeployResult
-)
-
-type DeployerConfig struct {
- // 七牛云 AccessKey。
- AccessKey string `json:"accessKey"`
- // 七牛云 SecretKey。
- SecretKey string `json:"secretKey"`
- // 直播空间名。
- Hub string `json:"hub"`
- // 域名匹配模式。
- // 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
- DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
- // 直播流域名(不支持泛域名)。
- Domain string `json:"domain"`
-}
-
-type Deployer struct {
- config *DeployerConfig
- logger *slog.Logger
- sdkClient *pili.Manager
- sdkCertmgr core.Certmgr
-}
-
-var _ Provider = (*Deployer)(nil)
-
-func NewDeployer(config *DeployerConfig) (*Deployer, error) {
- if config == nil {
- return nil, fmt.Errorf("the configuration of the deployer provider is nil")
- }
-
- manager := pili.NewManager(pili.ManagerConfig{AccessKey: config.AccessKey, SecretKey: config.SecretKey})
-
- pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
- AccessKey: config.AccessKey,
- SecretKey: config.SecretKey,
- })
- if err != nil {
- return nil, fmt.Errorf("could not create certmgr: %w", err)
- }
-
- return &Deployer{
- config: config,
- logger: slog.Default(),
- sdkClient: manager,
- sdkCertmgr: pcertmgr,
- }, nil
-}
-
-func (d *Deployer) SetLogger(logger *slog.Logger) {
- if logger == nil {
- d.logger = slog.New(slog.DiscardHandler)
- } else {
- d.logger = logger
- }
-
- d.sdkCertmgr.SetLogger(logger)
-}
-
-func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
- if d.config.Domain == "" {
- return nil, fmt.Errorf("config `domain` is required")
- }
-
- // 上传证书
- upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
- if err != nil {
- return nil, fmt.Errorf("failed to upload certificate file: %w", err)
- } else {
- d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
- }
-
- // 获取待部署的域名列表
- var domains []string
- switch d.config.DomainMatchPattern {
- case "", DOMAIN_MATCH_PATTERN_EXACT:
- {
- if d.config.Domain == "" {
- return nil, fmt.Errorf("config `domain` is required")
- }
-
- domains = []string{d.config.Domain}
- }
-
- case DOMAIN_MATCH_PATTERN_CERTSAN:
- {
- domainCandidates, err := d.getAllDomainsByHub(ctx, d.config.Hub)
- if err != nil {
- return nil, err
- }
-
- domains = lo.Filter(domainCandidates, func(domain string, _ int) bool {
- return xcerthostname.IsMatchByCertificatePEM(certPEM, domain)
- })
- if len(domains) == 0 {
- return nil, fmt.Errorf("could not find any domains matched by certificate")
- }
- }
-
- default:
- return nil, fmt.Errorf("unsupported domain match pattern: '%s'", d.config.DomainMatchPattern)
- }
-
- // 批量更新域名证书
- if len(domains) == 0 {
- d.logger.Info("no pili domains to deploy")
- } else {
- d.logger.Info("found pili domains to deploy", slog.Any("domains", domains))
-
- if err := xloop.ForRangeAllWithContext(ctx, domains, func(ctx context.Context, domain string, _ int) error {
- return d.updateDomainCertificate(ctx, d.config.Hub, domain, upres.CertName)
- }); err != nil {
- return nil, err
- }
- }
-
- return &DeployResult{}, nil
-}
-
-func (d *Deployer) getAllDomainsByHub(ctx context.Context, hub string) ([]string, error) {
- domains := make([]string, 0)
-
- // 查询域名列表
- // REF: https://developer.qiniu.com/pili/9910/pili-service-sdk#6
- getDomainListReq := pili.GetDomainsListRequest{
- Hub: hub,
- }
- getDomainListResp, err := d.sdkClient.GetDomainsList(ctx, getDomainListReq)
- d.logger.Debug("sdk request 'pili.GetDomainsList'", slog.Any("request", getDomainListReq), slog.Any("response", getDomainListResp))
- if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'pili.GetDomainsList': %w", err)
- }
-
- for _, domainItem := range getDomainListResp.Domains {
- domains = append(domains, domainItem.Domain)
- }
-
- return domains, nil
-}
-
-func (d *Deployer) updateDomainCertificate(ctx context.Context, hub string, domain string, cloudCertName string) error {
- // 修改域名证书配置
- // REF: https://developer.qiniu.com/pili/9910/pili-service-sdk#6
- setDomainCertReq := pili.SetDomainCertRequest{
- Hub: hub,
- Domain: domain,
- CertName: cloudCertName,
- }
- err := d.sdkClient.SetDomainCert(ctx, setDomainCertReq)
- d.logger.Debug("sdk request 'pili.SetDomainCert'", slog.Any("request", setDomainCertReq))
- if err != nil {
- return fmt.Errorf("failed to execute sdk request 'pili.SetDomainCert': %w", err)
- }
-
- return nil
-}
diff --git a/pkg/core/deployer/providers/qiniu-pili/qiniu_pili_test.go b/pkg/core/deployer/providers/qiniu-pili/qiniu_pili_test.go
deleted file mode 100644
index a3f5484e5..000000000
--- a/pkg/core/deployer/providers/qiniu-pili/qiniu_pili_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package qiniupili_test
-
-import (
- "testing"
-
- impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/qiniu-pili"
- tester "github.com/certimate-go/certimate/pkg/core/deployer/testing"
-)
-
-var (
- fp = tester.Args("QINIUPILI_")
- fTestCertPath string
- fTestKeyPath string
- fAccessKey string
- fSecretKey string
- fHub string
- fDomain string
-)
-
-func init() {
- fp.DefineString(&fTestCertPath, "TESTCERTPATH")
- fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
- fp.DefineString(&fAccessKey, "ACCESSKEY")
- fp.DefineString(&fSecretKey, "SECRETKEY")
- fp.DefineString(&fHub, "HUB")
- fp.DefineString(&fDomain, "DOMAIN")
-}
-
-/*
-Shell command to run this test:
-
- go test -v ./qiniu_pili_test.go -args \
- --QINIUPILI_TESTCERTPATH="/path/to/your-test-cert.pem" \
- --QINIUPILI_TESTKEYPATH="/path/to/your-test-key.pem" \
- --QINIUPILI_ACCESSKEY="your-access-key" \
- --QINIUPILI_SECRETKEY="your-secret-key" \
- --QINIUPILI_HUB="your-hub-name" \
- --QINIUPILI_DOMAIN="example.com"
-*/
-func TestProvider(t *testing.T) {
- fp.Parse()
-
- t.Run("Deploy", func(t *testing.T) {
- provider, err := impl.NewDeployer(&impl.DeployerConfig{
- AccessKey: fAccessKey,
- SecretKey: fSecretKey,
- DomainMatchPattern: impl.DOMAIN_MATCH_PATTERN_EXACT,
- Domain: fDomain,
- })
- if err != nil {
- t.Errorf("err: %+v", err)
- return
- }
-
- tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
- })
-}
diff --git a/pkg/core/deployer/providers/webhook/webhook.go b/pkg/core/deployer/providers/webhook/webhook.go
new file mode 100644
index 000000000..638e39b0a
--- /dev/null
+++ b/pkg/core/deployer/providers/webhook/webhook.go
@@ -0,0 +1,226 @@
+package webhook
+
+import (
+ "context"
+ "crypto/tls"
+ "encoding/json"
+ "fmt"
+ "log/slog"
+ "mime"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/go-resty/resty/v2"
+
+ "github.com/certimate-go/certimate/pkg/core"
+ xcert "github.com/certimate-go/certimate/pkg/utils/cert"
+ xcertx509 "github.com/certimate-go/certimate/pkg/utils/cert/x509"
+ xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
+)
+
+type (
+ Provider = core.Deployer
+ DeployResult = core.DeployerDeployResult
+)
+
+type DeployerConfig struct {
+ // Webhook URL。
+ WebhookUrl string `json:"webhookUrl"`
+ // Webhook 回调数据(application/json 或 application/x-www-form-urlencoded 格式)。
+ WebhookData string `json:"webhookData,omitempty"`
+ // 请求谓词。
+ // 零值时默认值 "POST"。
+ Method string `json:"method,omitempty"`
+ // 请求标头。
+ Headers map[string]string `json:"headers,omitempty"`
+ // 请求超时(单位:秒)。
+ // 零值时默认值 30。
+ Timeout int `json:"timeout,omitempty"`
+ // 是否允许不安全的连接。
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+}
+
+type Deployer struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ httpClient *resty.Client
+}
+
+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")
+ }
+
+ client := resty.New().
+ SetTimeout(30 * time.Second).
+ SetRetryCount(3).
+ SetRetryWaitTime(5 * time.Second).
+ AddRetryCondition(func(resp *resty.Response, _ error) bool {
+ return resp == nil || resp.StatusCode() >= 500
+ })
+ if config.Timeout > 0 {
+ client.SetTimeout(time.Duration(config.Timeout) * time.Second)
+ }
+ if config.AllowInsecureConnections {
+ client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
+ }
+
+ return &Deployer{
+ config: config,
+ logger: slog.Default(),
+ httpClient: client,
+ }, nil
+}
+
+func (d *Deployer) SetLogger(logger *slog.Logger) {
+ if logger == nil {
+ d.logger = slog.New(slog.DiscardHandler)
+ } else {
+ d.logger = logger
+ }
+}
+
+func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
+ // 解析证书内容
+ certX509, err := xcert.ParseCertificateFromPEM(certPEM)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse x509: %w", err)
+ }
+
+ // 提取服务器证书和中间证书
+ serverCertPEM, issuerCertPEM, err := xcert.ExtractCertificatesFromPEM(certPEM)
+ if err != nil {
+ return nil, fmt.Errorf("failed to extract certs: %w", err)
+ }
+
+ // 处理 Webhook URL
+ webhookUrl, err := url.Parse(d.config.WebhookUrl)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse webhook url: %w", err)
+ } else if webhookUrl.Scheme != "http" && webhookUrl.Scheme != "https" {
+ return nil, fmt.Errorf("unsupported webhook url scheme '%s'", webhookUrl.Scheme)
+ }
+
+ // 处理 Webhook 请求谓词
+ webhookMethod := strings.ToUpper(d.config.Method)
+ if webhookMethod == "" {
+ webhookMethod = http.MethodPost
+ } else if !allowedMethods[webhookMethod] {
+ return nil, fmt.Errorf("unsupported webhook request method '%s'", webhookMethod)
+ }
+
+ // 处理 Webhook 请求标头
+ webhookHeaders := make(http.Header)
+ for k, v := range d.config.Headers {
+ webhookHeaders.Set(k, v)
+ }
+
+ // 处理 Webhook 请求内容类型
+ webhookContentType := webhookHeaders.Get("Content-Type")
+ if webhookContentType == "" {
+ 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)
+ }
+
+ // 处理 Webhook 请求数据
+ var webhookData any
+ if d.config.WebhookData == "" {
+ webhookData = map[string]string{
+ "name": strings.Join(xcertx509.GetSubjectAltNames(certX509), ";"),
+ "cert": certPEM,
+ "privkey": privkeyPEM,
+ }
+ } else {
+ err = json.Unmarshal([]byte(d.config.WebhookData), &webhookData)
+ if err != nil {
+ return nil, fmt.Errorf("failed to unmarshal webhook data: %w", err)
+ }
+
+ if webhookMethod == http.MethodGet || webhookContentType == contentTypeForm || webhookContentType == contentTypeMultipart {
+ temp := make(map[string]string)
+ jsonb, err := json.Marshal(webhookData)
+ if err != nil {
+ return nil, fmt.Errorf("failed to unmarshal webhook data: %w", err)
+ } else if err := json.Unmarshal(jsonb, &temp); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal webhook data: %w", err)
+ } else {
+ webhookData = temp
+ }
+ }
+ }
+
+ // 替换变量值
+ webhookUrl.Path = strings.ReplaceAll(webhookUrl.Path, "${CERTIMATE_DEPLOYER_COMMONNAME}", url.PathEscape(xcertx509.GetSubjectCommonName(certX509)))
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${CERTIMATE_DEPLOYER_COMMONNAME}", xcertx509.GetSubjectCommonName(certX509))
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${CERTIMATE_DEPLOYER_SUBJECTALTNAMES}", strings.Join(xcertx509.GetSubjectAltNames(certX509), ";"))
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${CERTIMATE_DEPLOYER_CERTIFICATE}", certPEM)
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${CERTIMATE_DEPLOYER_CERTIFICATE_SERVER}", serverCertPEM)
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${CERTIMATE_DEPLOYER_CERTIFICATE_INTERMEDIA}", issuerCertPEM)
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${CERTIMATE_DEPLOYER_PRIVATEKEY}", privkeyPEM)
+
+ // 兼容旧版变量
+ // TODO: remove in future version
+ webhookUrl.Path = strings.ReplaceAll(webhookUrl.Path, "${DOMAIN}", url.PathEscape(certX509.Subject.CommonName))
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${DOMAIN}", certX509.Subject.CommonName)
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${DOMAINS}", strings.Join(certX509.DNSNames, ";"))
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${CERTIFICATE}", certPEM)
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${SERVER_CERTIFICATE}", serverCertPEM)
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${INTERMEDIA_CERTIFICATE}", issuerCertPEM)
+ xmaps.DeepReplaceValueUnsafe(webhookData, "${PRIVATE_KEY}", privkeyPEM)
+
+ // 生成请求
+ // 其中 GET 请求需转换为查询参数
+ req := d.httpClient.R().SetHeaderMultiValues(webhookHeaders)
+ req.URL = webhookUrl.String()
+ req.Method = webhookMethod
+ if webhookMethod == http.MethodGet {
+ req.SetQueryParams(webhookData.(map[string]string))
+ } else {
+ switch webhookContentType {
+ case contentTypeJson:
+ req.SetBody(webhookData)
+ case contentTypeForm:
+ req.SetFormData(webhookData.(map[string]string))
+ case contentTypeMultipart:
+ req.SetMultipartFormData(webhookData.(map[string]string))
+ }
+ }
+
+ // 发送请求
+ resp, err := req.Send()
+ if err != nil {
+ return nil, fmt.Errorf("failed to send webhook request: %w", err)
+ } else if resp.IsError() {
+ return nil, fmt.Errorf("unexpected webhook response status code: %d", resp.StatusCode())
+ }
+
+ d.logger.Debug("webhook responded", slog.Any("response", resp.String()))
+
+ return &DeployResult{}, nil
+}
diff --git a/pkg/core/deployer/providers/webhook/webhook_test.go b/pkg/core/deployer/providers/webhook/webhook_test.go
new file mode 100644
index 000000000..41e7ad3b4
--- /dev/null
+++ b/pkg/core/deployer/providers/webhook/webhook_test.go
@@ -0,0 +1,57 @@
+package webhook_test
+
+import (
+ "testing"
+
+ impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/webhook"
+ tester "github.com/certimate-go/certimate/pkg/core/deployer/testing"
+)
+
+var (
+ fp = tester.Args("WEBHOOK_")
+ fTestCertPath string
+ fTestKeyPath string
+ fWebhookUrl string
+ fWebhookContentType string
+ fWebhookData string
+)
+
+func init() {
+ fp.DefineString(&fTestCertPath, "TESTCERTPATH")
+ fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
+ fp.DefineString(&fWebhookUrl, "URL")
+ fp.DefineString(&fWebhookContentType, "CONTENTTYPE", "application/json")
+ fp.DefineString(&fWebhookData, "DATA")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./webhook_test.go -args \
+ --WEBHOOK_TESTCERTPATH="/path/to/your-test-cert.pem" \
+ --WEBHOOK_TESTKEYPATH="/path/to/your-test-key.pem" \
+ --WEBHOOK_URL="https://example.com/your-webhook-url" \
+ --WEBHOOK_CONTENTTYPE="application/json" \
+ --WEBHOOK_DATA="{\"certificate\":\"${CERTIFICATE}\",\"privateKey\":\"${PRIVATE_KEY}\"}"
+*/
+func TestProvider(t *testing.T) {
+ fp.Parse()
+
+ t.Run("Deploy", func(t *testing.T) {
+ provider, err := impl.NewDeployer(&impl.DeployerConfig{
+ WebhookUrl: fWebhookUrl,
+ WebhookData: fWebhookData,
+ Method: "POST",
+ Headers: map[string]string{
+ "Content-Type": fWebhookContentType,
+ },
+ AllowInsecureConnections: true,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
+ })
+}
diff --git a/pkg/sdk3rd/qiniu/auth.go b/pkg/sdk3rd/qiniu/auth.go
deleted file mode 100644
index a1668dd76..000000000
--- a/pkg/sdk3rd/qiniu/auth.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package qiniu
-
-import (
- "net/http"
-
- "github.com/qiniu/go-sdk/v7/auth"
- "github.com/qiniu/go-sdk/v7/client"
-)
-
-type transport struct {
- http.RoundTripper
- mac *auth.Credentials
-}
-
-func newTransport(mac *auth.Credentials, tr http.RoundTripper) *transport {
- if tr == nil {
- tr = client.DefaultTransport
- }
- return &transport{tr, mac}
-}
-
-func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
- token, err := t.mac.SignRequestV2(req)
- if err != nil {
- return nil, err
- }
-
- req.Header.Set("Authorization", "Qiniu "+token)
- return t.RoundTripper.RoundTrip(req)
-}
diff --git a/pkg/sdk3rd/qiniu/cdn.go b/pkg/sdk3rd/qiniu/cdn.go
deleted file mode 100644
index 627b7c902..000000000
--- a/pkg/sdk3rd/qiniu/cdn.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package qiniu
-
-import (
- "context"
- "fmt"
- "net/http"
- "net/url"
-
- "github.com/qiniu/go-sdk/v7/auth"
- "github.com/qiniu/go-sdk/v7/client"
-)
-
-type CdnManager struct {
- client *client.Client
-}
-
-func NewCdnManager(mac *auth.Credentials) *CdnManager {
- if mac == nil {
- mac = auth.Default()
- }
-
- client := &client.Client{Client: &http.Client{Transport: newTransport(mac, nil)}}
- return &CdnManager{client: client}
-}
-
-type GetDomainListResponse struct {
- Code *int `json:"code,omitempty"`
- Error *string `json:"error,omitempty"`
- Marker string `json:"marker"`
- Domains []*struct {
- Name string `json:"name"`
- Type string `json:"type"`
- CName string `json:"cname"`
- OperatingState string `json:"operatingState"`
- OperatingStateDesc string `json:"operatingStateDesc"`
- CreateAt string `json:"createAt"`
- ModifyAt string `json:"modifyAt"`
- } `json:"domains"`
-}
-
-func (m *CdnManager) GetDomainList(ctx context.Context, marker string, limit int) (*GetDomainListResponse, error) {
- query := url.Values{}
- if marker != "" {
- query.Set("marker", marker)
- }
- if limit > 0 {
- query.Set("limit", fmt.Sprintf("%d", limit))
- }
-
- resp := new(GetDomainListResponse)
- if err := m.client.Call(ctx, resp, http.MethodGet, urlf("domain?%s", query.Encode()), nil); err != nil {
- return nil, err
- }
- return resp, nil
-}
-
-type GetDomainInfoResponse struct {
- Code *int `json:"code,omitempty"`
- Error *string `json:"error,omitempty"`
- Name string `json:"name"`
- Type string `json:"type"`
- CName string `json:"cname"`
- Https *struct {
- CertID string `json:"certId"`
- ForceHttps bool `json:"forceHttps"`
- Http2Enable bool `json:"http2Enable"`
- } `json:"https"`
- PareDomain string `json:"pareDomain"`
- OperationType string `json:"operationType"`
- OperatingState string `json:"operatingState"`
- OperatingStateDesc string `json:"operatingStateDesc"`
- CreateAt string `json:"createAt"`
- ModifyAt string `json:"modifyAt"`
-}
-
-func (m *CdnManager) GetDomainInfo(ctx context.Context, domain string) (*GetDomainInfoResponse, error) {
- resp := new(GetDomainInfoResponse)
- if err := m.client.Call(ctx, resp, http.MethodGet, urlf("domain/%s", domain), nil); err != nil {
- return nil, err
- }
- return resp, nil
-}
-
-type ModifyDomainHttpsConfRequest struct {
- CertID string `json:"certId"`
- ForceHttps bool `json:"forceHttps"`
- Http2Enable bool `json:"http2Enable"`
-}
-
-type ModifyDomainHttpsConfResponse struct {
- Code *int `json:"code,omitempty"`
- Error *string `json:"error,omitempty"`
-}
-
-func (m *CdnManager) ModifyDomainHttpsConf(ctx context.Context, domain string, certId string, forceHttps bool, http2Enable bool) (*ModifyDomainHttpsConfResponse, error) {
- req := &ModifyDomainHttpsConfRequest{
- CertID: certId,
- ForceHttps: forceHttps,
- Http2Enable: http2Enable,
- }
- resp := new(ModifyDomainHttpsConfResponse)
- if err := m.client.CallWithJson(ctx, resp, http.MethodPut, urlf("domain/%s/httpsconf", domain), nil, req); err != nil {
- return nil, err
- }
- return resp, nil
-}
-
-type EnableDomainHttpsRequest struct {
- CertID string `json:"certId"`
- ForceHttps bool `json:"forceHttps"`
- Http2Enable bool `json:"http2Enable"`
-}
-
-type EnableDomainHttpsResponse struct {
- Code *int `json:"code,omitempty"`
- Error *string `json:"error,omitempty"`
-}
-
-func (m *CdnManager) EnableDomainHttps(ctx context.Context, domain string, certId string, forceHttps bool, http2Enable bool) (*EnableDomainHttpsResponse, error) {
- req := &EnableDomainHttpsRequest{
- CertID: certId,
- ForceHttps: forceHttps,
- Http2Enable: http2Enable,
- }
- resp := new(EnableDomainHttpsResponse)
- if err := m.client.CallWithJson(ctx, resp, http.MethodPut, urlf("domain/%s/sslize", domain), nil, req); err != nil {
- return nil, err
- }
- return resp, nil
-}
diff --git a/pkg/sdk3rd/qiniu/doc.go b/pkg/sdk3rd/qiniu/doc.go
deleted file mode 100644
index 5931d1ca5..000000000
--- a/pkg/sdk3rd/qiniu/doc.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// An extension SDK client for Qiniu.
-// Based on github.com/qiniu/go-sdk.
-package qiniu
\ No newline at end of file
diff --git a/pkg/sdk3rd/qiniu/kodo.go b/pkg/sdk3rd/qiniu/kodo.go
deleted file mode 100644
index 6a3245a28..000000000
--- a/pkg/sdk3rd/qiniu/kodo.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package qiniu
-
-import (
- "context"
- "net/http"
-
- "github.com/qiniu/go-sdk/v7/auth"
- "github.com/qiniu/go-sdk/v7/client"
-)
-
-type KodoManager struct {
- client *client.Client
-}
-
-func NewKodoManager(mac *auth.Credentials) *KodoManager {
- if mac == nil {
- mac = auth.Default()
- }
-
- client := &client.Client{Client: &http.Client{Transport: newTransport(mac, nil)}}
- return &KodoManager{client: client}
-}
-
-type BindBucketCertRequest struct {
- CertID string `json:"certid"`
- Domain string `json:"domain"`
-}
-
-type BindBucketCertResponse struct {
- Code *int `json:"code,omitempty"`
- Error *string `json:"error,omitempty"`
-}
-
-func (m *KodoManager) BindBucketCert(ctx context.Context, domain string, certId string) (*BindBucketCertResponse, error) {
- req := &BindBucketCertRequest{
- CertID: certId,
- Domain: domain,
- }
- resp := new(BindBucketCertResponse)
- if err := m.client.CallWithJson(ctx, resp, http.MethodPut, urlf("cert/bind"), nil, req); err != nil {
- return nil, err
- }
- return resp, nil
-}
diff --git a/pkg/sdk3rd/qiniu/sslcert.go b/pkg/sdk3rd/qiniu/sslcert.go
deleted file mode 100644
index f9784270f..000000000
--- a/pkg/sdk3rd/qiniu/sslcert.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package qiniu
-
-import (
- "context"
- "net/http"
- "net/url"
-
- "github.com/qiniu/go-sdk/v7/auth"
- "github.com/qiniu/go-sdk/v7/client"
-)
-
-type SslCertManager struct {
- client *client.Client
-}
-
-func NewSslCertManager(mac *auth.Credentials) *SslCertManager {
- if mac == nil {
- mac = auth.Default()
- }
-
- client := &client.Client{Client: &http.Client{Transport: newTransport(mac, nil)}}
- return &SslCertManager{client: client}
-}
-
-type GetSslCertListResponse struct {
- Code *int `json:"code,omitempty"`
- Error *string `json:"error,omitempty"`
- Certs []*struct {
- CertID string `json:"certid"`
- Name string `json:"name"`
- CommonName string `json:"common_name"`
- DnsNames []string `json:"dnsnames"`
- CreateTime int64 `json:"create_time"`
- NotBefore int64 `json:"not_before"`
- NotAfter int64 `json:"not_after"`
- ProductType string `json:"product_type"`
- ProductShortName string `json:"product_short_name,omitempty"`
- OrderId string `json:"orderid,omitempty"`
- CertType string `json:"cert_type"`
- Encrypt string `json:"encrypt"`
- EncryptParameter string `json:"encryptParameter,omitempty"`
- Enable bool `json:"enable"`
- } `json:"certs"`
- Marker string `json:"marker"`
-}
-
-func (m *SslCertManager) GetSslCertList(ctx context.Context, marker string, limit int32) (*GetSslCertListResponse, error) {
- resp := new(GetSslCertListResponse)
- if err := m.client.Call(ctx, resp, http.MethodGet, urlf("sslcert?marker=%s&limit=%d", url.QueryEscape(marker), limit), nil); err != nil {
- return nil, err
- }
- return resp, nil
-}
-
-type UploadSslCertRequest struct {
- Name string `json:"name"`
- CommonName string `json:"common_name"`
- Certificate string `json:"ca"`
- PrivateKey string `json:"pri"`
-}
-
-type UploadSslCertResponse struct {
- Code *int `json:"code,omitempty"`
- Error *string `json:"error,omitempty"`
- CertID string `json:"certID"`
-}
-
-func (m *SslCertManager) UploadSslCert(ctx context.Context, name string, commonName string, certificate string, privateKey string) (*UploadSslCertResponse, error) {
- req := &UploadSslCertRequest{
- Name: name,
- CommonName: commonName,
- Certificate: certificate,
- PrivateKey: privateKey,
- }
- resp := new(UploadSslCertResponse)
- if err := m.client.CallWithJson(ctx, resp, http.MethodPost, urlf("sslcert"), nil, req); err != nil {
- return nil, err
- }
- return resp, nil
-}
diff --git a/pkg/sdk3rd/qiniu/util.go b/pkg/sdk3rd/qiniu/util.go
deleted file mode 100644
index 0957a3102..000000000
--- a/pkg/sdk3rd/qiniu/util.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package qiniu
-
-import (
- "fmt"
- "strings"
-)
-
-const qiniuHost = "https://api.qiniu.com"
-
-func urlf(pathf string, pathargs ...any) string {
- path := fmt.Sprintf(pathf, pathargs...)
- path = strings.TrimPrefix(path, "/")
- return qiniuHost + "/" + path
-}
diff --git a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx
index 47f6c35c1..bc802e1da 100644
--- a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx
+++ b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx
@@ -90,7 +90,6 @@ import AccessConfigFieldsProviderPorkbun from "./AccessConfigFieldsProviderPorkb
import AccessConfigFieldsProviderPowerDNS from "./AccessConfigFieldsProviderPowerDNS";
import AccessConfigFieldsProviderProxmoxVE from "./AccessConfigFieldsProviderProxmoxVE";
import AccessConfigFieldsProviderQingCloud from "./AccessConfigFieldsProviderQingCloud";
-import AccessConfigFieldsProviderQiniu from "./AccessConfigFieldsProviderQiniu";
import AccessConfigFieldsProviderRainYun from "./AccessConfigFieldsProviderRainYun";
import AccessConfigFieldsProviderRatPanel from "./AccessConfigFieldsProviderRatPanel";
import AccessConfigFieldsProviderRegru from "./AccessConfigFieldsProviderRegru";
@@ -215,7 +214,6 @@ const providerComponentMap: Partial