diff --git a/go.mod b/go.mod
index a4ab4379..37686d8c 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,7 @@ require (
github.com/alibabacloud-go/esa-20240910/v2 v2.32.0
github.com/alibabacloud-go/fc-20230330/v4 v4.3.5
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12
+ github.com/alibabacloud-go/ga-20191120/v3 v3.1.8
github.com/alibabacloud-go/live-20161101 v1.1.1
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3
github.com/alibabacloud-go/slb-20140515/v4 v4.0.10
diff --git a/go.sum b/go.sum
index b9d4247d..5a64f77a 100644
--- a/go.sum
+++ b/go.sum
@@ -112,6 +112,7 @@ github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+M
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.5/go.mod h1:kUe8JqFmoVU7lfBauaDD5taFaW7mBI+xVsyHutYtabg=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE=
@@ -137,6 +138,8 @@ github.com/alibabacloud-go/fc-20230330/v4 v4.3.5 h1:nDNjVzGwkQPbQnAuxAmxvS9x8QGL
github.com/alibabacloud-go/fc-20230330/v4 v4.3.5/go.mod h1:vEJimQ6E/e+m2z0/oXdeQWlFw/Pi/Ar6NKcMrSvcILE=
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 h1:A3D8Mp6qf8DfR6Dt5MpS8aDVaWfS4N85T5CvGUvgrjM=
github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12/go.mod h1:F5c0E5UB3k8v6neTtw3FBcJ1YCNFzVoL1JPRHTe33u4=
+github.com/alibabacloud-go/ga-20191120/v3 v3.1.8 h1:5GF0PXijDhxRQ3gTg9Ee/CVPtglkxuVdz4yIQgYLPgw=
+github.com/alibabacloud-go/ga-20191120/v3 v3.1.8/go.mod h1:RVpR9VL4YECKoZCQijTYfPk8k52O61v6hSRekjxF0kw=
github.com/alibabacloud-go/live-20161101 v1.1.1 h1:rUGfA8RHmCMtQ5M3yMSyRde+yRXWqVecmiXBU3XrGJ8=
github.com/alibabacloud-go/live-20161101 v1.1.1/go.mod h1:g84w6qeAodT0/IHdc0tEed2a8PyhQhYl7TAj3jGl4A4=
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 h1:LtyUVlgBEKyzWgQJurzXM6MXCt84sQr9cE5OKqYymko=
diff --git a/internal/applicant/acme_ca.go b/internal/applicant/acme_ca.go
index 67b7693e..36c0a0a4 100644
--- a/internal/applicant/acme_ca.go
+++ b/internal/applicant/acme_ca.go
@@ -3,25 +3,26 @@ package applicant
import "github.com/usual2970/certimate/internal/domain"
const (
- sslProviderLetsEncrypt = string(domain.CAProviderTypeLetsEncrypt)
- sslProviderLetsEncryptStaging = string(domain.CAProviderTypeLetsEncryptStaging)
- sslProviderBuypass = string(domain.CAProviderTypeBuypass)
- sslProviderGoogleTrustServices = string(domain.CAProviderTypeGoogleTrustServices)
- sslProviderSSLCom = string(domain.CAProviderTypeSSLCom)
- sslProviderZeroSSL = string(domain.CAProviderTypeZeroSSL)
+ caLetsEncrypt = string(domain.CAProviderTypeLetsEncrypt)
+ caLetsEncryptStaging = string(domain.CAProviderTypeLetsEncryptStaging)
+ caBuypass = string(domain.CAProviderTypeBuypass)
+ caGoogleTrustServices = string(domain.CAProviderTypeGoogleTrustServices)
+ caSSLCom = string(domain.CAProviderTypeSSLCom)
+ caZeroSSL = string(domain.CAProviderTypeZeroSSL)
+ caCustom = string(domain.CAProviderTypeACMECA)
- sslProviderDefault = sslProviderLetsEncrypt
+ caDefault = caLetsEncrypt
)
-var sslProviderUrls = map[string]string{
- sslProviderLetsEncrypt: "https://acme-v02.api.letsencrypt.org/directory",
- sslProviderLetsEncryptStaging: "https://acme-staging-v02.api.letsencrypt.org/directory",
- sslProviderBuypass: "https://api.buypass.com/acme/directory",
- sslProviderGoogleTrustServices: "https://dv.acme-v02.api.pki.goog/directory",
- sslProviderSSLCom: "https://acme.ssl.com/sslcom-dv-rsa",
- sslProviderSSLCom + "RSA": "https://acme.ssl.com/sslcom-dv-rsa",
- sslProviderSSLCom + "ECC": "https://acme.ssl.com/sslcom-dv-ecc",
- sslProviderZeroSSL: "https://acme.zerossl.com/v2/DV90",
+var caDirUrls = map[string]string{
+ caLetsEncrypt: "https://acme-v02.api.letsencrypt.org/directory",
+ caLetsEncryptStaging: "https://acme-staging-v02.api.letsencrypt.org/directory",
+ caBuypass: "https://api.buypass.com/acme/directory",
+ caGoogleTrustServices: "https://dv.acme-v02.api.pki.goog/directory",
+ caSSLCom: "https://acme.ssl.com/sslcom-dv-rsa",
+ caSSLCom + "RSA": "https://acme.ssl.com/sslcom-dv-rsa",
+ caSSLCom + "ECC": "https://acme.ssl.com/sslcom-dv-ecc",
+ caZeroSSL: "https://acme.zerossl.com/v2/DV90",
}
type acmeSSLProviderConfig struct {
diff --git a/internal/applicant/acme_user.go b/internal/applicant/acme_user.go
index 29ac80cd..e6e13cb7 100644
--- a/internal/applicant/acme_user.go
+++ b/internal/applicant/acme_user.go
@@ -7,6 +7,7 @@ import (
"crypto/elliptic"
"crypto/rand"
"fmt"
+ "strings"
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/registration"
@@ -19,22 +20,31 @@ import (
)
type acmeUser struct {
- CA string
- Email string
+ // 证书颁发机构标识。
+ // 通常等同于 [CAProviderType] 的值。
+ // 对于自定义 ACME CA,值为 "custom#{access_id}"。
+ CA string
+ // 邮箱。
+ Email string
+ // 注册信息。
Registration *registration.Resource
+ // CSR 私钥。
privkey string
}
-func newAcmeUser(ca, email string) (*acmeUser, error) {
+func newAcmeUser(ca, caAccessId, email string) (*acmeUser, error) {
repo := repository.NewAcmeAccountRepository()
applyUser := &acmeUser{
CA: ca,
Email: email,
}
+ if ca == caCustom {
+ applyUser.CA = fmt.Sprintf("%s#%s", ca, caAccessId)
+ }
- acmeAccount, err := repo.GetByCAAndEmail(ca, email)
+ acmeAccount, err := repo.GetByCAAndEmail(applyUser.CA, applyUser.Email)
if err != nil {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
@@ -73,6 +83,10 @@ func (u *acmeUser) hasRegistration() bool {
return u.Registration != nil
}
+func (u *acmeUser) getCAProvider() string {
+ return strings.Split(u.CA, "#")[0]
+}
+
func (u *acmeUser) getPrivateKeyPEM() string {
return u.privkey
}
@@ -94,16 +108,16 @@ func registerAcmeUserWithSingleFlight(client *lego.Client, user *acmeUser, userR
func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions map[string]any) (*registration.Resource, error) {
var reg *registration.Resource
var err error
- switch user.CA {
- case sslProviderLetsEncrypt, sslProviderLetsEncryptStaging:
+ switch user.getCAProvider() {
+ case caLetsEncrypt, caLetsEncryptStaging:
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
- case sslProviderBuypass:
+ case caBuypass:
{
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
}
- case sslProviderGoogleTrustServices:
+ case caGoogleTrustServices:
{
access := domain.AccessConfigForGoogleTrustServices{}
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
@@ -117,7 +131,7 @@ func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions m
})
}
- case sslProviderSSLCom:
+ case caSSLCom:
{
access := domain.AccessConfigForSSLCom{}
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
@@ -131,7 +145,7 @@ func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions m
})
}
- case sslProviderZeroSSL:
+ case caZeroSSL:
{
access := domain.AccessConfigForZeroSSL{}
if err := maputil.Populate(userRegisterOptions, &access); err != nil {
@@ -145,6 +159,26 @@ func registerAcmeUser(client *lego.Client, user *acmeUser, userRegisterOptions m
})
}
+ case caCustom:
+ {
+ access := domain.AccessConfigForACMECA{}
+ if err := maputil.Populate(userRegisterOptions, &access); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ if access.EabKid == "" && access.EabHmacKey == "" {
+ reg, err = client.Registration.Register(registration.RegisterOptions{
+ TermsOfServiceAgreed: true,
+ })
+ } else {
+ reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
+ TermsOfServiceAgreed: true,
+ Kid: access.EabKid,
+ HmacEncoded: access.EabHmacKey,
+ })
+ }
+ }
+
default:
err = fmt.Errorf("unsupported ca provider '%s'", user.CA)
}
diff --git a/internal/applicant/applicant.go b/internal/applicant/applicant.go
index e9ed4cb1..e6a04bcd 100644
--- a/internal/applicant/applicant.go
+++ b/internal/applicant/applicant.go
@@ -20,12 +20,13 @@ import (
"golang.org/x/time/rate"
"github.com/usual2970/certimate/internal/domain"
+ maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
"github.com/usual2970/certimate/internal/repository"
)
type ApplyResult struct {
- CertificateFullChain string
+ FullChainCertificate string
IssuerCertificate string
PrivateKey string
ACMEAccountUrl string
@@ -53,20 +54,20 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
nodeConfig := config.Node.GetConfigForApply()
options := &applicantProviderOptions{
- Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
- ContactEmail: nodeConfig.ContactEmail,
- Provider: domain.ACMEDns01ProviderType(nodeConfig.Provider),
- ProviderAccessConfig: make(map[string]any),
- ProviderExtendedConfig: nodeConfig.ProviderConfig,
- CAProvider: domain.CAProviderType(nodeConfig.CAProvider),
- CAProviderAccessConfig: make(map[string]any),
- CAProviderExtendedConfig: nodeConfig.CAProviderConfig,
- KeyAlgorithm: nodeConfig.KeyAlgorithm,
- Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }),
- DnsPropagationWait: nodeConfig.DnsPropagationWait,
- DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout,
- DnsTTL: nodeConfig.DnsTTL,
- DisableFollowCNAME: nodeConfig.DisableFollowCNAME,
+ Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
+ ContactEmail: nodeConfig.ContactEmail,
+ Provider: domain.ACMEDns01ProviderType(nodeConfig.Provider),
+ ProviderAccessConfig: make(map[string]any),
+ ProviderServiceConfig: nodeConfig.ProviderConfig,
+ CAProvider: domain.CAProviderType(nodeConfig.CAProvider),
+ CAProviderAccessConfig: make(map[string]any),
+ CAProviderServiceConfig: nodeConfig.CAProviderConfig,
+ KeyAlgorithm: nodeConfig.KeyAlgorithm,
+ Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }),
+ DnsPropagationWait: nodeConfig.DnsPropagationWait,
+ DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout,
+ DnsTTL: nodeConfig.DnsTTL,
+ DisableFollowCNAME: nodeConfig.DisableFollowCNAME,
}
accessRepo := repository.NewAccessRepository()
@@ -81,6 +82,7 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
if access, err := accessRepo.GetById(context.Background(), nodeConfig.CAProviderAccessId); err != nil {
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.CAProviderAccessId, err)
} else {
+ options.CAProviderAccessId = access.Id
options.CAProviderAccessConfig = access.Config
}
}
@@ -91,13 +93,13 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
sslProviderConfig := &acmeSSLProviderConfig{
Config: make(map[domain.CAProviderType]map[string]any),
- Provider: sslProviderDefault,
+ Provider: caDefault,
}
if settings != nil {
if err := json.Unmarshal([]byte(settings.Content), sslProviderConfig); err != nil {
return nil, err
} else if sslProviderConfig.Provider == "" {
- sslProviderConfig.Provider = sslProviderDefault
+ sslProviderConfig.Provider = caDefault
}
}
@@ -163,7 +165,7 @@ func getLimiter(key string) *rate.Limiter {
}
func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOptions) (*ApplyResult, error) {
- user, err := newAcmeUser(string(options.CAProvider), options.ContactEmail)
+ user, err := newAcmeUser(string(options.CAProvider), options.CAProviderAccessId, options.ContactEmail)
if err != nil {
return nil, err
}
@@ -175,13 +177,26 @@ func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOpt
// Create an ACME client config
config := lego.NewConfig(user)
config.Certificate.KeyType = parseLegoKeyAlgorithm(domain.CertificateKeyAlgorithmType(options.KeyAlgorithm))
- config.CADirURL = sslProviderUrls[user.CA]
- if user.CA == sslProviderSSLCom {
+ switch user.getCAProvider() {
+ case caSSLCom:
if strings.HasPrefix(options.KeyAlgorithm, "RSA") {
- config.CADirURL = sslProviderUrls[sslProviderSSLCom+"RSA"]
+ config.CADirURL = caDirUrls[caSSLCom+"RSA"]
} else if strings.HasPrefix(options.KeyAlgorithm, "EC") {
- config.CADirURL = sslProviderUrls[sslProviderSSLCom+"ECC"]
+ config.CADirURL = caDirUrls[caSSLCom+"ECC"]
+ } else {
+ config.CADirURL = caDirUrls[caSSLCom]
}
+
+ case caCustom:
+ caDirURL := maputil.GetString(options.CAProviderAccessConfig, "endpoint")
+ if caDirURL != "" {
+ config.CADirURL = caDirURL
+ } else {
+ return nil, fmt.Errorf("invalid ca provider endpoint")
+ }
+
+ default:
+ config.CADirURL = caDirUrls[user.CA]
}
// Create an ACME client
@@ -229,7 +244,7 @@ func applyUseLego(legoProvider challenge.Provider, options *applicantProviderOpt
}
return &ApplyResult{
- CertificateFullChain: strings.TrimSpace(string(certResource.Certificate)),
+ FullChainCertificate: strings.TrimSpace(string(certResource.Certificate)),
IssuerCertificate: strings.TrimSpace(string(certResource.IssuerCertificate)),
PrivateKey: strings.TrimSpace(string(certResource.PrivateKey)),
ACMEAccountUrl: user.Registration.URI,
diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go
index 90a3cf72..de47ae18 100644
--- a/internal/applicant/providers.go
+++ b/internal/applicant/providers.go
@@ -42,22 +42,23 @@ import (
)
type applicantProviderOptions struct {
- Domains []string
- ContactEmail string
- Provider domain.ACMEDns01ProviderType
- ProviderAccessConfig map[string]any
- ProviderExtendedConfig map[string]any
- CAProvider domain.CAProviderType
- CAProviderAccessConfig map[string]any
- CAProviderExtendedConfig map[string]any
- KeyAlgorithm string
- Nameservers []string
- DnsPropagationWait int32
- DnsPropagationTimeout int32
- DnsTTL int32
- DisableFollowCNAME bool
- ReplacedARIAcct string
- ReplacedARICert string
+ Domains []string
+ ContactEmail string
+ Provider domain.ACMEDns01ProviderType
+ ProviderAccessConfig map[string]any
+ ProviderServiceConfig map[string]any
+ CAProvider domain.CAProviderType
+ CAProviderAccessId string
+ CAProviderAccessConfig map[string]any
+ CAProviderServiceConfig map[string]any
+ KeyAlgorithm string
+ Nameservers []string
+ DnsPropagationWait int32
+ DnsPropagationTimeout int32
+ DnsTTL int32
+ DisableFollowCNAME bool
+ ReplacedARIAcct string
+ ReplacedARICert string
}
func createApplicantProvider(options *applicantProviderOptions) (challenge.Provider, error) {
@@ -104,7 +105,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
applicant, err := pAliyunESA.NewChallengeProvider(&pAliyunESA.ChallengeProviderConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
@@ -125,8 +126,8 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
applicant, err := pAWSRoute53.NewChallengeProvider(&pAWSRoute53.ChallengeProviderConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- HostedZoneId: maputil.GetString(options.ProviderExtendedConfig, "hostedZoneId"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ HostedZoneId: maputil.GetString(options.ProviderServiceConfig, "hostedZoneId"),
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
@@ -333,7 +334,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
applicant, err := pHuaweiCloud.NewChallengeProvider(&pHuaweiCloud.ChallengeProviderConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
@@ -350,7 +351,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
applicant, err := pJDCloud.NewChallengeProvider(&pJDCloud.ChallengeProviderConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- RegionId: maputil.GetString(options.ProviderExtendedConfig, "regionId"),
+ RegionId: maputil.GetString(options.ProviderServiceConfig, "regionId"),
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
@@ -520,7 +521,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
applicant, err := pTencentCloudEO.NewChallengeProvider(&pTencentCloudEO.ChallengeProviderConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- ZoneId: maputil.GetString(options.ProviderExtendedConfig, "zoneId"),
+ ZoneId: maputil.GetString(options.ProviderServiceConfig, "zoneId"),
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go
index bdacf08e..e4a28746 100644
--- a/internal/deployer/deployer.go
+++ b/internal/deployer/deployer.go
@@ -31,9 +31,9 @@ func NewWithWorkflowNode(config DeployerWithWorkflowNodeConfig) (Deployer, error
nodeConfig := config.Node.GetConfigForDeploy()
options := &deployerProviderOptions{
- Provider: domain.DeploymentProviderType(nodeConfig.Provider),
- ProviderAccessConfig: make(map[string]any),
- ProviderExtendedConfig: nodeConfig.ProviderConfig,
+ Provider: domain.DeploymentProviderType(nodeConfig.Provider),
+ ProviderAccessConfig: make(map[string]any),
+ ProviderServiceConfig: nodeConfig.ProviderConfig,
}
accessRepo := repository.NewAccessRepository()
diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go
index d4c61a31..15a8f370 100644
--- a/internal/deployer/providers.go
+++ b/internal/deployer/providers.go
@@ -19,6 +19,7 @@ import (
pAliyunDDoS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-ddos"
pAliyunESA "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-esa"
pAliyunFC "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-fc"
+ pAliyunGA "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-ga"
pAliyunLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-live"
pAliyunNLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-nlb"
pAliyunOSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-oss"
@@ -34,12 +35,15 @@ import (
pBaishanCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baishan-cdn"
pBaotaPanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console"
pBaotaPanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site"
+ pBaotaWAFConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-console"
+ pBaotaWAFSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-site"
pBunnyCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/bunny-cdn"
pBytePlusCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/byteplus-cdn"
pCacheFly "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cachefly"
pCdnfly "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cdnfly"
pDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn"
pEdgioApplications "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications"
+ pFlexCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/flexcdn"
pGcoreCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/gcore-cdn"
pGoEdge "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/goedge"
pHuaweiCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-cdn"
@@ -51,6 +55,7 @@ import (
pJDCloudLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-live"
pJDCloudVOD "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-vod"
pK8sSecret "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/k8s-secret"
+ pLeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/lecdn"
pLocal "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/local"
pNetlifySite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/netlify-site"
pProxmoxVE "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/proxmoxve"
@@ -83,7 +88,9 @@ import (
pVolcEngineImageX "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-imagex"
pVolcEngineLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-live"
pVolcEngineTOS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-tos"
+ pWangsuCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/wangsu-cdn"
pWangsuCDNPro "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/wangsu-cdnpro"
+ pWangsuCertificate "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/wangsu-certificate"
pWebhook "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/webhook"
httputil "github.com/usual2970/certimate/internal/pkg/utils/http"
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
@@ -91,9 +98,9 @@ import (
)
type deployerProviderOptions struct {
- Provider domain.DeploymentProviderType
- ProviderAccessConfig map[string]any
- ProviderExtendedConfig map[string]any
+ Provider domain.DeploymentProviderType
+ ProviderAccessConfig map[string]any
+ ProviderServiceConfig map[string]any
}
func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer, error) {
@@ -113,20 +120,22 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
case domain.DeploymentProviderType1PanelConsole:
deployer, err := p1PanelConsole.NewDeployer(&p1PanelConsole.DeployerConfig{
ApiUrl: access.ApiUrl,
+ ApiVersion: access.ApiVersion,
ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
- AutoRestart: maputil.GetBool(options.ProviderExtendedConfig, "autoRestart"),
+ AutoRestart: maputil.GetBool(options.ProviderServiceConfig, "autoRestart"),
})
return deployer, err
case domain.DeploymentProviderType1PanelSite:
deployer, err := p1PanelSite.NewDeployer(&p1PanelSite.DeployerConfig{
ApiUrl: access.ApiUrl,
+ ApiVersion: access.ApiVersion,
ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
- ResourceType: p1PanelSite.ResourceType(maputil.GetOrDefaultString(options.ProviderExtendedConfig, "resourceType", string(p1PanelSite.RESOURCE_TYPE_WEBSITE))),
- WebsiteId: maputil.GetInt64(options.ProviderExtendedConfig, "websiteId"),
- CertificateId: maputil.GetInt64(options.ProviderExtendedConfig, "certificateId"),
+ ResourceType: p1PanelSite.ResourceType(maputil.GetOrDefaultString(options.ProviderServiceConfig, "resourceType", string(p1PanelSite.RESOURCE_TYPE_WEBSITE))),
+ WebsiteId: maputil.GetInt64(options.ProviderServiceConfig, "websiteId"),
+ CertificateId: maputil.GetInt64(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
@@ -135,7 +144,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
}
}
- case domain.DeploymentProviderTypeAliyunALB, domain.DeploymentProviderTypeAliyunAPIGW, domain.DeploymentProviderTypeAliyunCAS, domain.DeploymentProviderTypeAliyunCASDeploy, domain.DeploymentProviderTypeAliyunCDN, domain.DeploymentProviderTypeAliyunCLB, domain.DeploymentProviderTypeAliyunDCDN, domain.DeploymentProviderTypeAliyunDDoS, domain.DeploymentProviderTypeAliyunESA, domain.DeploymentProviderTypeAliyunFC, domain.DeploymentProviderTypeAliyunLive, domain.DeploymentProviderTypeAliyunNLB, domain.DeploymentProviderTypeAliyunOSS, domain.DeploymentProviderTypeAliyunVOD, domain.DeploymentProviderTypeAliyunWAF:
+ case domain.DeploymentProviderTypeAliyunALB, domain.DeploymentProviderTypeAliyunAPIGW, domain.DeploymentProviderTypeAliyunCAS, domain.DeploymentProviderTypeAliyunCASDeploy, domain.DeploymentProviderTypeAliyunCDN, domain.DeploymentProviderTypeAliyunCLB, domain.DeploymentProviderTypeAliyunDCDN, domain.DeploymentProviderTypeAliyunDDoS, domain.DeploymentProviderTypeAliyunESA, domain.DeploymentProviderTypeAliyunFC, domain.DeploymentProviderTypeAliyunGA, domain.DeploymentProviderTypeAliyunLive, domain.DeploymentProviderTypeAliyunNLB, domain.DeploymentProviderTypeAliyunOSS, domain.DeploymentProviderTypeAliyunVOD, domain.DeploymentProviderTypeAliyunWAF:
{
access := domain.AccessConfigForAliyun{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@@ -147,11 +156,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunALB.NewDeployer(&pAliyunALB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pAliyunALB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerId: maputil.GetString(options.ProviderExtendedConfig, "listenerId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pAliyunALB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -159,11 +168,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunAPIGW.NewDeployer(&pAliyunAPIGW.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ServiceType: pAliyunAPIGW.ServiceType(maputil.GetString(options.ProviderExtendedConfig, "serviceType")),
- GatewayId: maputil.GetString(options.ProviderExtendedConfig, "gatewayId"),
- GroupId: maputil.GetString(options.ProviderExtendedConfig, "groupId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ServiceType: pAliyunAPIGW.ServiceType(maputil.GetString(options.ProviderServiceConfig, "serviceType")),
+ GatewayId: maputil.GetString(options.ProviderServiceConfig, "gatewayId"),
+ GroupId: maputil.GetString(options.ProviderServiceConfig, "groupId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -171,7 +180,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunCAS.NewDeployer(&pAliyunCAS.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
})
return deployer, err
@@ -179,9 +188,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunCASDeploy.NewDeployer(&pAliyunCASDeploy.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderExtendedConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }),
- ContactIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderExtendedConfig, "contactIds"), ";"), func(s string) bool { return s != "" }),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderServiceConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }),
+ ContactIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderServiceConfig, "contactIds"), ";"), func(s string) bool { return s != "" }),
})
return deployer, err
@@ -189,7 +198,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunCDN.NewDeployer(&pAliyunCDN.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -197,11 +206,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunCLB.NewDeployer(&pAliyunCLB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pAliyunCLB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerPort: maputil.GetOrDefaultInt32(options.ProviderExtendedConfig, "listenerPort", 443),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pAliyunCLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerPort: maputil.GetOrDefaultInt32(options.ProviderServiceConfig, "listenerPort", 443),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -209,7 +218,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunDCDN.NewDeployer(&pAliyunDCDN.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -217,8 +226,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunDDoS.NewDeployer(&pAliyunDDoS.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -226,8 +235,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunESA.NewDeployer(&pAliyunESA.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- SiteId: maputil.GetInt64(options.ProviderExtendedConfig, "siteId"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ SiteId: maputil.GetInt64(options.ProviderServiceConfig, "siteId"),
})
return deployer, err
@@ -235,9 +244,20 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunFC.NewDeployer(&pAliyunFC.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ServiceVersion: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "serviceVersion", "3.0"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ServiceVersion: maputil.GetOrDefaultString(options.ProviderServiceConfig, "serviceVersion", "3.0"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
+ })
+ return deployer, err
+
+ case domain.DeploymentProviderTypeAliyunGA:
+ deployer, err := pAliyunGA.NewDeployer(&pAliyunGA.DeployerConfig{
+ AccessKeyId: access.AccessKeyId,
+ AccessKeySecret: access.AccessKeySecret,
+ ResourceType: pAliyunGA.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ AcceleratorId: maputil.GetString(options.ProviderServiceConfig, "acceleratorId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -245,8 +265,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunLive.NewDeployer(&pAliyunLive.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -254,10 +274,10 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunNLB.NewDeployer(&pAliyunNLB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pAliyunNLB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerId: maputil.GetString(options.ProviderExtendedConfig, "listenerId"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pAliyunNLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
})
return deployer, err
@@ -265,9 +285,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunOSS.NewDeployer(&pAliyunOSS.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Bucket: maputil.GetString(options.ProviderExtendedConfig, "bucket"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Bucket: maputil.GetString(options.ProviderServiceConfig, "bucket"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -275,8 +295,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunVOD.NewDeployer(&pAliyunVOD.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -284,10 +304,10 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAliyunWAF.NewDeployer(&pAliyunWAF.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ServiceVersion: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "serviceVersion", "3.0"),
- InstanceId: maputil.GetString(options.ProviderExtendedConfig, "instanceId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ServiceVersion: maputil.GetOrDefaultString(options.ProviderServiceConfig, "serviceVersion", "3.0"),
+ InstanceId: maputil.GetString(options.ProviderServiceConfig, "instanceId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -308,8 +328,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAWSACM.NewDeployer(&pAWSACM.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- CertificateArn: maputil.GetString(options.ProviderExtendedConfig, "certificateArn"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ CertificateArn: maputil.GetString(options.ProviderServiceConfig, "certificateArn"),
})
return deployer, err
@@ -317,8 +337,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pAWSCloudFront.NewDeployer(&pAWSCloudFront.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- DistributionId: maputil.GetString(options.ProviderExtendedConfig, "distributionId"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ DistributionId: maputil.GetString(options.ProviderServiceConfig, "distributionId"),
})
return deployer, err
@@ -341,8 +361,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
ClientId: access.ClientId,
ClientSecret: access.ClientSecret,
CloudName: access.CloudName,
- KeyVaultName: maputil.GetString(options.ProviderExtendedConfig, "keyvaultName"),
- CertificateName: maputil.GetString(options.ProviderExtendedConfig, "certificateName"),
+ KeyVaultName: maputil.GetString(options.ProviderServiceConfig, "keyvaultName"),
+ CertificateName: maputil.GetString(options.ProviderServiceConfig, "certificateName"),
})
return deployer, err
@@ -363,11 +383,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pBaiduCloudAppBLB.NewDeployer(&pBaiduCloudAppBLB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pBaiduCloudAppBLB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerPort: maputil.GetInt32(options.ProviderExtendedConfig, "listenerPort"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pBaiduCloudAppBLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerPort: maputil.GetInt32(options.ProviderServiceConfig, "listenerPort"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -375,11 +395,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pBaiduCloudBLB.NewDeployer(&pBaiduCloudBLB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pBaiduCloudBLB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerPort: maputil.GetInt32(options.ProviderExtendedConfig, "listenerPort"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pBaiduCloudBLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerPort: maputil.GetInt32(options.ProviderServiceConfig, "listenerPort"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -387,7 +407,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pBaiduCloudCDN.NewDeployer(&pBaiduCloudCDN.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -414,8 +434,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
case domain.DeploymentProviderTypeBaishanCDN:
deployer, err := pBaishanCDN.NewDeployer(&pBaishanCDN.DeployerConfig{
ApiToken: access.ApiToken,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
- CertificateId: maputil.GetString(options.ProviderExtendedConfig, "certificateId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
+ CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
@@ -437,7 +457,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
ApiUrl: access.ApiUrl,
ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
- AutoRestart: maputil.GetBool(options.ProviderExtendedConfig, "autoRestart"),
+ AutoRestart: maputil.GetBool(options.ProviderServiceConfig, "autoRestart"),
})
return deployer, err
@@ -446,9 +466,40 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
ApiUrl: access.ApiUrl,
ApiKey: access.ApiKey,
AllowInsecureConnections: access.AllowInsecureConnections,
- SiteType: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "siteType", "other"),
- SiteName: maputil.GetString(options.ProviderExtendedConfig, "siteName"),
- SiteNames: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderExtendedConfig, "siteNames"), ";"), func(s string) bool { return s != "" }),
+ SiteType: maputil.GetOrDefaultString(options.ProviderServiceConfig, "siteType", "other"),
+ SiteName: maputil.GetString(options.ProviderServiceConfig, "siteName"),
+ SiteNames: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderServiceConfig, "siteNames"), ";"), func(s string) bool { return s != "" }),
+ })
+ return deployer, err
+
+ default:
+ break
+ }
+ }
+
+ case domain.DeploymentProviderTypeBaotaWAFConsole, domain.DeploymentProviderTypeBaotaWAFSite:
+ {
+ access := domain.AccessConfigForBaotaWAF{}
+ if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ switch options.Provider {
+ case domain.DeploymentProviderTypeBaotaWAFConsole:
+ deployer, err := pBaotaWAFConsole.NewDeployer(&pBaotaWAFConsole.DeployerConfig{
+ ApiUrl: access.ApiUrl,
+ ApiKey: access.ApiKey,
+ AllowInsecureConnections: access.AllowInsecureConnections,
+ })
+ return deployer, err
+
+ case domain.DeploymentProviderTypeBaotaWAFSite:
+ deployer, err := pBaotaWAFSite.NewDeployer(&pBaotaWAFSite.DeployerConfig{
+ ApiUrl: access.ApiUrl,
+ ApiKey: access.ApiKey,
+ AllowInsecureConnections: access.AllowInsecureConnections,
+ SiteName: maputil.GetString(options.ProviderServiceConfig, "siteName"),
+ SitePort: maputil.GetOrDefaultInt32(options.ProviderServiceConfig, "sitePort", 443),
})
return deployer, err
@@ -466,8 +517,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pBunnyCDN.NewDeployer(&pBunnyCDN.DeployerConfig{
ApiKey: access.ApiKey,
- PullZoneId: maputil.GetString(options.ProviderExtendedConfig, "pullZoneId"),
- Hostname: maputil.GetString(options.ProviderExtendedConfig, "hostname"),
+ PullZoneId: maputil.GetString(options.ProviderServiceConfig, "pullZoneId"),
+ Hostname: maputil.GetString(options.ProviderServiceConfig, "hostname"),
})
return deployer, err
}
@@ -484,7 +535,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pBytePlusCDN.NewDeployer(&pBytePlusCDN.DeployerConfig{
AccessKey: access.AccessKey,
SecretKey: access.SecretKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -518,9 +569,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
ApiKey: access.ApiKey,
ApiSecret: access.ApiSecret,
AllowInsecureConnections: access.AllowInsecureConnections,
- ResourceType: pCdnfly.ResourceType(maputil.GetOrDefaultString(options.ProviderExtendedConfig, "resourceType", string(pCdnfly.RESOURCE_TYPE_SITE))),
- SiteId: maputil.GetString(options.ProviderExtendedConfig, "siteId"),
- CertificateId: maputil.GetString(options.ProviderExtendedConfig, "certificateId"),
+ ResourceType: pCdnfly.ResourceType(maputil.GetOrDefaultString(options.ProviderServiceConfig, "resourceType", string(pCdnfly.RESOURCE_TYPE_SITE))),
+ SiteId: maputil.GetString(options.ProviderServiceConfig, "siteId"),
+ CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
}
@@ -535,7 +586,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pDogeCDN.NewDeployer(&pDogeCDN.DeployerConfig{
AccessKey: access.AccessKey,
SecretKey: access.SecretKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
}
@@ -550,7 +601,26 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pEdgioApplications.NewDeployer(&pEdgioApplications.DeployerConfig{
ClientId: access.ClientId,
ClientSecret: access.ClientSecret,
- EnvironmentId: maputil.GetString(options.ProviderExtendedConfig, "environmentId"),
+ EnvironmentId: maputil.GetString(options.ProviderServiceConfig, "environmentId"),
+ })
+ return deployer, err
+ }
+
+ case domain.DeploymentProviderTypeFlexCDN:
+ {
+ access := domain.AccessConfigForFlexCDN{}
+ if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ deployer, err := pFlexCDN.NewDeployer(&pFlexCDN.DeployerConfig{
+ ApiUrl: access.ApiUrl,
+ ApiRole: access.ApiRole,
+ AccessKeyId: access.AccessKeyId,
+ AccessKey: access.AccessKey,
+ AllowInsecureConnections: access.AllowInsecureConnections,
+ ResourceType: pFlexCDN.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ CertificateId: maputil.GetInt64(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
}
@@ -566,8 +636,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
case domain.DeploymentProviderTypeGcoreCDN:
deployer, err := pGcoreCDN.NewDeployer(&pGcoreCDN.DeployerConfig{
ApiToken: access.ApiToken,
- ResourceId: maputil.GetInt64(options.ProviderExtendedConfig, "resourceId"),
- CertificateId: maputil.GetInt64(options.ProviderExtendedConfig, "certificateId"),
+ ResourceId: maputil.GetInt64(options.ProviderServiceConfig, "resourceId"),
+ CertificateId: maputil.GetInt64(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
@@ -589,8 +659,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
AccessKeyId: access.AccessKeyId,
AccessKey: access.AccessKey,
AllowInsecureConnections: access.AllowInsecureConnections,
- ResourceType: pGoEdge.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- CertificateId: maputil.GetInt64(options.ProviderExtendedConfig, "certificateId"),
+ ResourceType: pGoEdge.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ CertificateId: maputil.GetInt64(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
}
@@ -607,8 +677,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pHuaweiCloudCDN.NewDeployer(&pHuaweiCloudCDN.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -616,11 +686,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pHuaweiCloudELB.NewDeployer(&pHuaweiCloudELB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pHuaweiCloudELB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- CertificateId: maputil.GetString(options.ProviderExtendedConfig, "certificateId"),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerId: maputil.GetString(options.ProviderExtendedConfig, "listenerId"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pHuaweiCloudELB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
})
return deployer, err
@@ -635,10 +705,10 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pHuaweiCloudWAF.NewDeployer(&pHuaweiCloudWAF.DeployerConfig{
AccessKeyId: access.AccessKeyId,
SecretAccessKey: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pHuaweiCloudWAF.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- CertificateId: maputil.GetString(options.ProviderExtendedConfig, "certificateId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pHuaweiCloudWAF.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -659,10 +729,10 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pJDCloudALB.NewDeployer(&pJDCloudALB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- RegionId: maputil.GetString(options.ProviderExtendedConfig, "regionId"),
- ResourceType: pJDCloudALB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerId: maputil.GetString(options.ProviderExtendedConfig, "listenerId"),
+ RegionId: maputil.GetString(options.ProviderServiceConfig, "regionId"),
+ ResourceType: pJDCloudALB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
})
return deployer, err
@@ -670,7 +740,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pJDCloudCDN.NewDeployer(&pJDCloudCDN.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -678,7 +748,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pJDCloudLive.NewDeployer(&pJDCloudLive.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -686,7 +756,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pJDCloudVOD.NewDeployer(&pJDCloudVOD.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -695,21 +765,42 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
}
}
+ case domain.DeploymentProviderTypeLeCDN:
+ {
+ access := domain.AccessConfigForLeCDN{}
+ if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ deployer, err := pLeCDN.NewDeployer(&pLeCDN.DeployerConfig{
+ ApiUrl: access.ApiUrl,
+ ApiVersion: access.ApiVersion,
+ ApiRole: access.ApiRole,
+ Username: access.Username,
+ Password: access.Password,
+ AllowInsecureConnections: access.AllowInsecureConnections,
+ ResourceType: pLeCDN.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ CertificateId: maputil.GetInt64(options.ProviderServiceConfig, "certificateId"),
+ ClientId: maputil.GetInt64(options.ProviderServiceConfig, "clientId"),
+ })
+ return deployer, err
+ }
+
case domain.DeploymentProviderTypeLocal:
{
deployer, err := pLocal.NewDeployer(&pLocal.DeployerConfig{
- ShellEnv: pLocal.ShellEnvType(maputil.GetString(options.ProviderExtendedConfig, "shellEnv")),
- PreCommand: maputil.GetString(options.ProviderExtendedConfig, "preCommand"),
- PostCommand: maputil.GetString(options.ProviderExtendedConfig, "postCommand"),
- OutputFormat: pLocal.OutputFormatType(maputil.GetOrDefaultString(options.ProviderExtendedConfig, "format", string(pLocal.OUTPUT_FORMAT_PEM))),
- OutputCertPath: maputil.GetString(options.ProviderExtendedConfig, "certPath"),
- OutputServerCertPath: maputil.GetString(options.ProviderExtendedConfig, "certPathForServerOnly"),
- OutputIntermediaCertPath: maputil.GetString(options.ProviderExtendedConfig, "certPathForIntermediaOnly"),
- OutputKeyPath: maputil.GetString(options.ProviderExtendedConfig, "keyPath"),
- PfxPassword: maputil.GetString(options.ProviderExtendedConfig, "pfxPassword"),
- JksAlias: maputil.GetString(options.ProviderExtendedConfig, "jksAlias"),
- JksKeypass: maputil.GetString(options.ProviderExtendedConfig, "jksKeypass"),
- JksStorepass: maputil.GetString(options.ProviderExtendedConfig, "jksStorepass"),
+ ShellEnv: pLocal.ShellEnvType(maputil.GetString(options.ProviderServiceConfig, "shellEnv")),
+ PreCommand: maputil.GetString(options.ProviderServiceConfig, "preCommand"),
+ PostCommand: maputil.GetString(options.ProviderServiceConfig, "postCommand"),
+ OutputFormat: pLocal.OutputFormatType(maputil.GetOrDefaultString(options.ProviderServiceConfig, "format", string(pLocal.OUTPUT_FORMAT_PEM))),
+ OutputCertPath: maputil.GetString(options.ProviderServiceConfig, "certPath"),
+ OutputServerCertPath: maputil.GetString(options.ProviderServiceConfig, "certPathForServerOnly"),
+ OutputIntermediaCertPath: maputil.GetString(options.ProviderServiceConfig, "certPathForIntermediaOnly"),
+ OutputKeyPath: maputil.GetString(options.ProviderServiceConfig, "keyPath"),
+ PfxPassword: maputil.GetString(options.ProviderServiceConfig, "pfxPassword"),
+ JksAlias: maputil.GetString(options.ProviderServiceConfig, "jksAlias"),
+ JksKeypass: maputil.GetString(options.ProviderServiceConfig, "jksKeypass"),
+ JksStorepass: maputil.GetString(options.ProviderServiceConfig, "jksStorepass"),
})
return deployer, err
}
@@ -723,11 +814,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pK8sSecret.NewDeployer(&pK8sSecret.DeployerConfig{
KubeConfig: access.KubeConfig,
- Namespace: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "namespace", "default"),
- SecretName: maputil.GetString(options.ProviderExtendedConfig, "secretName"),
- SecretType: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "secretType", "kubernetes.io/tls"),
- SecretDataKeyForCrt: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "secretDataKeyForCrt", "tls.crt"),
- SecretDataKeyForKey: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "secretDataKeyForKey", "tls.key"),
+ Namespace: maputil.GetOrDefaultString(options.ProviderServiceConfig, "namespace", "default"),
+ SecretName: maputil.GetString(options.ProviderServiceConfig, "secretName"),
+ SecretType: maputil.GetOrDefaultString(options.ProviderServiceConfig, "secretType", "kubernetes.io/tls"),
+ SecretDataKeyForCrt: maputil.GetOrDefaultString(options.ProviderServiceConfig, "secretDataKeyForCrt", "tls.crt"),
+ SecretDataKeyForKey: maputil.GetOrDefaultString(options.ProviderServiceConfig, "secretDataKeyForKey", "tls.key"),
})
return deployer, err
}
@@ -741,7 +832,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pNetlifySite.NewDeployer(&pNetlifySite.DeployerConfig{
ApiToken: access.ApiToken,
- SiteId: maputil.GetString(options.ProviderExtendedConfig, "siteId"),
+ SiteId: maputil.GetString(options.ProviderServiceConfig, "siteId"),
})
return deployer, err
}
@@ -758,8 +849,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
ApiToken: access.ApiToken,
ApiTokenSecret: access.ApiTokenSecret,
AllowInsecureConnections: access.AllowInsecureConnections,
- NodeName: maputil.GetString(options.ProviderExtendedConfig, "nodeName"),
- AutoRestart: maputil.GetBool(options.ProviderExtendedConfig, "autoRestart"),
+ NodeName: maputil.GetString(options.ProviderServiceConfig, "nodeName"),
+ AutoRestart: maputil.GetBool(options.ProviderServiceConfig, "autoRestart"),
})
return deployer, err
}
@@ -776,7 +867,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pQiniuCDN.NewDeployer(&pQiniuCDN.DeployerConfig{
AccessKey: access.AccessKey,
SecretKey: access.SecretKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -784,8 +875,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pQiniuPili.NewDeployer(&pQiniuPili.DeployerConfig{
AccessKey: access.AccessKey,
SecretKey: access.SecretKey,
- Hub: maputil.GetString(options.ProviderExtendedConfig, "hub"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Hub: maputil.GetString(options.ProviderServiceConfig, "hub"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -805,8 +896,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
case domain.DeploymentProviderTypeTencentCloudCDN:
deployer, err := pRainYunRCDN.NewDeployer(&pRainYunRCDN.DeployerConfig{
ApiKey: access.ApiKey,
- InstanceId: maputil.GetInt32(options.ProviderExtendedConfig, "instanceId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ InstanceId: maputil.GetInt32(options.ProviderServiceConfig, "instanceId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -838,7 +929,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
AccessTokenId: access.AccessTokenId,
AccessToken: access.AccessToken,
AllowInsecureConnections: access.AllowInsecureConnections,
- SiteName: maputil.GetString(options.ProviderExtendedConfig, "siteName"),
+ SiteName: maputil.GetString(options.ProviderServiceConfig, "siteName"),
})
return deployer, err
@@ -858,8 +949,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
ApiUrl: access.ApiUrl,
ApiToken: access.ApiToken,
AllowInsecureConnections: access.AllowInsecureConnections,
- ResourceType: pSafeLine.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- CertificateId: maputil.GetInt32(options.ProviderExtendedConfig, "certificateId"),
+ ResourceType: pSafeLine.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ CertificateId: maputil.GetInt32(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
}
@@ -878,18 +969,18 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
SshPassword: access.Password,
SshKey: access.Key,
SshKeyPassphrase: access.KeyPassphrase,
- UseSCP: maputil.GetBool(options.ProviderExtendedConfig, "useSCP"),
- PreCommand: maputil.GetString(options.ProviderExtendedConfig, "preCommand"),
- PostCommand: maputil.GetString(options.ProviderExtendedConfig, "postCommand"),
- OutputFormat: pSSH.OutputFormatType(maputil.GetOrDefaultString(options.ProviderExtendedConfig, "format", string(pSSH.OUTPUT_FORMAT_PEM))),
- OutputCertPath: maputil.GetString(options.ProviderExtendedConfig, "certPath"),
- OutputServerCertPath: maputil.GetString(options.ProviderExtendedConfig, "certPathForServerOnly"),
- OutputIntermediaCertPath: maputil.GetString(options.ProviderExtendedConfig, "certPathForIntermediaOnly"),
- OutputKeyPath: maputil.GetString(options.ProviderExtendedConfig, "keyPath"),
- PfxPassword: maputil.GetString(options.ProviderExtendedConfig, "pfxPassword"),
- JksAlias: maputil.GetString(options.ProviderExtendedConfig, "jksAlias"),
- JksKeypass: maputil.GetString(options.ProviderExtendedConfig, "jksKeypass"),
- JksStorepass: maputil.GetString(options.ProviderExtendedConfig, "jksStorepass"),
+ UseSCP: maputil.GetBool(options.ProviderServiceConfig, "useSCP"),
+ PreCommand: maputil.GetString(options.ProviderServiceConfig, "preCommand"),
+ PostCommand: maputil.GetString(options.ProviderServiceConfig, "postCommand"),
+ OutputFormat: pSSH.OutputFormatType(maputil.GetOrDefaultString(options.ProviderServiceConfig, "format", string(pSSH.OUTPUT_FORMAT_PEM))),
+ OutputCertPath: maputil.GetString(options.ProviderServiceConfig, "certPath"),
+ OutputServerCertPath: maputil.GetString(options.ProviderServiceConfig, "certPathForServerOnly"),
+ OutputIntermediaCertPath: maputil.GetString(options.ProviderServiceConfig, "certPathForIntermediaOnly"),
+ OutputKeyPath: maputil.GetString(options.ProviderServiceConfig, "keyPath"),
+ PfxPassword: maputil.GetString(options.ProviderServiceConfig, "pfxPassword"),
+ JksAlias: maputil.GetString(options.ProviderServiceConfig, "jksAlias"),
+ JksKeypass: maputil.GetString(options.ProviderServiceConfig, "jksKeypass"),
+ JksStorepass: maputil.GetString(options.ProviderServiceConfig, "jksStorepass"),
})
return deployer, err
}
@@ -906,7 +997,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudCDN.NewDeployer(&pTencentCloudCDN.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -914,11 +1005,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudCLB.NewDeployer(&pTencentCloudCLB.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pTencentCloudCLB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerId: maputil.GetString(options.ProviderExtendedConfig, "listenerId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pTencentCloudCLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -926,9 +1017,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudCOS.NewDeployer(&pTencentCloudCOS.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Bucket: maputil.GetString(options.ProviderExtendedConfig, "bucket"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Bucket: maputil.GetString(options.ProviderServiceConfig, "bucket"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -936,7 +1027,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudCSS.NewDeployer(&pTencentCloudCSS.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -944,7 +1035,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudECDN.NewDeployer(&pTencentCloudECDN.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -952,8 +1043,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudEO.NewDeployer(&pTencentCloudEO.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- ZoneId: maputil.GetString(options.ProviderExtendedConfig, "zoneId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ ZoneId: maputil.GetString(options.ProviderServiceConfig, "zoneId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -961,8 +1052,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudSCF.NewDeployer(&pTencentCloudSCF.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -977,9 +1068,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudSSLDeploy.NewDeployer(&pTencentCloudSSLDeploy.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: maputil.GetString(options.ProviderExtendedConfig, "resourceType"),
- ResourceIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderExtendedConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: maputil.GetString(options.ProviderServiceConfig, "resourceType"),
+ ResourceIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderServiceConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }),
})
return deployer, err
@@ -987,8 +1078,8 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudVOD.NewDeployer(&pTencentCloudVOD.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- SubAppId: maputil.GetInt64(options.ProviderExtendedConfig, "subAppId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ SubAppId: maputil.GetInt64(options.ProviderServiceConfig, "subAppId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -996,9 +1087,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pTencentCloudWAF.NewDeployer(&pTencentCloudWAF.DeployerConfig{
SecretId: access.SecretId,
SecretKey: access.SecretKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
- DomainId: maputil.GetString(options.ProviderExtendedConfig, "domainId"),
- InstanceId: maputil.GetString(options.ProviderExtendedConfig, "instanceId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
+ DomainId: maputil.GetString(options.ProviderServiceConfig, "domainId"),
+ InstanceId: maputil.GetString(options.ProviderServiceConfig, "instanceId"),
})
return deployer, err
@@ -1020,7 +1111,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
PrivateKey: access.PrivateKey,
PublicKey: access.PublicKey,
ProjectId: access.ProjectId,
- DomainId: maputil.GetString(options.ProviderExtendedConfig, "domainId"),
+ DomainId: maputil.GetString(options.ProviderServiceConfig, "domainId"),
})
return deployer, err
@@ -1029,9 +1120,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
PrivateKey: access.PrivateKey,
PublicKey: access.PublicKey,
ProjectId: access.ProjectId,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Bucket: maputil.GetString(options.ProviderExtendedConfig, "bucket"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Bucket: maputil.GetString(options.ProviderServiceConfig, "bucket"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1052,7 +1143,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pUpyunCDN.NewDeployer(&pUpyunCDN.DeployerConfig{
Username: access.Username,
Password: access.Password,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1073,11 +1164,11 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineALB.NewDeployer(&pVolcEngineALB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pVolcEngineALB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerId: maputil.GetString(options.ProviderExtendedConfig, "listenerId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pVolcEngineALB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1085,7 +1176,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineCDN.NewDeployer(&pVolcEngineCDN.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1093,7 +1184,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineCertCenter.NewDeployer(&pVolcEngineCertCenter.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
})
return deployer, err
@@ -1101,10 +1192,10 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineCLB.NewDeployer(&pVolcEngineCLB.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ResourceType: pVolcEngineCLB.ResourceType(maputil.GetString(options.ProviderExtendedConfig, "resourceType")),
- LoadbalancerId: maputil.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
- ListenerId: maputil.GetString(options.ProviderExtendedConfig, "listenerId"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ResourceType: pVolcEngineCLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
+ LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
+ ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
})
return deployer, err
@@ -1112,7 +1203,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineDCDN.NewDeployer(&pVolcEngineDCDN.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1120,9 +1211,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineImageX.NewDeployer(&pVolcEngineImageX.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- ServiceId: maputil.GetString(options.ProviderExtendedConfig, "serviceId"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ ServiceId: maputil.GetString(options.ProviderServiceConfig, "serviceId"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1130,7 +1221,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineLive.NewDeployer(&pVolcEngineLive.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1138,9 +1229,9 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pVolcEngineTOS.NewDeployer(&pVolcEngineTOS.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.SecretAccessKey,
- Region: maputil.GetString(options.ProviderExtendedConfig, "region"),
- Bucket: maputil.GetString(options.ProviderExtendedConfig, "bucket"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
+ Region: maputil.GetString(options.ProviderServiceConfig, "region"),
+ Bucket: maputil.GetString(options.ProviderServiceConfig, "bucket"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
})
return deployer, err
@@ -1149,7 +1240,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
}
}
- case domain.DeploymentProviderTypeWangsuCDNPro:
+ case domain.DeploymentProviderTypeWangsuCDN, domain.DeploymentProviderTypeWangsuCDNPro, domain.DeploymentProviderTypeWangsuCertificate:
{
access := domain.AccessConfigForWangsu{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
@@ -1157,15 +1248,31 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
}
switch options.Provider {
+ case domain.DeploymentProviderTypeWangsuCDN:
+ deployer, err := pWangsuCDN.NewDeployer(&pWangsuCDN.DeployerConfig{
+ AccessKeyId: access.AccessKeyId,
+ AccessKeySecret: access.AccessKeySecret,
+ Domains: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderServiceConfig, "domains"), ";"), func(s string) bool { return s != "" }),
+ })
+ return deployer, err
+
case domain.DeploymentProviderTypeWangsuCDNPro:
deployer, err := pWangsuCDNPro.NewDeployer(&pWangsuCDNPro.DeployerConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
ApiKey: access.ApiKey,
- Environment: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "environment", "production"),
- Domain: maputil.GetString(options.ProviderExtendedConfig, "domain"),
- CertificateId: maputil.GetString(options.ProviderExtendedConfig, "certificateId"),
- WebhookId: maputil.GetString(options.ProviderExtendedConfig, "webhookId"),
+ Environment: maputil.GetOrDefaultString(options.ProviderServiceConfig, "environment", "production"),
+ Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
+ CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
+ WebhookId: maputil.GetString(options.ProviderServiceConfig, "webhookId"),
+ })
+ return deployer, err
+
+ case domain.DeploymentProviderTypeWangsuCertificate:
+ deployer, err := pWangsuCertificate.NewDeployer(&pWangsuCertificate.DeployerConfig{
+ AccessKeyId: access.AccessKeyId,
+ AccessKeySecret: access.AccessKeySecret,
+ CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
})
return deployer, err
@@ -1191,7 +1298,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
}
}
- if extendedHeadersString := maputil.GetString(options.ProviderExtendedConfig, "headers"); extendedHeadersString != "" {
+ if extendedHeadersString := maputil.GetString(options.ProviderServiceConfig, "headers"); extendedHeadersString != "" {
h, err := httputil.ParseHeaders(extendedHeadersString)
if err != nil {
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
@@ -1203,7 +1310,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{
WebhookUrl: access.Url,
- WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.DefaultDataForDeployment),
+ WebhookData: maputil.GetOrDefaultString(options.ProviderServiceConfig, "webhookData", access.DefaultDataForDeployment),
Method: access.Method,
Headers: mergedHeaders,
AllowInsecureConnections: access.AllowInsecureConnections,
diff --git a/internal/domain/access.go b/internal/domain/access.go
index 8bc5d0ef..cb5b7708 100644
--- a/internal/domain/access.go
+++ b/internal/domain/access.go
@@ -17,10 +17,17 @@ type Access struct {
type AccessConfigFor1Panel struct {
ApiUrl string `json:"apiUrl"`
+ ApiVersion string `json:"apiVersion"`
ApiKey string `json:"apiKey"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
}
+type AccessConfigForACMECA struct {
+ Endpoint string `json:"endpoint"`
+ EabKid string `json:"eabKid,omitempty"`
+ EabHmacKey string `json:"eabHmacKey,omitempty"`
+}
+
type AccessConfigForACMEHttpReq struct {
Endpoint string `json:"endpoint"`
Mode string `json:"mode,omitempty"`
@@ -60,6 +67,12 @@ type AccessConfigForBaotaPanel struct {
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
}
+type AccessConfigForBaotaWAF struct {
+ ApiUrl string `json:"apiUrl"`
+ ApiKey string `json:"apiKey"`
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+}
+
type AccessConfigForBytePlus struct {
AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"`
@@ -133,6 +146,14 @@ type AccessConfigForEmail struct {
DefaultReceiverAddress string `json:"defaultReceiverAddress,omitempty"`
}
+type AccessConfigForFlexCDN struct {
+ ApiUrl string `json:"apiUrl"`
+ ApiRole string `json:"apiRole"`
+ AccessKeyId string `json:"accessKeyId"`
+ AccessKey string `json:"accessKey"`
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+}
+
type AccessConfigForGcore struct {
ApiToken string `json:"apiToken"`
}
@@ -178,6 +199,15 @@ type AccessConfigForLarkBot struct {
WebhookUrl string `json:"webhookUrl"`
}
+type AccessConfigForLeCDN struct {
+ ApiUrl string `json:"apiUrl"`
+ ApiVersion string `json:"apiVersion"`
+ ApiRole string `json:"apiRole"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+}
+
type AccessConfigForMattermost struct {
ServerUrl string `json:"serverUrl"`
Username string `json:"username"`
@@ -242,7 +272,7 @@ type AccessConfigForRainYun struct {
type AccessConfigForRatPanel struct {
ApiUrl string `json:"apiUrl"`
- AccessTokenId uint `json:"accessTokenId"`
+ AccessTokenId int32 `json:"accessTokenId"`
AccessToken string `json:"accessToken"`
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
}
diff --git a/internal/domain/certificate.go b/internal/domain/certificate.go
index d2a998da..710ce268 100644
--- a/internal/domain/certificate.go
+++ b/internal/domain/certificate.go
@@ -20,7 +20,7 @@ type Certificate struct {
SerialNumber string `json:"serialNumber" db:"serialNumber"`
Certificate string `json:"certificate" db:"certificate"`
PrivateKey string `json:"privateKey" db:"privateKey"`
- Issuer string `json:"issuer" db:"issuer"`
+ IssuerOrg string `json:"issuerOrg" db:"issuerOrg"`
IssuerCertificate string `json:"issuerCertificate" db:"issuerCertificate"`
KeyAlgorithm CertificateKeyAlgorithmType `json:"keyAlgorithm" db:"keyAlgorithm"`
EffectAt time.Time `json:"effectAt" db:"effectAt"`
@@ -38,7 +38,7 @@ type Certificate struct {
func (c *Certificate) PopulateFromX509(certX509 *x509.Certificate) *Certificate {
c.SubjectAltNames = strings.Join(certX509.DNSNames, ";")
c.SerialNumber = strings.ToUpper(certX509.SerialNumber.Text(16))
- c.Issuer = strings.Join(certX509.Issuer.Organization, ";")
+ c.IssuerOrg = strings.Join(certX509.Issuer.Organization, ";")
c.EffectAt = certX509.NotBefore
c.ExpireAt = certX509.NotAfter
diff --git a/internal/domain/provider.go b/internal/domain/provider.go
index 4a0c05dd..db0de59d 100644
--- a/internal/domain/provider.go
+++ b/internal/domain/provider.go
@@ -10,7 +10,7 @@ type AccessProviderType string
*/
const (
AccessProviderType1Panel = AccessProviderType("1panel")
- AccessProviderTypeACMECA = AccessProviderType("acmeca") // ACME CA(预留)
+ AccessProviderTypeACMECA = AccessProviderType("acmeca")
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai(预留)
AccessProviderTypeAliyun = AccessProviderType("aliyun")
@@ -19,6 +19,7 @@ const (
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
AccessProviderTypeBaishan = AccessProviderType("baishan")
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
+ AccessProviderTypeBaotaWAF = AccessProviderType("baotawaf")
AccessProviderTypeBytePlus = AccessProviderType("byteplus")
AccessProviderTypeBunny = AccessProviderType("bunny")
AccessProviderTypeBuypass = AccessProviderType("buypass")
@@ -36,8 +37,8 @@ const (
AccessProviderTypeDynv6 = AccessProviderType("dynv6")
AccessProviderTypeEdgio = AccessProviderType("edgio")
AccessProviderTypeEmail = AccessProviderType("email")
- AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留)
- AccessProviderTypeFlexCDN = AccessProviderType("flexcdn") // FlexCDN(预留)
+ AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留)
+ AccessProviderTypeFlexCDN = AccessProviderType("flexcdn")
AccessProviderTypeGname = AccessProviderType("gname")
AccessProviderTypeGcore = AccessProviderType("gcore")
AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
@@ -49,7 +50,7 @@ const (
AccessProviderTypeLarkBot = AccessProviderType("larkbot")
AccessProviderTypeLetsEncrypt = AccessProviderType("letsencrypt")
AccessProviderTypeLetsEncryptStaging = AccessProviderType("letsencryptstaging")
- AccessProviderTypeLeCDN = AccessProviderType("lecdn") // LeCDN(预留)
+ AccessProviderTypeLeCDN = AccessProviderType("lecdn")
AccessProviderTypeLocal = AccessProviderType("local")
AccessProviderTypeMattermost = AccessProviderType("mattermost")
AccessProviderTypeNamecheap = AccessProviderType("namecheap")
@@ -91,6 +92,7 @@ type CAProviderType string
NOTICE: If you add new constant, please keep ASCII order.
*/
const (
+ CAProviderTypeACMECA = CAProviderType(AccessProviderTypeACMECA)
CAProviderTypeBuypass = CAProviderType(AccessProviderTypeBuypass)
CAProviderTypeGoogleTrustServices = CAProviderType(AccessProviderTypeGoogleTrustServices)
CAProviderTypeLetsEncrypt = CAProviderType(AccessProviderTypeLetsEncrypt)
@@ -173,7 +175,7 @@ const (
DeploymentProviderTypeAliyunDDoS = DeploymentProviderType(AccessProviderTypeAliyun + "-ddos")
DeploymentProviderTypeAliyunESA = DeploymentProviderType(AccessProviderTypeAliyun + "-esa")
DeploymentProviderTypeAliyunFC = DeploymentProviderType(AccessProviderTypeAliyun + "-fc")
- DeploymentProviderTypeAliyunGA = DeploymentProviderType(AccessProviderTypeAliyun + "-ga") // 阿里云全球加速(预留)
+ DeploymentProviderTypeAliyunGA = DeploymentProviderType(AccessProviderTypeAliyun + "-ga")
DeploymentProviderTypeAliyunLive = DeploymentProviderType(AccessProviderTypeAliyun + "-live")
DeploymentProviderTypeAliyunNLB = DeploymentProviderType(AccessProviderTypeAliyun + "-nlb")
DeploymentProviderTypeAliyunOSS = DeploymentProviderType(AccessProviderTypeAliyun + "-oss")
@@ -189,13 +191,15 @@ const (
DeploymentProviderTypeBaishanCDN = DeploymentProviderType(AccessProviderTypeBaishan + "-cdn")
DeploymentProviderTypeBaotaPanelConsole = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-console")
DeploymentProviderTypeBaotaPanelSite = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-site")
+ DeploymentProviderTypeBaotaWAFConsole = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-console")
+ DeploymentProviderTypeBaotaWAFSite = DeploymentProviderType(AccessProviderTypeBaotaWAF + "-site")
DeploymentProviderTypeBunnyCDN = DeploymentProviderType(AccessProviderTypeBunny + "-cdn")
DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn")
DeploymentProviderTypeCacheFly = DeploymentProviderType(AccessProviderTypeCacheFly)
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
DeploymentProviderTypeEdgioApplications = DeploymentProviderType(AccessProviderTypeEdgio + "-applications")
- DeploymentProviderTypeFlexCDN = DeploymentProviderType(AccessProviderTypeFlexCDN) // FlexCDN(预留)
+ DeploymentProviderTypeFlexCDN = DeploymentProviderType(AccessProviderTypeFlexCDN)
DeploymentProviderTypeGcoreCDN = DeploymentProviderType(AccessProviderTypeGcore + "-cdn")
DeploymentProviderTypeGoEdge = DeploymentProviderType(AccessProviderTypeGoEdge)
DeploymentProviderTypeHuaweiCloudCDN = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-cdn")
@@ -207,7 +211,7 @@ const (
DeploymentProviderTypeJDCloudLive = DeploymentProviderType(AccessProviderTypeJDCloud + "-live")
DeploymentProviderTypeJDCloudVOD = DeploymentProviderType(AccessProviderTypeJDCloud + "-vod")
DeploymentProviderTypeKubernetesSecret = DeploymentProviderType(AccessProviderTypeKubernetes + "-secret")
- DeploymentProviderTypeLeCDN = DeploymentProviderType(AccessProviderTypeLeCDN) // LeCDN(预留)
+ DeploymentProviderTypeLeCDN = DeploymentProviderType(AccessProviderTypeLeCDN)
DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal)
DeploymentProviderTypeNetlifySite = DeploymentProviderType(AccessProviderTypeNetlify + "-site")
DeploymentProviderTypeProxmoxVE = DeploymentProviderType(AccessProviderTypeProxmoxVE)
@@ -242,9 +246,9 @@ const (
DeploymentProviderTypeVolcEngineImageX = DeploymentProviderType(AccessProviderTypeVolcEngine + "-imagex")
DeploymentProviderTypeVolcEngineLive = DeploymentProviderType(AccessProviderTypeVolcEngine + "-live")
DeploymentProviderTypeVolcEngineTOS = DeploymentProviderType(AccessProviderTypeVolcEngine + "-tos")
- DeploymentProviderTypeWangsuCDN = DeploymentProviderType(AccessProviderTypeWangsu + "-cdn") // 网宿 CDN(预留)
+ DeploymentProviderTypeWangsuCDN = DeploymentProviderType(AccessProviderTypeWangsu + "-cdn")
DeploymentProviderTypeWangsuCDNPro = DeploymentProviderType(AccessProviderTypeWangsu + "-cdnpro")
- DeploymentProviderTypeWangsuCert = DeploymentProviderType(AccessProviderTypeWangsu + "-cert") // 网宿证书管理(预留)
+ DeploymentProviderTypeWangsuCertificate = DeploymentProviderType(AccessProviderTypeWangsu + "-certificate")
DeploymentProviderTypeWebhook = DeploymentProviderType(AccessProviderTypeWebhook)
)
diff --git a/internal/notify/notifier.go b/internal/notify/notifier.go
index 955e88c3..ee3fbd2f 100644
--- a/internal/notify/notifier.go
+++ b/internal/notify/notifier.go
@@ -31,9 +31,9 @@ func NewWithWorkflowNode(config NotifierWithWorkflowNodeConfig) (Notifier, error
nodeConfig := config.Node.GetConfigForNotify()
options := ¬ifierProviderOptions{
- Provider: domain.NotificationProviderType(nodeConfig.Provider),
- ProviderAccessConfig: make(map[string]any),
- ProviderExtendedConfig: nodeConfig.ProviderConfig,
+ Provider: domain.NotificationProviderType(nodeConfig.Provider),
+ ProviderAccessConfig: make(map[string]any),
+ ProviderServiceConfig: nodeConfig.ProviderConfig,
}
accessRepo := repository.NewAccessRepository()
diff --git a/internal/notify/providers.go b/internal/notify/providers.go
index 70787480..3a8c575d 100644
--- a/internal/notify/providers.go
+++ b/internal/notify/providers.go
@@ -18,9 +18,9 @@ import (
)
type notifierProviderOptions struct {
- Provider domain.NotificationProviderType
- ProviderAccessConfig map[string]any
- ProviderExtendedConfig map[string]any
+ Provider domain.NotificationProviderType
+ ProviderAccessConfig map[string]any
+ ProviderServiceConfig map[string]any
}
func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier, error) {
@@ -55,8 +55,8 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
SmtpTls: access.SmtpTls,
Username: access.Username,
Password: access.Password,
- SenderAddress: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "senderAddress", access.DefaultSenderAddress),
- ReceiverAddress: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "receiverAddress", access.DefaultReceiverAddress),
+ SenderAddress: maputil.GetOrDefaultString(options.ProviderServiceConfig, "senderAddress", access.DefaultSenderAddress),
+ ReceiverAddress: maputil.GetOrDefaultString(options.ProviderServiceConfig, "receiverAddress", access.DefaultReceiverAddress),
})
}
@@ -83,7 +83,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
ServerUrl: access.ServerUrl,
Username: access.Username,
Password: access.Password,
- ChannelId: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "channelId", access.DefaultChannelId),
+ ChannelId: maputil.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
})
}
@@ -96,7 +96,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
return pTelegramBot.NewNotifier(&pTelegramBot.NotifierConfig{
BotToken: access.BotToken,
- ChatId: maputil.GetOrDefaultInt64(options.ProviderExtendedConfig, "chatId", access.DefaultChatId),
+ ChatId: maputil.GetOrDefaultInt64(options.ProviderServiceConfig, "chatId", access.DefaultChatId),
})
}
@@ -117,7 +117,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
mergedHeaders[http.CanonicalHeaderKey(key)] = h.Get(key)
}
}
- if extendedHeadersString := maputil.GetString(options.ProviderExtendedConfig, "headers"); extendedHeadersString != "" {
+ if extendedHeadersString := maputil.GetString(options.ProviderServiceConfig, "headers"); extendedHeadersString != "" {
h, err := httputil.ParseHeaders(extendedHeadersString)
if err != nil {
return nil, fmt.Errorf("failed to parse webhook headers: %w", err)
@@ -129,7 +129,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
return pWebhook.NewNotifier(&pWebhook.NotifierConfig{
WebhookUrl: access.Url,
- WebhookData: maputil.GetOrDefaultString(options.ProviderExtendedConfig, "webhookData", access.DefaultDataForNotification),
+ WebhookData: maputil.GetOrDefaultString(options.ProviderServiceConfig, "webhookData", access.DefaultDataForNotification),
Method: access.Method,
Headers: mergedHeaders,
AllowInsecureConnections: access.AllowInsecureConnections,
diff --git a/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go
index 069e01f9..e81b264f 100644
--- a/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go
+++ b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go
@@ -9,12 +9,15 @@ import (
"net/url"
"github.com/usual2970/certimate/internal/pkg/core/deployer"
- opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
+ onepanelsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
)
type DeployerConfig struct {
// 1Panel 地址。
ApiUrl string `json:"apiUrl"`
+ // 1Panel 版本。
+ // 可取值 "v1"、"v2"。
+ ApiVersion string `json:"apiVersion"`
// 1Panel 接口密钥。
ApiKey string `json:"apiKey"`
// 是否允许不安全的连接。
@@ -26,7 +29,7 @@ type DeployerConfig struct {
type DeployerProvider struct {
config *DeployerConfig
logger *slog.Logger
- sdkClient *opsdk.Client
+ sdkClient *onepanelsdk.Client
}
var _ deployer.Deployer = (*DeployerProvider)(nil)
@@ -36,7 +39,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil")
}
- client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
+ client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiKey, config.AllowInsecureConnections)
if err != nil {
return nil, fmt.Errorf("failed to create sdk client: %w", err)
}
@@ -59,7 +62,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
// 设置面板 SSL 证书
- updateSystemSSLReq := &opsdk.UpdateSystemSSLRequest{
+ updateSystemSSLReq := &onepanelsdk.UpdateSystemSSLRequest{
Cert: certPEM,
Key: privkeyPEM,
SSL: "enable",
@@ -79,16 +82,20 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
return &deployer.DeployResult{}, nil
}
-func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) {
+func createSdkClient(apiUrl, apiVersion, apiKey string, skipTlsVerify bool) (*onepanelsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid 1panel api url")
}
+ if apiVersion == "" {
+ return nil, errors.New("invalid 1panel api version")
+ }
+
if apiKey == "" {
return nil, errors.New("invalid 1panel api key")
}
- client := opsdk.NewClient(apiUrl, apiKey)
+ client := onepanelsdk.NewClient(apiUrl, apiVersion, apiKey)
if skipTlsVerify {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
}
diff --git a/internal/pkg/core/deployer/providers/1panel-console/1panel_console_test.go b/internal/pkg/core/deployer/providers/1panel-console/1panel_console_test.go
index abec586c..88bf961a 100644
--- a/internal/pkg/core/deployer/providers/1panel-console/1panel_console_test.go
+++ b/internal/pkg/core/deployer/providers/1panel-console/1panel_console_test.go
@@ -15,6 +15,7 @@ var (
fInputCertPath string
fInputKeyPath string
fApiUrl string
+ fApiVersion string
fApiKey string
)
@@ -24,6 +25,7 @@ func init() {
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
+ flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v1", "")
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
}
@@ -34,6 +36,7 @@ Shell command to run this test:
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIURL="http://127.0.0.1:20410" \
+ --CERTIMATE_DEPLOYER_1PANELCONSOLE_APIVERSION="v1" \
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIKEY="your-api-key"
*/
func TestDeploy(t *testing.T) {
@@ -45,11 +48,13 @@ func TestDeploy(t *testing.T) {
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
fmt.Sprintf("APIURL: %v", fApiUrl),
+ fmt.Sprintf("APIVERSION: %v", fApiVersion),
fmt.Sprintf("APIKEY: %v", fApiKey),
}, "\n"))
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl,
+ ApiVersion: fApiVersion,
ApiKey: fApiKey,
AllowInsecureConnections: true,
AutoRestart: true,
diff --git a/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go
index 7d360c77..690e5242 100644
--- a/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go
+++ b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go
@@ -12,12 +12,15 @@ import (
"github.com/usual2970/certimate/internal/pkg/core/deployer"
"github.com/usual2970/certimate/internal/pkg/core/uploader"
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/1panel-ssl"
- opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
+ onepanelsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
)
type DeployerConfig struct {
// 1Panel 地址。
ApiUrl string `json:"apiUrl"`
+ // 1Panel 版本。
+ // 可取值 "v1"、"v2"。
+ ApiVersion string `json:"apiVersion"`
// 1Panel 接口密钥。
ApiKey string `json:"apiKey"`
// 是否允许不安全的连接。
@@ -35,7 +38,7 @@ type DeployerConfig struct {
type DeployerProvider struct {
config *DeployerConfig
logger *slog.Logger
- sdkClient *opsdk.Client
+ sdkClient *onepanelsdk.Client
sslUploader uploader.Uploader
}
@@ -46,14 +49,15 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
panic("config is nil")
}
- client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
+ client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiKey, config.AllowInsecureConnections)
if err != nil {
return nil, fmt.Errorf("failed to create sdk client: %w", err)
}
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
- ApiUrl: config.ApiUrl,
- ApiKey: config.ApiKey,
+ ApiUrl: config.ApiUrl,
+ ApiVersion: config.ApiVersion,
+ ApiKey: config.ApiKey,
})
if err != nil {
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
@@ -103,7 +107,7 @@ func (d *DeployerProvider) deployToWebsite(ctx context.Context, certPEM string,
}
// 获取网站 HTTPS 配置
- getHttpsConfReq := &opsdk.GetHttpsConfRequest{
+ getHttpsConfReq := &onepanelsdk.GetHttpsConfRequest{
WebsiteID: d.config.WebsiteId,
}
getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq)
@@ -122,7 +126,7 @@ func (d *DeployerProvider) deployToWebsite(ctx context.Context, certPEM string,
// 修改网站 HTTPS 配置
certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
- updateHttpsConfReq := &opsdk.UpdateHttpsConfRequest{
+ updateHttpsConfReq := &onepanelsdk.UpdateHttpsConfRequest{
WebsiteID: d.config.WebsiteId,
Type: "existed",
WebsiteSSLID: certId,
@@ -147,7 +151,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
}
// 获取证书详情
- getWebsiteSSLReq := &opsdk.GetWebsiteSSLRequest{
+ getWebsiteSSLReq := &onepanelsdk.GetWebsiteSSLRequest{
SSLID: d.config.CertificateId,
}
getWebsiteSSLResp, err := d.sdkClient.GetWebsiteSSL(getWebsiteSSLReq)
@@ -157,7 +161,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
}
// 更新证书
- uploadWebsiteSSLReq := &opsdk.UploadWebsiteSSLRequest{
+ uploadWebsiteSSLReq := &onepanelsdk.UploadWebsiteSSLRequest{
Type: "paste",
SSLID: d.config.CertificateId,
Description: getWebsiteSSLResp.Data.Description,
@@ -173,16 +177,20 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
return nil
}
-func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) {
+func createSdkClient(apiUrl, apiVersion, apiKey string, skipTlsVerify bool) (*onepanelsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid 1panel api url")
}
+ if apiVersion == "" {
+ return nil, errors.New("invalid 1panel api version")
+ }
+
if apiKey == "" {
return nil, errors.New("invalid 1panel api key")
}
- client := opsdk.NewClient(apiUrl, apiKey)
+ client := onepanelsdk.NewClient(apiUrl, apiVersion, apiKey)
if skipTlsVerify {
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
}
diff --git a/internal/pkg/core/deployer/providers/1panel-site/1panel_site_test.go b/internal/pkg/core/deployer/providers/1panel-site/1panel_site_test.go
index 702584e3..1d5bafef 100644
--- a/internal/pkg/core/deployer/providers/1panel-site/1panel_site_test.go
+++ b/internal/pkg/core/deployer/providers/1panel-site/1panel_site_test.go
@@ -15,6 +15,7 @@ var (
fInputCertPath string
fInputKeyPath string
fApiUrl string
+ fApiVersion string
fApiKey string
fWebsiteId int64
)
@@ -25,6 +26,7 @@ func init() {
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
+ flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v1", "")
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
flag.Int64Var(&fWebsiteId, argsPrefix+"WEBSITEID", 0, "")
}
@@ -36,6 +38,7 @@ Shell command to run this test:
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_DEPLOYER_1PANELSITE_APIURL="http://127.0.0.1:20410" \
+ --CERTIMATE_DEPLOYER_1PANELSITE_APIVERSION="v1" \
--CERTIMATE_DEPLOYER_1PANELSITE_APIKEY="your-api-key" \
--CERTIMATE_DEPLOYER_1PANELSITE_WEBSITEID="your-website-id"
*/
@@ -48,12 +51,14 @@ func TestDeploy(t *testing.T) {
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
fmt.Sprintf("APIURL: %v", fApiUrl),
+ fmt.Sprintf("APIVERSION: %v", fApiVersion),
fmt.Sprintf("APIKEY: %v", fApiKey),
fmt.Sprintf("WEBSITEID: %v", fWebsiteId),
}, "\n"))
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl,
+ ApiVersion: fApiVersion,
ApiKey: fApiKey,
AllowInsecureConnections: true,
ResourceType: provider.RESOURCE_TYPE_WEBSITE,
diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go
index 3dca4a9d..35b4997c 100644
--- a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go
+++ b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go
@@ -157,7 +157,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
if listListenersResp.Body.Listeners != nil {
for _, listener := range listListenersResp.Body.Listeners {
- listenerIds = append(listenerIds, *listener.ListenerId)
+ listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
}
@@ -192,7 +192,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
if listListenersResp.Body.Listeners != nil {
for _, listener := range listListenersResp.Body.Listeners {
- listenerIds = append(listenerIds, *listener.ListenerId)
+ listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
}
@@ -211,8 +211,13 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
d.logger.Info("found https/quic listeners to deploy", slog.Any("listenerIds", listenerIds))
for _, listenerId := range listenerIds {
- if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
- errs = append(errs, err)
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
+ errs = append(errs, err)
+ }
}
}
diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go
index c75119e9..11d5b565 100644
--- a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go
+++ b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go
@@ -96,6 +96,7 @@ func TestDeploy(t *testing.T) {
fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
fmt.Sprintf("REGION: %v", fRegion),
fmt.Sprintf("LISTENERID: %v", fListenerId),
+ fmt.Sprintf("DOMAIN: %v", fDomain),
}, "\n"))
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
diff --git a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go
index d443514e..34c3a49e 100644
--- a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go
+++ b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go
@@ -171,7 +171,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
select {
case <-ctx.Done():
return ctx.Err()
-
default:
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listenerPort, cloudCertId); err != nil {
errs = append(errs, err)
diff --git a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go
index 3b8ce12d..dfa46173 100644
--- a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go
+++ b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go
@@ -18,7 +18,7 @@ var (
fAccessKeySecret string
fRegion string
fLoadbalancerId string
- fListenerPort int
+ fListenerPort int64
fDomain string
)
@@ -31,7 +31,7 @@ func init() {
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "")
- flag.IntVar(&fListenerPort, argsPrefix+"LISTENERPORT", 443, "")
+ flag.Int64Var(&fListenerPort, argsPrefix+"LISTENERPORT", 443, "")
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
}
diff --git a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go
index 8557068c..426aa3a6 100644
--- a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go
+++ b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go
@@ -22,6 +22,7 @@ type DeployerConfig struct {
// 阿里云地域。
Region string `json:"region"`
// 服务版本。
+ // 可取值 "2.0"、"3.0"。
ServiceVersion string `json:"serviceVersion"`
// 自定义域名(支持泛域名)。
Domain string `json:"domain"`
diff --git a/internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga.go b/internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga.go
new file mode 100644
index 00000000..f69660a8
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga.go
@@ -0,0 +1,322 @@
+package aliyunga
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log/slog"
+ "strings"
+
+ aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
+ aliga "github.com/alibabacloud-go/ga-20191120/v3/client"
+ "github.com/alibabacloud-go/tea/tea"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ "github.com/usual2970/certimate/internal/pkg/core/uploader"
+ uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
+ sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
+)
+
+type DeployerConfig struct {
+ // 阿里云 AccessKeyId。
+ AccessKeyId string `json:"accessKeyId"`
+ // 阿里云 AccessKeySecret。
+ AccessKeySecret string `json:"accessKeySecret"`
+ // 部署资源类型。
+ ResourceType ResourceType `json:"resourceType"`
+ // 全球加速实例 ID。
+ AcceleratorId string `json:"acceleratorId"`
+ // 全球加速监听 ID。
+ // 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。
+ ListenerId string `json:"listenerId,omitempty"`
+ // SNI 域名(不支持泛域名)。
+ // 部署资源类型为 [RESOURCE_TYPE_ACCELERATOR]、[RESOURCE_TYPE_LISTENER] 时选填。
+ Domain string `json:"domain,omitempty"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient *aliga.Client
+ sslUploader uploader.Uploader
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ sslUploader: uploader,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ d.sslUploader.WithLogger(logger)
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ // 上传证书到 CAS
+ upres, err := d.sslUploader.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))
+ }
+
+ // 根据部署资源类型决定部署方式
+ switch d.config.ResourceType {
+ case RESOURCE_TYPE_ACCELERATOR:
+ if err := d.deployToAccelerator(ctx, upres.ExtendedData["certIdentifier"].(string)); err != nil {
+ return nil, err
+ }
+
+ case RESOURCE_TYPE_LISTENER:
+ if err := d.deployToListener(ctx, upres.ExtendedData["certIdentifier"].(string)); err != nil {
+ return nil, err
+ }
+
+ default:
+ return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func (d *DeployerProvider) deployToAccelerator(ctx context.Context, cloudCertId string) error {
+ if d.config.AcceleratorId == "" {
+ return errors.New("config `acceleratorId` is required")
+ }
+
+ // 查询 HTTPS 监听列表
+ // REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-listlisteners
+ listenerIds := make([]string, 0)
+ listListenersPageNumber := int32(1)
+ listListenersPageSize := int32(50)
+ for {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ }
+
+ listListenersReq := &aliga.ListListenersRequest{
+ RegionId: tea.String("cn-hangzhou"),
+ AcceleratorId: tea.String(d.config.AcceleratorId),
+ PageNumber: tea.Int32(listListenersPageNumber),
+ PageSize: tea.Int32(listListenersPageSize),
+ }
+ listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
+ d.logger.Debug("sdk request 'ga.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'ga.ListListeners': %w", err)
+ }
+
+ if listListenersResp.Body.Listeners != nil {
+ for _, listener := range listListenersResp.Body.Listeners {
+ if strings.EqualFold(tea.StringValue(listener.Protocol), "https") {
+ listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
+ }
+ }
+ }
+
+ if len(listListenersResp.Body.Listeners) < int(listListenersPageSize) {
+ break
+ } else {
+ listListenersPageNumber++
+ }
+ }
+
+ // 遍历更新监听证书
+ if len(listenerIds) == 0 {
+ d.logger.Info("no ga listeners to deploy")
+ } else {
+ var errs []error
+ d.logger.Info("found https listeners to deploy", slog.Any("listenerIds", listenerIds))
+
+ for _, listenerId := range listenerIds {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ if err := d.updateListenerCertificate(ctx, d.config.AcceleratorId, listenerId, cloudCertId); err != nil {
+ errs = append(errs, err)
+ }
+ }
+ }
+
+ if len(errs) > 0 {
+ return errors.Join(errs...)
+ }
+ }
+
+ return nil
+}
+
+func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error {
+ if d.config.AcceleratorId == "" {
+ return errors.New("config `acceleratorId` is required")
+ }
+ if d.config.ListenerId == "" {
+ return errors.New("config `listenerId` is required")
+ }
+
+ // 更新监听
+ if err := d.updateListenerCertificate(ctx, d.config.AcceleratorId, d.config.ListenerId, cloudCertId); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudAcceleratorId string, cloudListenerId string, cloudCertId string) error {
+ // 查询监听绑定的证书列表
+ // REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-listlistenercertificates
+ var listenerDefaultCertificate *aliga.ListListenerCertificatesResponseBodyCertificates
+ var listenerAdditionalCertificates []*aliga.ListListenerCertificatesResponseBodyCertificates = make([]*aliga.ListListenerCertificatesResponseBodyCertificates, 0)
+ var listListenerCertificatesNextToken *string
+ for {
+ listListenerCertificatesReq := &aliga.ListListenerCertificatesRequest{
+ RegionId: tea.String("cn-hangzhou"),
+ AcceleratorId: tea.String(d.config.AcceleratorId),
+ NextToken: listListenerCertificatesNextToken,
+ MaxResults: tea.Int32(20),
+ }
+ listListenerCertificatesResp, err := d.sdkClient.ListListenerCertificates(listListenerCertificatesReq)
+ d.logger.Debug("sdk request 'ga.ListListenerCertificates'", slog.Any("request", listListenerCertificatesReq), slog.Any("response", listListenerCertificatesResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'ga.ListListenerCertificates': %w", err)
+ }
+
+ if listListenerCertificatesResp.Body.Certificates != nil {
+ for _, certificate := range listListenerCertificatesResp.Body.Certificates {
+ if tea.BoolValue(certificate.IsDefault) {
+ listenerDefaultCertificate = certificate
+ } else {
+ listenerAdditionalCertificates = append(listenerAdditionalCertificates, certificate)
+ }
+ }
+ }
+
+ if listListenerCertificatesResp.Body.NextToken == nil {
+ break
+ } else {
+ listListenerCertificatesNextToken = listListenerCertificatesResp.Body.NextToken
+ }
+ }
+
+ if d.config.Domain == "" {
+ // 未指定 SNI,只需部署到监听器
+ if listenerDefaultCertificate != nil && tea.StringValue(listenerDefaultCertificate.CertificateId) == cloudCertId {
+ d.logger.Info("no need to update ga listener default certificate")
+ return nil
+ }
+
+ // 修改监听的属性
+ // REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-updatelistener
+ updateListenerReq := &aliga.UpdateListenerRequest{
+ RegionId: tea.String("cn-hangzhou"),
+ ListenerId: tea.String(cloudListenerId),
+ Certificates: []*aliga.UpdateListenerRequestCertificates{{
+ Id: tea.String(cloudCertId),
+ }},
+ }
+ updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq)
+ d.logger.Debug("sdk request 'ga.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'ga.UpdateListener': %w", err)
+ }
+ } else {
+ // 指定 SNI,需部署到扩展域名
+ if sliceutil.Some(listenerAdditionalCertificates, func(item *aliga.ListListenerCertificatesResponseBodyCertificates) bool {
+ return tea.StringValue(item.CertificateId) == cloudCertId
+ }) {
+ d.logger.Info("no need to update ga listener additional certificate")
+ return nil
+ }
+
+ if sliceutil.Some(listenerAdditionalCertificates, func(item *aliga.ListListenerCertificatesResponseBodyCertificates) bool {
+ return tea.StringValue(item.Domain) == d.config.Domain
+ }) {
+ // 为监听替换扩展证书
+ // REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-updateadditionalcertificatewithlistener
+ updateAdditionalCertificateWithListenerReq := &aliga.UpdateAdditionalCertificateWithListenerRequest{
+ RegionId: tea.String("cn-hangzhou"),
+ AcceleratorId: tea.String(cloudAcceleratorId),
+ ListenerId: tea.String(cloudListenerId),
+ CertificateId: tea.String(cloudCertId),
+ Domain: tea.String(d.config.Domain),
+ }
+ updateAdditionalCertificateWithListenerResp, err := d.sdkClient.UpdateAdditionalCertificateWithListener(updateAdditionalCertificateWithListenerReq)
+ d.logger.Debug("sdk request 'ga.UpdateAdditionalCertificateWithListener'", slog.Any("request", updateAdditionalCertificateWithListenerReq), slog.Any("response", updateAdditionalCertificateWithListenerResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'ga.UpdateAdditionalCertificateWithListener': %w", err)
+ }
+ } else {
+ // 为监听绑定扩展证书
+ // REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-associateadditionalcertificateswithlistener
+ associateAdditionalCertificatesWithListenerReq := &aliga.AssociateAdditionalCertificatesWithListenerRequest{
+ RegionId: tea.String("cn-hangzhou"),
+ AcceleratorId: tea.String(cloudAcceleratorId),
+ ListenerId: tea.String(cloudListenerId),
+ Certificates: []*aliga.AssociateAdditionalCertificatesWithListenerRequestCertificates{{
+ Id: tea.String(cloudCertId),
+ Domain: tea.String(d.config.Domain),
+ }},
+ }
+ associateAdditionalCertificatesWithListenerResp, err := d.sdkClient.AssociateAdditionalCertificatesWithListener(associateAdditionalCertificatesWithListenerReq)
+ d.logger.Debug("sdk request 'ga.AssociateAdditionalCertificatesWithListener'", slog.Any("request", associateAdditionalCertificatesWithListenerReq), slog.Any("response", associateAdditionalCertificatesWithListenerResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'ga.AssociateAdditionalCertificatesWithListener': %w", err)
+ }
+ }
+ }
+
+ return nil
+}
+
+func createSdkClient(accessKeyId, accessKeySecret string) (*aliga.Client, error) {
+ // 接入点一览 https://api.aliyun.com/product/Ga
+ config := &aliopen.Config{
+ AccessKeyId: tea.String(accessKeyId),
+ AccessKeySecret: tea.String(accessKeySecret),
+ Endpoint: tea.String("ga.cn-hangzhou.aliyuncs.com"),
+ }
+
+ client, err := aliga.NewClient(config)
+ if err != nil {
+ return nil, err
+ }
+
+ return client, nil
+}
+
+func createSslUploader(accessKeyId, accessKeySecret string) (uploader.Uploader, error) {
+ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
+ AccessKeyId: accessKeyId,
+ AccessKeySecret: accessKeySecret,
+ Region: "cn-hangzhou",
+ })
+ return uploader, err
+}
diff --git a/internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga_test.go b/internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga_test.go
new file mode 100644
index 00000000..611ddc41
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga_test.go
@@ -0,0 +1,118 @@
+package aliyunga_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-ga"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fAccessKeyId string
+ fAccessKeySecret string
+ fAcceleratorId string
+ fListenerId string
+ fDomain string
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_ALIYUNGA_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
+ flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
+ flag.StringVar(&fAcceleratorId, argsPrefix+"ACCELERATORID", "", "")
+ flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "")
+ flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./aliyun_ga_test.go -args \
+ --CERTIMATE_DEPLOYER_ALIYUNGA_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_ALIYUNGA_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_ALIYUNGA_ACCESSKEYID="your-access-key-id" \
+ --CERTIMATE_DEPLOYER_ALIYUNGA_ACCESSKEYSECRET="your-access-key-secret" \
+ --CERTIMATE_DEPLOYER_ALIYUNGA_ACCELERATORID="your-ga-accelerator-id" \
+ --CERTIMATE_DEPLOYER_ALIYUNGA_LISTENERID="your-ga-listener-id" \
+ --CERTIMATE_DEPLOYER_ALIYUNGA_DOMAIN="your-ga-sni-domain"
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy_ToAccelerator", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
+ fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
+ fmt.Sprintf("ACCELERATORID: %v", fAcceleratorId),
+ fmt.Sprintf("DOMAIN: %v", fDomain),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ AccessKeyId: fAccessKeyId,
+ AccessKeySecret: fAccessKeySecret,
+ ResourceType: provider.RESOURCE_TYPE_ACCELERATOR,
+ AcceleratorId: fAcceleratorId,
+ Domain: fDomain,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+
+ t.Run("Deploy_ToListener", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
+ fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
+ fmt.Sprintf("LISTENERID: %v", fListenerId),
+ fmt.Sprintf("DOMAIN: %v", fDomain),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ AccessKeyId: fAccessKeyId,
+ AccessKeySecret: fAccessKeySecret,
+ ResourceType: provider.RESOURCE_TYPE_LISTENER,
+ ListenerId: fListenerId,
+ Domain: fDomain,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/internal/pkg/core/deployer/providers/aliyun-ga/consts.go b/internal/pkg/core/deployer/providers/aliyun-ga/consts.go
new file mode 100644
index 00000000..f96d98d5
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/aliyun-ga/consts.go
@@ -0,0 +1,10 @@
+package aliyunga
+
+type ResourceType string
+
+const (
+ // 资源类型:部署到指定全球加速器。
+ RESOURCE_TYPE_ACCELERATOR = ResourceType("accelerator")
+ // 资源类型:部署到指定监听器。
+ RESOURCE_TYPE_LISTENER = ResourceType("listener")
+)
diff --git a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go
index b8391144..58015f3d 100644
--- a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go
+++ b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go
@@ -145,7 +145,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
if listListenersResp.Body.Listeners != nil {
for _, listener := range listListenersResp.Body.Listeners {
- listenerIds = append(listenerIds, *listener.ListenerId)
+ listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
}
@@ -167,7 +167,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
select {
case <-ctx.Done():
return ctx.Err()
-
default:
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
errs = append(errs, err)
diff --git a/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console.go b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console.go
new file mode 100644
index 00000000..811b350b
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console.go
@@ -0,0 +1,88 @@
+package baotapanelconsole
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "log/slog"
+ "net/url"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btwaf"
+)
+
+type DeployerConfig struct {
+ // 堡塔云 WAF 地址。
+ ApiUrl string `json:"apiUrl"`
+ // 堡塔云 WAF 接口密钥。
+ ApiKey string `json:"apiKey"`
+ // 是否允许不安全的连接。
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient *btsdk.Client
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ // 设置面板 SSL
+ configSetSSLReq := &btsdk.ConfigSetSSLRequest{
+ CertContent: certPEM,
+ KeyContent: privkeyPEM,
+ }
+ configSetSSLResp, err := d.sdkClient.ConfigSetSSL(configSetSSLReq)
+ d.logger.Debug("sdk request 'bt.ConfigSetSSL'", slog.Any("request", configSetSSLReq), slog.Any("response", configSetSSLResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'bt.ConfigSetSSL': %w", err)
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
+ if _, err := url.Parse(apiUrl); err != nil {
+ return nil, errors.New("invalid baota api url")
+ }
+
+ if apiKey == "" {
+ return nil, errors.New("invalid baota api key")
+ }
+
+ client := btsdk.NewClient(apiUrl, apiKey)
+ if skipTlsVerify {
+ client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
+ }
+
+ return client, nil
+}
diff --git a/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console_test.go b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console_test.go
new file mode 100644
index 00000000..ba6ddd26
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/baotawaf-console/baotawaf_console_test.go
@@ -0,0 +1,73 @@
+package baotapanelconsole_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-console"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fApiUrl string
+ fApiKey string
+ fSiteName string
+ fSitePort int64
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
+ flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./baotawaf_console_test.go -args \
+ --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_APIURL="http://127.0.0.1:8888" \
+ --CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_APIKEY="your-api-key"
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("APIURL: %v", fApiUrl),
+ fmt.Sprintf("APIKEY: %v", fApiKey),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ ApiUrl: fApiUrl,
+ ApiKey: fApiKey,
+ AllowInsecureConnections: true,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/internal/pkg/core/deployer/providers/baotawaf-site/baotawaf_site.go b/internal/pkg/core/deployer/providers/baotawaf-site/baotawaf_site.go
new file mode 100644
index 00000000..ed05937a
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/baotawaf-site/baotawaf_site.go
@@ -0,0 +1,151 @@
+package baotapanelwaf
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "log/slog"
+ "net/url"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btwaf"
+ typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
+)
+
+type DeployerConfig struct {
+ // 堡塔云 WAF 地址。
+ ApiUrl string `json:"apiUrl"`
+ // 堡塔云 WAF 接口密钥。
+ ApiKey string `json:"apiKey"`
+ // 是否允许不安全的连接。
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+ // 网站名称。
+ SiteName string `json:"siteName"`
+ // 网站 SSL 端口。
+ // 零值时默认为 443。
+ SitePort int32 `json:"sitePort,omitempty"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient *btsdk.Client
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ if d.config.SiteName == "" {
+ return nil, errors.New("config `siteName` is required")
+ }
+ if d.config.SitePort == 0 {
+ d.config.SitePort = 443
+ }
+
+ // 遍历获取网站列表,获取网站 ID
+ // REF: https://support.huaweicloud.com/api-waf/ListHost.html
+ siteId := ""
+ getSitListPage := int32(1)
+ getSitListPageSize := int32(100)
+ for {
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ default:
+ }
+
+ getSiteListReq := &btsdk.GetSiteListRequest{
+ SiteName: typeutil.ToPtr(d.config.SiteName),
+ Page: typeutil.ToPtr(getSitListPage),
+ PageSize: typeutil.ToPtr(getSitListPageSize),
+ }
+ getSiteListResp, err := d.sdkClient.GetSiteList(getSiteListReq)
+ d.logger.Debug("sdk request 'bt.GetSiteList'", slog.Any("request", getSiteListReq), slog.Any("response", getSiteListResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'bt.GetSiteList': %w", err)
+ }
+
+ if getSiteListResp.Result != nil && getSiteListResp.Result.List != nil {
+ for _, siteItem := range getSiteListResp.Result.List {
+ if siteItem.SiteName == d.config.SiteName {
+ siteId = siteItem.SiteId
+ break
+ }
+ }
+ }
+
+ if getSiteListResp.Result == nil || len(getSiteListResp.Result.List) < int(getSitListPageSize) {
+ break
+ } else {
+ getSitListPage++
+ }
+ }
+ if siteId == "" {
+ return nil, errors.New("site not found")
+ }
+
+ // 修改站点配置
+ modifySiteReq := &btsdk.ModifySiteRequest{
+ SiteId: siteId,
+ Type: typeutil.ToPtr("openCert"),
+ Server: &btsdk.SiteServerInfo{
+ ListenSSLPort: typeutil.ToPtr(d.config.SitePort),
+ SSL: &btsdk.SiteServerSSLInfo{
+ IsSSL: typeutil.ToPtr(int32(1)),
+ FullChain: typeutil.ToPtr(certPEM),
+ PrivateKey: typeutil.ToPtr(privkeyPEM),
+ },
+ },
+ }
+ modifySiteResp, err := d.sdkClient.ModifySite(modifySiteReq)
+ d.logger.Debug("sdk request 'bt.ModifySite'", slog.Any("request", modifySiteReq), slog.Any("response", modifySiteResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'bt.ModifySite': %w", err)
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
+ if _, err := url.Parse(apiUrl); err != nil {
+ return nil, errors.New("invalid baota api url")
+ }
+
+ if apiKey == "" {
+ return nil, errors.New("invalid baota api key")
+ }
+
+ client := btsdk.NewClient(apiUrl, apiKey)
+ if skipTlsVerify {
+ client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
+ }
+
+ return client, nil
+}
diff --git a/internal/pkg/core/deployer/providers/baotawaf-site/baotawaf_site_test.go b/internal/pkg/core/deployer/providers/baotawaf-site/baotawaf_site_test.go
new file mode 100644
index 00000000..4e1ffe34
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/baotawaf-site/baotawaf_site_test.go
@@ -0,0 +1,81 @@
+package baotapanelwaf_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-site"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fApiUrl string
+ fApiKey string
+ fSiteName string
+ fSitePort int64
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_BAOTAWAFSITE_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
+ flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
+ flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "")
+ flag.Int64Var(&fSitePort, argsPrefix+"SITEPORT", 0, "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./baotawaf_site_test.go -args \
+ --CERTIMATE_DEPLOYER_BAOTAWAFSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_BAOTAWAFSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_BAOTAWAFSITE_APIURL="http://127.0.0.1:8888" \
+ --CERTIMATE_DEPLOYER_BAOTAWAFSITE_APIKEY="your-api-key" \
+ --CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITENAME="your-site-name"\
+ --CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITEPORT=443
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("APIURL: %v", fApiUrl),
+ fmt.Sprintf("APIKEY: %v", fApiKey),
+ fmt.Sprintf("SITENAME: %v", fSiteName),
+ fmt.Sprintf("SITEPORT: %v", fSitePort),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ ApiUrl: fApiUrl,
+ ApiKey: fApiKey,
+ AllowInsecureConnections: true,
+ SiteName: fSiteName,
+ SitePort: int32(fSitePort),
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/internal/pkg/core/deployer/providers/flexcdn/consts.go b/internal/pkg/core/deployer/providers/flexcdn/consts.go
new file mode 100644
index 00000000..be55a475
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/flexcdn/consts.go
@@ -0,0 +1,8 @@
+package flexcdn
+
+type ResourceType string
+
+const (
+ // 资源类型:替换指定证书。
+ RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate")
+)
diff --git a/internal/pkg/core/deployer/providers/flexcdn/flexcdn.go b/internal/pkg/core/deployer/providers/flexcdn/flexcdn.go
new file mode 100644
index 00000000..a12ed164
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/flexcdn/flexcdn.go
@@ -0,0 +1,145 @@
+package flexcdn
+
+import (
+ "context"
+ "crypto/tls"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "log/slog"
+ "net/url"
+ "time"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ flexcdnsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/flexcdn"
+ certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
+)
+
+type DeployerConfig struct {
+ // FlexCDN URL。
+ ApiUrl string `json:"apiUrl"`
+ // FlexCDN 用户角色。
+ // 可取值 "user"、"admin"。
+ ApiRole string `json:"apiRole"`
+ // FlexCDN AccessKeyId。
+ AccessKeyId string `json:"accessKeyId"`
+ // FlexCDN AccessKey。
+ AccessKey string `json:"accessKey"`
+ // 是否允许不安全的连接。
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+ // 部署资源类型。
+ ResourceType ResourceType `json:"resourceType"`
+ // 证书 ID。
+ // 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
+ CertificateId int64 `json:"certificateId,omitempty"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient *flexcdnsdk.Client
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.ApiUrl, config.ApiRole, config.AccessKeyId, config.AccessKey, config.AllowInsecureConnections)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ // 根据部署资源类型决定部署方式
+ switch d.config.ResourceType {
+ case RESOURCE_TYPE_CERTIFICATE:
+ if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
+ return nil, err
+ }
+
+ default:
+ return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM string, privkeyPEM string) error {
+ if d.config.CertificateId == 0 {
+ return errors.New("config `certificateId` is required")
+ }
+
+ // 解析证书内容
+ certX509, err := certutil.ParseCertificateFromPEM(certPEM)
+ if err != nil {
+ return err
+ }
+
+ // 修改证书
+ // REF: https://flexcdn.cloud/dev/api/service/SSLCertService?role=user#updateSSLCert
+ updateSSLCertReq := &flexcdnsdk.UpdateSSLCertRequest{
+ SSLCertId: d.config.CertificateId,
+ IsOn: true,
+ Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
+ Description: "upload from certimate",
+ ServerName: certX509.Subject.CommonName,
+ IsCA: false,
+ CertData: base64.StdEncoding.EncodeToString([]byte(certPEM)),
+ KeyData: base64.StdEncoding.EncodeToString([]byte(privkeyPEM)),
+ TimeBeginAt: certX509.NotBefore.Unix(),
+ TimeEndAt: certX509.NotAfter.Unix(),
+ DNSNames: certX509.DNSNames,
+ CommonNames: []string{certX509.Subject.CommonName},
+ }
+ updateSSLCertResp, err := d.sdkClient.UpdateSSLCert(updateSSLCertReq)
+ d.logger.Debug("sdk request 'flexcdn.UpdateSSLCert'", slog.Any("request", updateSSLCertReq), slog.Any("response", updateSSLCertResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'flexcdn.UpdateSSLCert': %w", err)
+ }
+
+ return nil
+}
+
+func createSdkClient(apiUrl, apiRole, accessKeyId, accessKey string, skipTlsVerify bool) (*flexcdnsdk.Client, error) {
+ if _, err := url.Parse(apiUrl); err != nil {
+ return nil, errors.New("invalid flexcdn api url")
+ }
+
+ if apiRole != "user" && apiRole != "admin" {
+ return nil, errors.New("invalid flexcdn api role")
+ }
+
+ if accessKeyId == "" {
+ return nil, errors.New("invalid flexcdn access key id")
+ }
+
+ if accessKey == "" {
+ return nil, errors.New("invalid flexcdn access key")
+ }
+
+ client := flexcdnsdk.NewClient(apiUrl, apiRole, accessKeyId, accessKey)
+ if skipTlsVerify {
+ client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
+ }
+
+ return client, nil
+}
diff --git a/internal/pkg/core/deployer/providers/flexcdn/flexcdn_test.go b/internal/pkg/core/deployer/providers/flexcdn/flexcdn_test.go
new file mode 100644
index 00000000..b9b8de07
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/flexcdn/flexcdn_test.go
@@ -0,0 +1,83 @@
+package flexcdn_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/flexcdn"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fApiUrl string
+ fAccessKeyId string
+ fAccessKey string
+ fCertificateId int64
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_FLEXCDN_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
+ flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
+ flag.StringVar(&fAccessKey, argsPrefix+"ACCESSKEY", "", "")
+ flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./flexcdn_test.go -args \
+ --CERTIMATE_DEPLOYER_FLEXCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_FLEXCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_FLEXCDN_APIURL="http://127.0.0.1:7788" \
+ --CERTIMATE_DEPLOYER_FLEXCDN_ACCESSKEYID="your-access-key-id" \
+ --CERTIMATE_DEPLOYER_FLEXCDN_ACCESSKEY="your-access-key" \
+ --CERTIMATE_DEPLOYER_FLEXCDN_CERTIFICATEID="your-cerficiate-id"
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy_ToCertificate", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("APIURL: %v", fApiUrl),
+ fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
+ fmt.Sprintf("ACCESSKEY: %v", fAccessKey),
+ fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ ApiUrl: fApiUrl,
+ ApiRole: "user",
+ AccessKeyId: fAccessKeyId,
+ AccessKey: fAccessKey,
+ AllowInsecureConnections: true,
+ ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
+ CertificateId: fCertificateId,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/internal/pkg/core/deployer/providers/goedge/goedge.go b/internal/pkg/core/deployer/providers/goedge/goedge.go
index 73eade64..ecae774e 100644
--- a/internal/pkg/core/deployer/providers/goedge/goedge.go
+++ b/internal/pkg/core/deployer/providers/goedge/goedge.go
@@ -19,6 +19,7 @@ type DeployerConfig struct {
// GoEdge URL。
ApiUrl string `json:"apiUrl"`
// GoEdge 用户角色。
+ // 可取值 "user"、"admin"。
ApiRole string `json:"apiRole"`
// GoEdge AccessKeyId。
AccessKeyId string `json:"accessKeyId"`
diff --git a/internal/pkg/core/deployer/providers/goedge/goedge_test.go b/internal/pkg/core/deployer/providers/goedge/goedge_test.go
index c8c32b37..d10f931c 100644
--- a/internal/pkg/core/deployer/providers/goedge/goedge_test.go
+++ b/internal/pkg/core/deployer/providers/goedge/goedge_test.go
@@ -17,7 +17,7 @@ var (
fApiUrl string
fAccessKeyId string
fAccessKey string
- fCertificateId int
+ fCertificateId int64
)
func init() {
@@ -28,7 +28,7 @@ func init() {
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
flag.StringVar(&fAccessKey, argsPrefix+"ACCESSKEY", "", "")
- flag.IntVar(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
+ flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
}
/*
@@ -45,7 +45,7 @@ Shell command to run this test:
func TestDeploy(t *testing.T) {
flag.Parse()
- t.Run("Deploy", func(t *testing.T) {
+ t.Run("Deploy_ToCertificate", func(t *testing.T) {
t.Log(strings.Join([]string{
"args:",
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
@@ -58,11 +58,12 @@ func TestDeploy(t *testing.T) {
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl,
+ ApiRole: "user",
AccessKeyId: fAccessKeyId,
AccessKey: fAccessKey,
AllowInsecureConnections: true,
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
- CertificateId: int64(fCertificateId),
+ CertificateId: fCertificateId,
})
if err != nil {
t.Errorf("err: %+v", err)
diff --git a/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go b/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go
index 748111dd..23ec4a92 100644
--- a/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go
+++ b/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go
@@ -210,7 +210,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, certPEM str
select {
case <-ctx.Done():
return ctx.Err()
-
default:
if err := d.modifyListenerCertificate(ctx, listenerId, upres.CertId); err != nil {
errs = append(errs, err)
diff --git a/internal/pkg/core/deployer/providers/lecdn/consts.go b/internal/pkg/core/deployer/providers/lecdn/consts.go
new file mode 100644
index 00000000..f5b7c0c9
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/lecdn/consts.go
@@ -0,0 +1,8 @@
+package lecdn
+
+type ResourceType string
+
+const (
+ // 资源类型:替换指定证书。
+ RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate")
+)
diff --git a/internal/pkg/core/deployer/providers/lecdn/lecdn.go b/internal/pkg/core/deployer/providers/lecdn/lecdn.go
new file mode 100644
index 00000000..1ad88dcf
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/lecdn/lecdn.go
@@ -0,0 +1,176 @@
+package lecdn
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "log/slog"
+ "net/url"
+ "time"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ leclientsdkv3 "github.com/usual2970/certimate/internal/pkg/sdk3rd/lecdn/v3/client"
+ lemastersdkv3 "github.com/usual2970/certimate/internal/pkg/sdk3rd/lecdn/v3/master"
+)
+
+type DeployerConfig struct {
+ // LeCDN URL。
+ ApiUrl string `json:"apiUrl"`
+ // LeCDN 版本。
+ // 可取值 "v3"。
+ ApiVersion string `json:"apiVersion"`
+ // LeCDN 用户角色。
+ // 可取值 "client"、"master"。
+ ApiRole string `json:"apiRole"`
+ // LeCDN 用户名。
+ Username string `json:"accessKeyId"`
+ // LeCDN 用户密码。
+ Password string `json:"accessKey"`
+ // 是否允许不安全的连接。
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+ // 部署资源类型。
+ ResourceType ResourceType `json:"resourceType"`
+ // 证书 ID。
+ // 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
+ CertificateId int64 `json:"certificateId,omitempty"`
+ // 客户 ID。
+ // 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时选填。
+ ClientId int64 `json:"clientId,omitempty"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient interface{}
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+const (
+ apiVersionV3 = "v3"
+
+ apiRoleClient = "client"
+ apiRoleMaster = "master"
+)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiRole, config.Username, config.Password, config.AllowInsecureConnections)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ // 根据部署资源类型决定部署方式
+ switch d.config.ResourceType {
+ case RESOURCE_TYPE_CERTIFICATE:
+ if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
+ return nil, err
+ }
+
+ default:
+ return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM string, privkeyPEM string) error {
+ if d.config.CertificateId == 0 {
+ return errors.New("config `certificateId` is required")
+ }
+
+ // 修改证书
+ // REF: https://wdk0pwf8ul.feishu.cn/wiki/YE1XwCRIHiLYeKkPupgcXrlgnDd
+ switch sdkClient := d.sdkClient.(type) {
+ case *leclientsdkv3.Client:
+ updateSSLCertReq := &leclientsdkv3.UpdateCertificateRequest{
+ Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
+ Description: "upload from certimate",
+ Type: "upload",
+ SSLPEM: certPEM,
+ SSLKey: privkeyPEM,
+ AutoRenewal: false,
+ }
+ updateSSLCertResp, err := sdkClient.UpdateCertificate(d.config.CertificateId, updateSSLCertReq)
+ d.logger.Debug("sdk request 'lecdn.UpdateCertificate'", slog.Int64("certId", d.config.CertificateId), slog.Any("request", updateSSLCertReq), slog.Any("response", updateSSLCertResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'lecdn.UpdateCertificate': %w", err)
+ }
+
+ case *lemastersdkv3.Client:
+ updateSSLCertReq := &lemastersdkv3.UpdateCertificateRequest{
+ ClientId: d.config.ClientId,
+ Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
+ Description: "upload from certimate",
+ Type: "upload",
+ SSLPEM: certPEM,
+ SSLKey: privkeyPEM,
+ AutoRenewal: false,
+ }
+ updateSSLCertResp, err := sdkClient.UpdateCertificate(d.config.CertificateId, updateSSLCertReq)
+ d.logger.Debug("sdk request 'lecdn.UpdateCertificate'", slog.Int64("certId", d.config.CertificateId), slog.Any("request", updateSSLCertReq), slog.Any("response", updateSSLCertResp))
+ if err != nil {
+ return fmt.Errorf("failed to execute sdk request 'lecdn.UpdateCertificate': %w", err)
+ }
+
+ default:
+ panic("sdk client is not implemented")
+ }
+
+ return nil
+}
+
+func createSdkClient(apiUrl, apiVersion, apiRole, username, password string, skipTlsVerify bool) (interface{}, error) {
+ if _, err := url.Parse(apiUrl); err != nil {
+ return nil, errors.New("invalid lecdn api url")
+ }
+
+ if username == "" {
+ return nil, errors.New("invalid lecdn username")
+ }
+
+ if password == "" {
+ return nil, errors.New("invalid lecdn password")
+ }
+
+ if apiVersion == apiVersionV3 && apiRole == apiRoleClient {
+ // v3 版客户端
+ client := leclientsdkv3.NewClient(apiUrl, username, password)
+ if skipTlsVerify {
+ client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
+ }
+
+ return client, nil
+ } else if apiVersion == apiVersionV3 && apiRole == apiRoleMaster {
+ // v3 版主控端
+ client := lemastersdkv3.NewClient(apiUrl, username, password)
+ if skipTlsVerify {
+ client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
+ }
+
+ return client, nil
+ }
+
+ return nil, fmt.Errorf("invalid lecdn api version or user role")
+}
diff --git a/internal/pkg/core/deployer/providers/lecdn/lecdn_test.go b/internal/pkg/core/deployer/providers/lecdn/lecdn_test.go
new file mode 100644
index 00000000..cbaa4523
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/lecdn/lecdn_test.go
@@ -0,0 +1,87 @@
+package lecdn_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/lecdn"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fApiUrl string
+ fApiVersion string
+ fUsername string
+ fPassword string
+ fCertificateId int64
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_LECDN_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
+ flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v3", "")
+ flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "")
+ flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "")
+ flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./lecdn_test.go -args \
+ --CERTIMATE_DEPLOYER_LECDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_LECDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_LECDN_APIURL="http://127.0.0.1:5090" \
+ --CERTIMATE_DEPLOYER_LECDN_USERNAME="your-username" \
+ --CERTIMATE_DEPLOYER_LECDN_PASSWORD="your-password" \
+ --CERTIMATE_DEPLOYER_LECDN_CERTIFICATEID="your-cerficiate-id"
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy_ToCertificate", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("APIURL: %v", fApiUrl),
+ fmt.Sprintf("APIVERSION: %v", fApiVersion),
+ fmt.Sprintf("USERNAME: %v", fUsername),
+ fmt.Sprintf("PASSWORD: %v", fPassword),
+ fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ ApiUrl: fApiUrl,
+ ApiVersion: fApiVersion,
+ ApiRole: "user",
+ Username: fUsername,
+ Password: fPassword,
+ AllowInsecureConnections: true,
+ ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
+ CertificateId: fCertificateId,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go
index ceb31771..51faf4f2 100644
--- a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go
+++ b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console.go
@@ -15,8 +15,8 @@ import (
type DeployerConfig struct {
// 耗子面板地址。
ApiUrl string `json:"apiUrl"`
- // 耗子面板访问令牌ID。
- AccessTokenId uint `json:"accessTokenId"`
+ // 耗子面板访问令牌 ID。
+ AccessTokenId int32 `json:"accessTokenId"`
// 耗子面板访问令牌。
AccessToken string `json:"accessToken"`
// 是否允许不安全的连接。
@@ -64,15 +64,15 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
PrivateKey: privkeyPEM,
}
settingCertResp, err := d.sdkClient.SettingCert(settingCertReq)
- d.logger.Debug("sdk request 'ratpanel.SettingCertRequest'", slog.Any("request", settingCertReq), slog.Any("response", settingCertResp))
+ d.logger.Debug("sdk request 'ratpanel.SettingCert'", slog.Any("request", settingCertReq), slog.Any("response", settingCertResp))
if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.SettingCertRequest': %w", err)
+ return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.SettingCert': %w", err)
}
return &deployer.DeployResult{}, nil
}
-func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
+func createSdkClient(apiUrl string, accessTokenId int32, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid ratpanel api url")
}
@@ -80,6 +80,7 @@ func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skip
if accessTokenId == 0 {
return nil, errors.New("invalid ratpanel access token id")
}
+
if accessToken == "" {
return nil, errors.New("invalid ratpanel access token")
}
diff --git a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go
index 40804f87..3f3193b3 100644
--- a/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go
+++ b/internal/pkg/core/deployer/providers/ratpanel-console/ratpanel_console_test.go
@@ -15,8 +15,8 @@ var (
fInputCertPath string
fInputKeyPath string
fApiUrl string
- fTokenId uint
- fToken string
+ fAccessTokenId int64
+ fAccessToken string
)
func init() {
@@ -25,8 +25,8 @@ func init() {
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
- flag.UintVar(&fTokenId, argsPrefix+"TOKENID", 0, "")
- flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "")
+ flag.Int64Var(&fAccessTokenId, argsPrefix+"ACCESSTOKENID", 0, "")
+ flag.StringVar(&fAccessToken, argsPrefix+"ACCESSTOKEN", "", "")
}
/*
@@ -36,8 +36,8 @@ Shell command to run this test:
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_APIURL="http://127.0.0.1:8888" \
- --CERTIMATE_DEPLOYER_RATPANELCONSOLE_TOKENID=your-access-token-id \
- --CERTIMATE_DEPLOYER_RATPANELCONSOLE_TOKEN="your-access-token"
+ --CERTIMATE_DEPLOYER_RATPANELCONSOLE_ACCESSTOKENID="your-access-token-id" \
+ --CERTIMATE_DEPLOYER_RATPANELCONSOLE_ACCESSTOKEN="your-access-token"
*/
func TestDeploy(t *testing.T) {
flag.Parse()
@@ -48,14 +48,14 @@ func TestDeploy(t *testing.T) {
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
fmt.Sprintf("APIURL: %v", fApiUrl),
- fmt.Sprintf("TOKENID: %v", fTokenId),
- fmt.Sprintf("TOKEN: %v", fToken),
+ fmt.Sprintf("ACCESSTOKENID: %v", fAccessTokenId),
+ fmt.Sprintf("ACCESSTOKEN: %v", fAccessToken),
}, "\n"))
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl,
- AccessTokenId: fTokenId,
- AccessToken: fToken,
+ AccessTokenId: int32(fAccessTokenId),
+ AccessToken: fAccessToken,
AllowInsecureConnections: true,
})
if err != nil {
diff --git a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go
index 85f54ab5..b4e283be 100644
--- a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go
+++ b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site.go
@@ -15,14 +15,14 @@ import (
type DeployerConfig struct {
// 耗子面板地址。
ApiUrl string `json:"apiUrl"`
- // 耗子面板访问令牌ID。
- AccessTokenId uint `json:"accessTokenId"`
+ // 耗子面板访问令牌 ID。
+ AccessTokenId int32 `json:"accessTokenId"`
// 耗子面板访问令牌。
AccessToken string `json:"accessToken"`
// 是否允许不安全的连接。
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
// 网站名称。
- SiteName string `json:"siteName,omitempty"`
+ SiteName string `json:"siteName"`
}
type DeployerProvider struct {
@@ -71,15 +71,15 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
PrivateKey: privkeyPEM,
}
websiteCertResp, err := d.sdkClient.WebsiteCert(websiteCertReq)
- d.logger.Debug("sdk request 'ratpanel.WebsiteCertRequest'", slog.Any("request", websiteCertReq), slog.Any("response", websiteCertResp))
+ d.logger.Debug("sdk request 'ratpanel.WebsiteCert'", slog.Any("request", websiteCertReq), slog.Any("response", websiteCertResp))
if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.WebsiteCertRequest': %w", err)
+ return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.WebsiteCert': %w", err)
}
return &deployer.DeployResult{}, nil
}
-func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
+func createSdkClient(apiUrl string, accessTokenId int32, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid ratpanel api url")
}
@@ -87,6 +87,7 @@ func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skip
if accessTokenId == 0 {
return nil, errors.New("invalid ratpanel access token id")
}
+
if accessToken == "" {
return nil, errors.New("invalid ratpanel access token")
}
diff --git a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go
index a4cab040..658175fb 100644
--- a/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go
+++ b/internal/pkg/core/deployer/providers/ratpanel-site/ratpanel_site_test.go
@@ -15,8 +15,8 @@ var (
fInputCertPath string
fInputKeyPath string
fApiUrl string
- fTokenId uint
- fToken string
+ fAccessTokenId int64
+ fAccessToken string
fSiteName string
)
@@ -26,8 +26,8 @@ func init() {
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
- flag.UintVar(&fTokenId, argsPrefix+"TOKENID", 0, "")
- flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "")
+ flag.Int64Var(&fAccessTokenId, argsPrefix+"ACCESSTOKENID", 0, "")
+ flag.StringVar(&fAccessToken, argsPrefix+"ACCESSTOKEN", "", "")
flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "")
}
@@ -38,8 +38,8 @@ Shell command to run this test:
--CERTIMATE_DEPLOYER_RATPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_DEPLOYER_RATPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_DEPLOYER_RATPANELSITE_APIURL="http://127.0.0.1:8888" \
- --CERTIMATE_DEPLOYER_RATPANELSITE_TOKENID=your-access-token-id \
- --CERTIMATE_DEPLOYER_RATPANELSITE_TOKEN="your-access-token" \
+ --CERTIMATE_DEPLOYER_RATPANELSITE_ACCESSTOKENID="your-access-token-id" \
+ --CERTIMATE_DEPLOYER_RATPANELSITE_ACCESSTOKEN="your-access-token" \
--CERTIMATE_DEPLOYER_RATPANELSITE_SITENAME="your-site-name"
*/
func TestDeploy(t *testing.T) {
@@ -51,15 +51,15 @@ func TestDeploy(t *testing.T) {
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
fmt.Sprintf("APIURL: %v", fApiUrl),
- fmt.Sprintf("TOKENID: %v", fTokenId),
- fmt.Sprintf("TOKEN: %v", fToken),
+ fmt.Sprintf("ACCESSTOKENID: %v", fAccessTokenId),
+ fmt.Sprintf("ACCESSTOKEN: %v", fAccessToken),
fmt.Sprintf("SITENAME: %v", fSiteName),
}, "\n"))
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
ApiUrl: fApiUrl,
- AccessTokenId: fTokenId,
- AccessToken: fToken,
+ AccessTokenId: int32(fAccessTokenId),
+ AccessToken: fAccessToken,
AllowInsecureConnections: true,
SiteName: fSiteName,
})
diff --git a/internal/pkg/core/deployer/providers/safeline/safeline_test.go b/internal/pkg/core/deployer/providers/safeline/safeline_test.go
index 294086c8..67fe6755 100644
--- a/internal/pkg/core/deployer/providers/safeline/safeline_test.go
+++ b/internal/pkg/core/deployer/providers/safeline/safeline_test.go
@@ -16,7 +16,7 @@ var (
fInputKeyPath string
fApiUrl string
fApiToken string
- fCertificateId int
+ fCertificateId int64
)
func init() {
@@ -26,7 +26,7 @@ func init() {
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "")
- flag.IntVar(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
+ flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
}
/*
diff --git a/internal/pkg/core/deployer/providers/ssh/ssh_test.go b/internal/pkg/core/deployer/providers/ssh/ssh_test.go
index b63471d1..ae908185 100644
--- a/internal/pkg/core/deployer/providers/ssh/ssh_test.go
+++ b/internal/pkg/core/deployer/providers/ssh/ssh_test.go
@@ -15,7 +15,7 @@ var (
fInputCertPath string
fInputKeyPath string
fSshHost string
- fSshPort int
+ fSshPort int64
fSshUsername string
fSshPassword string
fOutputCertPath string
@@ -28,7 +28,7 @@ func init() {
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fSshHost, argsPrefix+"SSHHOST", "", "")
- flag.IntVar(&fSshPort, argsPrefix+"SSHPORT", 0, "")
+ flag.Int64Var(&fSshPort, argsPrefix+"SSHPORT", 0, "")
flag.StringVar(&fSshUsername, argsPrefix+"SSHUSERNAME", "", "")
flag.StringVar(&fSshPassword, argsPrefix+"SSHPASSWORD", "", "")
flag.StringVar(&fOutputCertPath, argsPrefix+"OUTPUTCERTPATH", "", "")
diff --git a/internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn.go b/internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn.go
new file mode 100644
index 00000000..43c65de2
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn.go
@@ -0,0 +1,104 @@
+package wangsucdn
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log/slog"
+ "strconv"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ "github.com/usual2970/certimate/internal/pkg/core/uploader"
+ uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/wangsu-certificate"
+ wangsusdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/cdn"
+)
+
+type DeployerConfig struct {
+ // 网宿云 AccessKeyId。
+ AccessKeyId string `json:"accessKeyId"`
+ // 网宿云 AccessKeySecret。
+ AccessKeySecret string `json:"accessKeySecret"`
+ // 加速域名数组。
+ Domains []string `json:"domains"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient *wangsusdk.Client
+ sslUploader uploader.Uploader
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
+ AccessKeyId: config.AccessKeyId,
+ AccessKeySecret: config.AccessKeySecret,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ sslUploader: uploader,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ // 上传证书到证书管理
+ upres, err := d.sslUploader.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))
+ }
+
+ // 批量修改域名证书配置
+ // REF: https://www.wangsu.com/document/api-doc/37447
+ certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
+ batchUpdateCertificateConfigReq := &wangsusdk.BatchUpdateCertificateConfigRequest{
+ CertificateId: certId,
+ DomainNames: d.config.Domains,
+ }
+ batchUpdateCertificateConfigResp, err := d.sdkClient.BatchUpdateCertificateConfig(batchUpdateCertificateConfigReq)
+ d.logger.Debug("sdk request 'cdn.BatchUpdateCertificateConfig'", slog.Any("request", batchUpdateCertificateConfigReq), slog.Any("response", batchUpdateCertificateConfigResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'cdn.BatchUpdateCertificateConfig': %w", err)
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func createSdkClient(accessKeyId, accessKeySecret string) (*wangsusdk.Client, error) {
+ if accessKeyId == "" {
+ return nil, errors.New("invalid wangsu access key id")
+ }
+
+ if accessKeySecret == "" {
+ return nil, errors.New("invalid wangsu access key secret")
+ }
+
+ return wangsusdk.NewClient(accessKeyId, accessKeySecret), nil
+}
diff --git a/internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn_test.go b/internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn_test.go
new file mode 100644
index 00000000..99859b85
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn_test.go
@@ -0,0 +1,75 @@
+package wangsucdn_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/wangsu-cdn"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fAccessKeyId string
+ fAccessKeySecret string
+ fDomain string
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_WANGSUCDN_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
+ flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
+ flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./wangsu_cdn_test.go -args \
+ --CERTIMATE_DEPLOYER_WANGSUCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_WANGSUCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_WANGSUCDN_ACCESSKEYID="your-access-key-id" \
+ --CERTIMATE_DEPLOYER_WANGSUCDN_ACCESSKEYSECRET="your-access-key-secret" \
+ --CERTIMATE_DEPLOYER_WANGSUCDN_DOMAIN="example.com"
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
+ fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
+ fmt.Sprintf("DOMAIN: %v", fDomain),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ AccessKeyId: fAccessKeyId,
+ AccessKeySecret: fAccessKeySecret,
+ Domains: []string{fDomain},
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/internal/pkg/core/deployer/providers/wangsu-cdnpro/wangsu_cdnpro.go b/internal/pkg/core/deployer/providers/wangsu-cdnpro/wangsu_cdnpro.go
index ee16b08a..4d5f2e10 100644
--- a/internal/pkg/core/deployer/providers/wangsu-cdnpro/wangsu_cdnpro.go
+++ b/internal/pkg/core/deployer/providers/wangsu-cdnpro/wangsu_cdnpro.go
@@ -17,7 +17,7 @@ import (
"time"
"github.com/usual2970/certimate/internal/pkg/core/deployer"
- wangsucdn "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/cdn"
+ wangsucdn "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/cdnpro"
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
)
@@ -88,9 +88,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
// 查询已部署加速域名的详情
getHostnameDetailResp, err := d.sdkClient.GetHostnameDetail(d.config.Domain)
- d.logger.Debug("sdk request 'cdn.GetHostnameDetail'", slog.String("hostname", d.config.Domain), slog.Any("response", getHostnameDetailResp))
+ d.logger.Debug("sdk request 'cdnpro.GetHostnameDetail'", slog.String("hostname", d.config.Domain), slog.Any("response", getHostnameDetailResp))
if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetHostnameDetail': %w", err)
+ return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.GetHostnameDetail': %w", err)
}
// 生成网宿云证书参数
@@ -126,9 +126,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
NewVersion: certificateNewVersionInfo,
}
createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
- d.logger.Debug("sdk request 'cdn.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
+ d.logger.Debug("sdk request 'cdnpro.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'cdn.CreateCertificate': %w", err)
+ return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.CreateCertificate': %w", err)
}
wangsuCertUrl = createCertificateResp.CertificateUrl
@@ -149,9 +149,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
NewVersion: certificateNewVersionInfo,
}
updateCertificateResp, err := d.sdkClient.UpdateCertificate(d.config.CertificateId, updateCertificateReq)
- d.logger.Debug("sdk request 'cdn.CreateCertificate'", slog.Any("certificateId", d.config.CertificateId), slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
+ d.logger.Debug("sdk request 'cdnpro.CreateCertificate'", slog.Any("certificateId", d.config.CertificateId), slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'cdn.UpdateCertificate': %w", err)
+ return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.UpdateCertificate': %w", err)
}
wangsuCertUrl = updateCertificateResp.CertificateUrl
@@ -186,9 +186,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
createDeploymentTaskReq.Webhook = typeutil.ToPtr(d.config.WebhookId)
}
createDeploymentTaskResp, err := d.sdkClient.CreateDeploymentTask(createDeploymentTaskReq)
- d.logger.Debug("sdk request 'cdn.CreateCertificate'", slog.Any("request", createDeploymentTaskReq), slog.Any("response", createDeploymentTaskResp))
+ d.logger.Debug("sdk request 'cdnpro.CreateCertificate'", slog.Any("request", createDeploymentTaskReq), slog.Any("response", createDeploymentTaskResp))
if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'cdn.CreateDeploymentTask': %w", err)
+ return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.CreateDeploymentTask': %w", err)
}
// 循环获取部署任务详细信息,等待任务状态变更
@@ -206,9 +206,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
}
getDeploymentTaskDetailResp, err := d.sdkClient.GetDeploymentTaskDetail(wangsuTaskId)
- d.logger.Info("sdk request 'cdn.GetDeploymentTaskDetail'", slog.Any("taskId", wangsuTaskId), slog.Any("response", getDeploymentTaskDetailResp))
+ d.logger.Info("sdk request 'cdnpro.GetDeploymentTaskDetail'", slog.Any("taskId", wangsuTaskId), slog.Any("response", getDeploymentTaskDetailResp))
if err != nil {
- return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetDeploymentTaskDetail': %w", err)
+ return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.GetDeploymentTaskDetail': %w", err)
}
if getDeploymentTaskDetailResp.Status == "failed" {
diff --git a/internal/pkg/core/deployer/providers/wangsu-certificate/wangsu_certificate.go b/internal/pkg/core/deployer/providers/wangsu-certificate/wangsu_certificate.go
new file mode 100644
index 00000000..3f691489
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/wangsu-certificate/wangsu_certificate.go
@@ -0,0 +1,109 @@
+package wangsucertificate
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log/slog"
+ "time"
+
+ "github.com/usual2970/certimate/internal/pkg/core/deployer"
+ "github.com/usual2970/certimate/internal/pkg/core/uploader"
+ uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/wangsu-certificate"
+ wangsusdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/certificate"
+ typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
+)
+
+type DeployerConfig struct {
+ // 网宿云 AccessKeyId。
+ AccessKeyId string `json:"accessKeyId"`
+ // 网宿云 AccessKeySecret。
+ AccessKeySecret string `json:"accessKeySecret"`
+ // 证书 ID。
+ // 选填。零值时表示新建证书;否则表示更新证书。
+ CertificateId string `json:"certificateId,omitempty"`
+}
+
+type DeployerProvider struct {
+ config *DeployerConfig
+ logger *slog.Logger
+ sdkClient *wangsusdk.Client
+ sslUploader uploader.Uploader
+}
+
+var _ deployer.Deployer = (*DeployerProvider)(nil)
+
+func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
+ AccessKeyId: config.AccessKeyId,
+ AccessKeySecret: config.AccessKeySecret,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
+ }
+
+ return &DeployerProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ sslUploader: uploader,
+ }, nil
+}
+
+func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
+ if logger == nil {
+ d.logger = slog.Default()
+ } else {
+ d.logger = logger
+ }
+ return d
+}
+
+func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
+ if d.config.CertificateId == "" {
+ // 上传证书到证书管理
+ upres, err := d.sslUploader.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))
+ }
+ } else {
+ // 修改证书
+ // REF: https://www.wangsu.com/document/api-doc/25568?productCode=certificatemanagement
+ updateCertificateReq := &wangsusdk.UpdateCertificateRequest{
+ Name: typeutil.ToPtr(fmt.Sprintf("certimate_%d", time.Now().UnixMilli())),
+ Certificate: typeutil.ToPtr(certPEM),
+ PrivateKey: typeutil.ToPtr(privkeyPEM),
+ Comment: typeutil.ToPtr("upload from certimate"),
+ }
+ updateCertificateResp, err := d.sdkClient.UpdateCertificate(d.config.CertificateId, updateCertificateReq)
+ d.logger.Debug("sdk request 'certificatemanagement.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'certificatemanagement.CreateCertificate': %w", err)
+ }
+ }
+
+ return &deployer.DeployResult{}, nil
+}
+
+func createSdkClient(accessKeyId, accessKeySecret string) (*wangsusdk.Client, error) {
+ if accessKeyId == "" {
+ return nil, errors.New("invalid wangsu access key id")
+ }
+
+ if accessKeySecret == "" {
+ return nil, errors.New("invalid wangsu access key secret")
+ }
+
+ return wangsusdk.NewClient(accessKeyId, accessKeySecret), nil
+}
diff --git a/internal/pkg/core/deployer/providers/wangsu-certificate/wangsu_certificate_test.go b/internal/pkg/core/deployer/providers/wangsu-certificate/wangsu_certificate_test.go
new file mode 100644
index 00000000..a6805ec9
--- /dev/null
+++ b/internal/pkg/core/deployer/providers/wangsu-certificate/wangsu_certificate_test.go
@@ -0,0 +1,75 @@
+package wangsucertificate_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/wangsu-certificate"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fAccessKeyId string
+ fAccessKeySecret string
+ fCertificateId string
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
+ flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
+ flag.StringVar(&fCertificateId, argsPrefix+"CERTIFICATEID", "", "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./wangsu_certificate_test.go -args \
+ --CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_ACCESSKEYID="your-access-key-id" \
+ --CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_ACCESSKEYSECRET="your-access-key-secret" \
+ --CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_CERTIFICATEID="your-certificate-id"
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
+ fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
+ fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
+ }, "\n"))
+
+ deployer, err := provider.NewDeployer(&provider.DeployerConfig{
+ AccessKeyId: fAccessKeyId,
+ AccessKeySecret: fAccessKeySecret,
+ CertificateId: fCertificateId,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/internal/pkg/core/deployer/providers/webhook/webhook.go b/internal/pkg/core/deployer/providers/webhook/webhook.go
index 3a21717b..49b07b47 100644
--- a/internal/pkg/core/deployer/providers/webhook/webhook.go
+++ b/internal/pkg/core/deployer/providers/webhook/webhook.go
@@ -176,7 +176,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
}
// 发送请求
- resp, err := req.SetDebug(true).Send()
+ resp, err := req.Send()
if err != nil {
return nil, fmt.Errorf("failed to send webhook request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/bark/bark.go b/internal/pkg/core/notifier/providers/bark/bark.go
index 4d1902f2..97ece0be 100644
--- a/internal/pkg/core/notifier/providers/bark/bark.go
+++ b/internal/pkg/core/notifier/providers/bark/bark.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log/slog"
- "net/http"
"github.com/go-resty/resty/v2"
@@ -65,7 +64,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"body": message,
"device_key": n.config.DeviceKey,
})
- resp, err := req.Execute(http.MethodPost, serverUrl)
+ resp, err := req.Post(serverUrl)
if err != nil {
return nil, fmt.Errorf("bark api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/email/email_test.go b/internal/pkg/core/notifier/providers/email/email_test.go
index 30bfba07..cf0669ca 100644
--- a/internal/pkg/core/notifier/providers/email/email_test.go
+++ b/internal/pkg/core/notifier/providers/email/email_test.go
@@ -17,7 +17,7 @@ const (
var (
fSmtpHost string
- fSmtpPort int
+ fSmtpPort int64
fSmtpTLS bool
fUsername string
fPassword string
@@ -29,7 +29,7 @@ func init() {
argsPrefix := "CERTIMATE_NOTIFIER_EMAIL_"
flag.StringVar(&fSmtpHost, argsPrefix+"SMTPHOST", "", "")
- flag.IntVar(&fSmtpPort, argsPrefix+"SMTPPORT", 0, "")
+ flag.Int64Var(&fSmtpPort, argsPrefix+"SMTPPORT", 0, "")
flag.BoolVar(&fSmtpTLS, argsPrefix+"SMTPTLS", false, "")
flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "")
flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "")
diff --git a/internal/pkg/core/notifier/providers/gotify/gotify.go b/internal/pkg/core/notifier/providers/gotify/gotify.go
index 05b2f919..81dcb8ad 100644
--- a/internal/pkg/core/notifier/providers/gotify/gotify.go
+++ b/internal/pkg/core/notifier/providers/gotify/gotify.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log/slog"
- "net/http"
"strings"
"github.com/go-resty/resty/v2"
@@ -64,7 +63,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"message": message,
"priority": n.config.Priority,
})
- resp, err := req.Execute(http.MethodPost, fmt.Sprintf("%s/message", serverUrl))
+ resp, err := req.Post(fmt.Sprintf("%s/message", serverUrl))
if err != nil {
return nil, fmt.Errorf("gotify api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/mattermost/mattermost.go b/internal/pkg/core/notifier/providers/mattermost/mattermost.go
index 4f1c3e9c..a9b2f4d6 100644
--- a/internal/pkg/core/notifier/providers/mattermost/mattermost.go
+++ b/internal/pkg/core/notifier/providers/mattermost/mattermost.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log/slog"
- "net/http"
"strings"
"github.com/go-resty/resty/v2"
@@ -64,7 +63,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"login_id": n.config.Username,
"password": n.config.Password,
})
- loginResp, err := loginReq.Execute(http.MethodPost, fmt.Sprintf("%s/api/v4/users/login", serverUrl))
+ loginResp, err := loginReq.Post(fmt.Sprintf("%s/api/v4/users/login", serverUrl))
if err != nil {
return nil, fmt.Errorf("mattermost api error: failed to send request: %w", err)
} else if loginResp.IsError() {
@@ -88,7 +87,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
},
},
})
- postResp, err := postReq.Execute(http.MethodPost, fmt.Sprintf("%s/api/v4/posts", serverUrl))
+ postResp, err := postReq.Post(fmt.Sprintf("%s/api/v4/posts", serverUrl))
if err != nil {
return nil, fmt.Errorf("mattermost api error: failed to send request: %w", err)
} else if postResp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/pushover/pushover.go b/internal/pkg/core/notifier/providers/pushover/pushover.go
index 459a4950..b7f74bba 100644
--- a/internal/pkg/core/notifier/providers/pushover/pushover.go
+++ b/internal/pkg/core/notifier/providers/pushover/pushover.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log/slog"
- "net/http"
"github.com/go-resty/resty/v2"
@@ -59,7 +58,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"token": n.config.Token,
"user": n.config.User,
})
- resp, err := req.Execute(http.MethodPost, "https://api.pushover.net/1/messages.json")
+ resp, err := req.Post("https://api.pushover.net/1/messages.json")
if err != nil {
return nil, fmt.Errorf("pushover api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/pushplus/pushplus.go b/internal/pkg/core/notifier/providers/pushplus/pushplus.go
index a8a95ac7..834f9683 100644
--- a/internal/pkg/core/notifier/providers/pushplus/pushplus.go
+++ b/internal/pkg/core/notifier/providers/pushplus/pushplus.go
@@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"log/slog"
- "net/http"
"github.com/go-resty/resty/v2"
@@ -57,7 +56,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"content": message,
"token": n.config.Token,
})
- resp, err := req.Execute(http.MethodPost, "https://www.pushplus.plus/send")
+ resp, err := req.Post("https://www.pushplus.plus/send")
if err != nil {
return nil, fmt.Errorf("pushplus api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/serverchan/serverchan.go b/internal/pkg/core/notifier/providers/serverchan/serverchan.go
index cd77ce83..d74b2fcc 100644
--- a/internal/pkg/core/notifier/providers/serverchan/serverchan.go
+++ b/internal/pkg/core/notifier/providers/serverchan/serverchan.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log/slog"
- "net/http"
"github.com/go-resty/resty/v2"
@@ -55,7 +54,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"text": subject,
"desp": message,
})
- resp, err := req.Execute(http.MethodPost, n.config.ServerUrl)
+ resp, err := req.Post(n.config.ServerUrl)
if err != nil {
return nil, fmt.Errorf("serverchan api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go b/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go
index a324ee00..99b86a38 100644
--- a/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go
+++ b/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log/slog"
- "net/http"
"github.com/go-resty/resty/v2"
@@ -57,7 +56,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"chat_id": n.config.ChatId,
"text": subject + "\n" + message,
})
- resp, err := req.Execute(http.MethodPost, fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", n.config.BotToken))
+ resp, err := req.Post(fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", n.config.BotToken))
if err != nil {
return nil, fmt.Errorf("telegram api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/notifier/providers/wecombot/wecombot.go b/internal/pkg/core/notifier/providers/wecombot/wecombot.go
index daa771e0..36c179d4 100644
--- a/internal/pkg/core/notifier/providers/wecombot/wecombot.go
+++ b/internal/pkg/core/notifier/providers/wecombot/wecombot.go
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log/slog"
- "net/http"
"github.com/go-resty/resty/v2"
@@ -57,7 +56,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
"content": subject + "\n\n" + message,
},
})
- resp, err := req.Execute(http.MethodPost, n.config.WebhookUrl)
+ resp, err := req.Post(n.config.WebhookUrl)
if err != nil {
return nil, fmt.Errorf("wecom api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go
index e5a0b0ba..63900125 100644
--- a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go
+++ b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go
@@ -10,12 +10,14 @@ import (
"time"
"github.com/usual2970/certimate/internal/pkg/core/uploader"
- opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
+ onepanelsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
)
type UploaderConfig struct {
// 1Panel 地址。
ApiUrl string `json:"apiUrl"`
+ // 1Panel 版本。
+ ApiVersion string `json:"apiVersion"`
// 1Panel 接口密钥。
ApiKey string `json:"apiKey"`
}
@@ -23,7 +25,7 @@ type UploaderConfig struct {
type UploaderProvider struct {
config *UploaderConfig
logger *slog.Logger
- sdkClient *opsdk.Client
+ sdkClient *onepanelsdk.Client
}
var _ uploader.Uploader = (*UploaderProvider)(nil)
@@ -33,7 +35,7 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
panic("config is nil")
}
- client, err := createSdkClient(config.ApiUrl, config.ApiKey)
+ client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiKey)
if err != nil {
return nil, fmt.Errorf("failed to create sdk client: %w", err)
}
@@ -67,7 +69,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE
certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
// 上传证书
- uploadWebsiteSSLReq := &opsdk.UploadWebsiteSSLRequest{
+ uploadWebsiteSSLReq := &onepanelsdk.UploadWebsiteSSLRequest{
Type: "paste",
Description: certName,
Certificate: certPEM,
@@ -99,7 +101,7 @@ func (u *UploaderProvider) getCertIfExists(ctx context.Context, certPEM string,
default:
}
- searchWebsiteSSLReq := &opsdk.SearchWebsiteSSLRequest{
+ searchWebsiteSSLReq := &onepanelsdk.SearchWebsiteSSLRequest{
Page: searchWebsiteSSLPageNumber,
PageSize: searchWebsiteSSLPageSize,
}
@@ -130,15 +132,19 @@ func (u *UploaderProvider) getCertIfExists(ctx context.Context, certPEM string,
return nil, nil
}
-func createSdkClient(apiUrl, apiKey string) (*opsdk.Client, error) {
+func createSdkClient(apiUrl, apiVersion, apiKey string) (*onepanelsdk.Client, error) {
if _, err := url.Parse(apiUrl); err != nil {
return nil, errors.New("invalid 1panel api url")
}
+ if apiVersion == "" {
+ return nil, errors.New("invalid 1panel api version")
+ }
+
if apiKey == "" {
return nil, errors.New("invalid 1panel api key")
}
- client := opsdk.NewClient(apiUrl, apiKey)
+ client := onepanelsdk.NewClient(apiUrl, apiVersion, apiKey)
return client, nil
}
diff --git a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl_test.go b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl_test.go
index 257030f5..cfb250be 100644
--- a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl_test.go
+++ b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl_test.go
@@ -16,6 +16,7 @@ var (
fInputCertPath string
fInputKeyPath string
fApiUrl string
+ fApiVersion string
fApiKey string
)
@@ -25,6 +26,7 @@ func init() {
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
+ flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v1", "")
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
}
@@ -35,6 +37,7 @@ Shell command to run this test:
--CERTIMATE_UPLOADER_1PANELSSL_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_UPLOADER_1PANELSSL_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_UPLOADER_1PANELSSL_APIURL="http://127.0.0.1:20410" \
+ --CERTIMATE_UPLOADER_1PANELSSL_APIVERSION="v1" \
--CERTIMATE_UPLOADER_1PANELSSL_APIKEY="your-api-key"
*/
func TestDeploy(t *testing.T) {
@@ -46,12 +49,14 @@ func TestDeploy(t *testing.T) {
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
fmt.Sprintf("APIURL: %v", fApiUrl),
+ fmt.Sprintf("APIVERSION: %v", fApiVersion),
fmt.Sprintf("APIKEY: %v", fApiKey),
}, "\n"))
uploader, err := provider.NewUploader(&provider.UploaderConfig{
- ApiUrl: fApiUrl,
- ApiKey: fApiKey,
+ ApiUrl: fApiUrl,
+ ApiVersion: fApiVersion,
+ ApiKey: fApiKey,
})
if err != nil {
t.Errorf("err: %+v", err)
diff --git a/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate.go b/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate.go
new file mode 100644
index 00000000..b512be09
--- /dev/null
+++ b/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate.go
@@ -0,0 +1,143 @@
+package jdcloudssl
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log/slog"
+ "regexp"
+ "strings"
+ "time"
+
+ wangsusdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/certificate"
+
+ "github.com/usual2970/certimate/internal/pkg/core/uploader"
+ certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
+ typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
+)
+
+type UploaderConfig struct {
+ // 网宿云 AccessKeyId。
+ AccessKeyId string `json:"accessKeyId"`
+ // 网宿云 AccessKeySecret。
+ AccessKeySecret string `json:"accessKeySecret"`
+}
+
+type UploaderProvider struct {
+ config *UploaderConfig
+ logger *slog.Logger
+ sdkClient *wangsusdk.Client
+}
+
+var _ uploader.Uploader = (*UploaderProvider)(nil)
+
+func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create sdk client: %w", err)
+ }
+
+ return &UploaderProvider{
+ config: config,
+ logger: slog.Default(),
+ sdkClient: client,
+ }, nil
+}
+
+func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
+ if logger == nil {
+ u.logger = slog.Default()
+ } else {
+ u.logger = logger
+ }
+ return u
+}
+
+func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (res *uploader.UploadResult, err error) {
+ // 解析证书内容
+ certX509, err := certutil.ParseCertificateFromPEM(certPEM)
+ if err != nil {
+ return nil, err
+ }
+
+ // 查询证书列表,避免重复上传
+ // REF: https://www.wangsu.com/document/api-doc/26426
+ listCertificatesResp, err := u.sdkClient.ListCertificates()
+ u.logger.Debug("sdk request 'certificatemanagement.ListCertificates'", slog.Any("response", listCertificatesResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'certificatemanagement.ListCertificates': %w", err)
+ }
+
+ if listCertificatesResp.Certificates != nil {
+ for _, certificate := range listCertificatesResp.Certificates {
+ // 对比证书序列号
+ if !strings.EqualFold(certX509.SerialNumber.Text(16), certificate.Serial) {
+ continue
+ }
+
+ // 再对比证书有效期
+ cstzone := time.FixedZone("CST", 8*60*60)
+ oldCertNotBefore, _ := time.ParseInLocation(time.DateTime, certificate.ValidityFrom, cstzone)
+ oldCertNotAfter, _ := time.ParseInLocation(time.DateTime, certificate.ValidityTo, cstzone)
+ if !certX509.NotBefore.Equal(oldCertNotBefore) || !certX509.NotAfter.Equal(oldCertNotAfter) {
+ continue
+ }
+
+ // 如果以上信息都一致,则视为已存在相同证书,直接返回
+ u.logger.Info("ssl certificate already exists")
+ return &uploader.UploadResult{
+ CertId: certificate.CertificateId,
+ CertName: certificate.Name,
+ }, nil
+ }
+ }
+
+ // 生成新证书名(需符合网宿云命名规则)
+ var certId string
+ certName := fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
+
+ // 新增证书
+ // REF: https://www.wangsu.com/document/api-doc/25199?productCode=certificatemanagement
+ createCertificateReq := &wangsusdk.CreateCertificateRequest{
+ Name: typeutil.ToPtr(certName),
+ Certificate: typeutil.ToPtr(certPEM),
+ PrivateKey: typeutil.ToPtr(privkeyPEM),
+ Comment: typeutil.ToPtr("upload from certimate"),
+ }
+ createCertificateResp, err := u.sdkClient.CreateCertificate(createCertificateReq)
+ u.logger.Debug("sdk request 'certificatemanagement.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute sdk request 'certificatemanagement.CreateCertificate': %w", err)
+ }
+
+ // 网宿云证书 URL 中包含证书 ID
+ // 格式:
+ // https://open.chinanetcenter.com/api/certificate/100001
+ wangsuCertIdMatches := regexp.MustCompile(`/certificate/([0-9]+)`).FindStringSubmatch(createCertificateResp.CertificateUrl)
+ if len(wangsuCertIdMatches) > 1 {
+ certId = wangsuCertIdMatches[1]
+ } else {
+ return nil, fmt.Errorf("received empty certificate id")
+ }
+
+ return &uploader.UploadResult{
+ CertId: certId,
+ CertName: certName,
+ }, nil
+}
+
+func createSdkClient(accessKeyId, accessKeySecret string) (*wangsusdk.Client, error) {
+ if accessKeyId == "" {
+ return nil, errors.New("invalid wangsu access key id")
+ }
+
+ if accessKeySecret == "" {
+ return nil, errors.New("invalid wangsu access key secret")
+ }
+
+ return wangsusdk.NewClient(accessKeyId, accessKeySecret), nil
+}
diff --git a/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate_test.go b/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate_test.go
new file mode 100644
index 00000000..bdec8cfe
--- /dev/null
+++ b/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate_test.go
@@ -0,0 +1,72 @@
+package jdcloudssl_test
+
+import (
+ "context"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/wangsu-certificate"
+)
+
+var (
+ fInputCertPath string
+ fInputKeyPath string
+ fAccessKeyId string
+ fAccessKeySecret string
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_UPLOADER_JDCLOUDSSL_"
+
+ flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
+ flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
+ flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
+ flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./wangsu_certificate_test.go -args \
+ --CERTIMATE_UPLOADER_WANGSUCERTIFICATE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
+ --CERTIMATE_UPLOADER_WANGSUCERTIFICATE_INPUTKEYPATH="/path/to/your-input-key.pem" \
+ --CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_ACCESSKEYID="your-access-key-id" \
+ --CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_ACCESSKEYSECRET="your-access-key-secret"
+*/
+func TestDeploy(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Deploy", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
+ fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
+ fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
+ fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
+ }, "\n"))
+
+ uploader, err := provider.NewUploader(&provider.UploaderConfig{
+ AccessKeyId: fAccessKeyId,
+ AccessKeySecret: fAccessKeySecret,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ fInputCertData, _ := os.ReadFile(fInputCertPath)
+ fInputKeyData, _ := os.ReadFile(fInputKeyPath)
+ res, err := uploader.Upload(context.Background(), string(fInputCertData), string(fInputKeyData))
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ sres, _ := json.Marshal(res)
+ t.Logf("ok: %s", string(sres))
+ })
+}
diff --git a/internal/pkg/sdk3rd/1panel/client.go b/internal/pkg/sdk3rd/1panel/client.go
index e8946bae..003203d3 100644
--- a/internal/pkg/sdk3rd/1panel/client.go
+++ b/internal/pkg/sdk3rd/1panel/client.go
@@ -14,19 +14,30 @@ import (
)
type Client struct {
- apiHost string
- apiKey string
+ apiKey string
client *resty.Client
}
-func NewClient(apiHost, apiKey string) *Client {
- client := resty.New()
+func NewClient(apiHost, apiVersion, apiKey string) *Client {
+ if apiVersion == "" {
+ apiVersion = "v1"
+ }
+
+ client := resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/") + "/api/" + apiVersion).
+ SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
+ timestamp := fmt.Sprintf("%d", time.Now().Unix())
+ tokenMd5 := md5.Sum([]byte("1panel" + apiKey + timestamp))
+ tokenMd5Hex := hex.EncodeToString(tokenMd5[:])
+ req.Header.Set("1Panel-Timestamp", timestamp)
+ req.Header.Set("1Panel-Token", tokenMd5Hex)
+
+ return nil
+ })
return &Client{
- apiHost: strings.TrimRight(apiHost, "/"),
- apiKey: apiKey,
- client: client,
+ client: client,
}
}
@@ -40,16 +51,8 @@ func (c *Client) WithTLSConfig(config *tls.Config) *Client {
return c
}
-func (c *Client) generateToken(timestamp string) string {
- tokenMd5 := md5.Sum([]byte("1panel" + c.apiKey + timestamp))
- tokenMd5Hex := hex.EncodeToString(tokenMd5[:])
- return tokenMd5Hex
-}
-
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
req := c.client.R()
- req.Method = method
- req.URL = c.apiHost + "/api/v1" + path
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -65,17 +68,10 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- timestamp := fmt.Sprintf("%d", time.Now().Unix())
- token := c.generateToken(timestamp)
- req.SetHeader("1Panel-Timestamp", timestamp)
- req.SetHeader("1Panel-Token", token)
-
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("1panel api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/baishan/client.go b/internal/pkg/sdk3rd/baishan/client.go
index 81790a21..b3e428ee 100644
--- a/internal/pkg/sdk3rd/baishan/client.go
+++ b/internal/pkg/sdk3rd/baishan/client.go
@@ -13,17 +13,16 @@ import (
)
type Client struct {
- apiToken string
-
client *resty.Client
}
func NewClient(apiToken string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL("https://cdn.api.baishan.com").
+ SetHeader("token", apiToken)
return &Client{
- apiToken: apiToken,
- client: client,
+ client: client,
}
}
@@ -34,8 +33,6 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
req := c.client.R()
- req.Method = method
- req.URL = "https://cdn.api.baishan.com" + path
if strings.EqualFold(method, http.MethodGet) {
qs := url.Values{}
if params != nil {
@@ -61,17 +58,12 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
}
}
- req = req.
- SetQueryParam("token", c.apiToken).
- SetQueryParamsFromValues(qs)
+ req = req.SetQueryParamsFromValues(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetQueryParam("token", c.apiToken).
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("baishan api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/btpanel/client.go b/internal/pkg/sdk3rd/btpanel/client.go
index e09eed13..1da625da 100644
--- a/internal/pkg/sdk3rd/btpanel/client.go
+++ b/internal/pkg/sdk3rd/btpanel/client.go
@@ -14,19 +14,18 @@ import (
)
type Client struct {
- apiHost string
- apiKey string
+ apiKey string
client *resty.Client
}
func NewClient(apiHost, apiKey string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/"))
return &Client{
- apiHost: strings.TrimRight(apiHost, "/"),
- apiKey: apiKey,
- client: client,
+ apiKey: apiKey,
+ client: client,
}
}
@@ -78,11 +77,10 @@ func (c *Client) sendRequest(path string, params interface{}) (*resty.Response,
data["request_time"] = fmt.Sprintf("%d", timestamp)
data["request_token"] = c.generateSignature(fmt.Sprintf("%d", timestamp))
- url := c.apiHost + path
req := c.client.R().
SetHeader("Content-Type", "application/x-www-form-urlencoded").
SetFormData(data)
- resp, err := req.Post(url)
+ resp, err := req.Post(path)
if err != nil {
return resp, fmt.Errorf("baota api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/btwaf/api.go b/internal/pkg/sdk3rd/btwaf/api.go
new file mode 100644
index 00000000..bc35dee5
--- /dev/null
+++ b/internal/pkg/sdk3rd/btwaf/api.go
@@ -0,0 +1,19 @@
+package btwaf
+
+func (c *Client) GetSiteList(req *GetSiteListRequest) (*GetSiteListResponse, error) {
+ resp := &GetSiteListResponse{}
+ err := c.sendRequestWithResult("/wafmastersite/get_site_list", req, resp)
+ return resp, err
+}
+
+func (c *Client) ModifySite(req *ModifySiteRequest) (*ModifySiteResponse, error) {
+ resp := &ModifySiteResponse{}
+ err := c.sendRequestWithResult("/wafmastersite/modify_site", req, resp)
+ return resp, err
+}
+
+func (c *Client) ConfigSetSSL(req *ConfigSetSSLRequest) (*ConfigSetSSLResponse, error) {
+ resp := &ConfigSetSSLResponse{}
+ err := c.sendRequestWithResult("/config/set_cert", req, resp)
+ return resp, err
+}
diff --git a/internal/pkg/sdk3rd/btwaf/client.go b/internal/pkg/sdk3rd/btwaf/client.go
new file mode 100644
index 00000000..5ae545cc
--- /dev/null
+++ b/internal/pkg/sdk3rd/btwaf/client.go
@@ -0,0 +1,77 @@
+package btwaf
+
+import (
+ "crypto/md5"
+ "crypto/tls"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/go-resty/resty/v2"
+)
+
+type Client struct {
+ client *resty.Client
+}
+
+func NewClient(apiHost, apiKey string) *Client {
+ client := resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/") + "/api").
+ SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
+ timestamp := fmt.Sprintf("%d", time.Now().Unix())
+ keyMd5 := md5.Sum([]byte(apiKey))
+ keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:]))
+ signMd5 := md5.Sum([]byte(timestamp + keyMd5Hex))
+ signMd5Hex := strings.ToLower(hex.EncodeToString(signMd5[:]))
+ req.Header.Set("waf_request_time", timestamp)
+ req.Header.Set("waf_request_token", signMd5Hex)
+
+ return nil
+ })
+
+ return &Client{
+ client: client,
+ }
+}
+
+func (c *Client) WithTimeout(timeout time.Duration) *Client {
+ c.client.SetTimeout(timeout)
+ return c
+}
+
+func (c *Client) WithTLSConfig(config *tls.Config) *Client {
+ c.client.SetTLSClientConfig(config)
+ return c
+}
+
+func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) {
+ req := c.client.R().
+ SetHeader("Content-Type", "application/json").
+ SetBody(params)
+ resp, err := req.Post(path)
+ if err != nil {
+ return resp, fmt.Errorf("baota api error: failed to send request: %w", err)
+ } else if resp.IsError() {
+ return resp, fmt.Errorf("baota api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String())
+ }
+
+ return resp, nil
+}
+
+func (c *Client) sendRequestWithResult(path string, params interface{}, result BaseResponse) error {
+ resp, err := c.sendRequest(path, params)
+ if err != nil {
+ return err
+ }
+
+ if err := json.Unmarshal(resp.Body(), &result); err != nil {
+ return fmt.Errorf("baota api error: failed to unmarshal response: %w", err)
+ } else if errcode := result.GetCode(); errcode != 0 {
+ return fmt.Errorf("baota api error: code='%d'", errcode)
+ }
+
+ return nil
+}
diff --git a/internal/pkg/sdk3rd/btwaf/models.go b/internal/pkg/sdk3rd/btwaf/models.go
new file mode 100644
index 00000000..16290e88
--- /dev/null
+++ b/internal/pkg/sdk3rd/btwaf/models.go
@@ -0,0 +1,67 @@
+package btwaf
+
+type BaseResponse interface {
+ GetCode() int32
+}
+
+type baseResponse struct {
+ Code *int32 `json:"code,omitempty"`
+}
+
+func (r *baseResponse) GetCode() int32 {
+ if r.Code != nil {
+ return *r.Code
+ }
+ return 0
+}
+
+type GetSiteListRequest struct {
+ Page *int32 `json:"p,omitempty"`
+ PageSize *int32 `json:"p_size,omitempty"`
+ SiteName *string `json:"site_name,omitempty"`
+}
+
+type GetSiteListResponse struct {
+ baseResponse
+ Result *struct {
+ List []*struct {
+ SiteId string `json:"site_id"`
+ SiteName string `json:"site_name"`
+ Type string `json:"types"`
+ Status int32 `json:"status"`
+ CreateTime int64 `json:"create_time"`
+ UpdateTime int64 `json:"update_time"`
+ } `json:"list"`
+ Total int32 `json:"total"`
+ } `json:"res,omitempty"`
+}
+
+type SiteServerInfo struct {
+ ListenSSLPort *int32 `json:"listen_ssl_port,omitempty"`
+ SSL *SiteServerSSLInfo `json:"ssl,omitempty"`
+}
+
+type SiteServerSSLInfo struct {
+ IsSSL *int32 `json:"is_ssl,omitempty"`
+ FullChain *string `json:"full_chain,omitempty"`
+ PrivateKey *string `json:"private_key,omitempty"`
+}
+
+type ModifySiteRequest struct {
+ SiteId string `json:"site_id"`
+ Type *string `json:"types,omitempty"`
+ Server *SiteServerInfo `json:"server,omitempty"`
+}
+
+type ModifySiteResponse struct {
+ baseResponse
+}
+
+type ConfigSetSSLRequest struct {
+ CertContent string `json:"certContent"`
+ KeyContent string `json:"keyContent"`
+}
+
+type ConfigSetSSLResponse struct {
+ baseResponse
+}
diff --git a/internal/pkg/sdk3rd/bunny/client.go b/internal/pkg/sdk3rd/bunny/client.go
index 0f0dbea5..8d50e1fc 100644
--- a/internal/pkg/sdk3rd/bunny/client.go
+++ b/internal/pkg/sdk3rd/bunny/client.go
@@ -11,17 +11,16 @@ import (
)
type Client struct {
- apiToken string
-
client *resty.Client
}
func NewClient(apiToken string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL("https://api.bunny.net").
+ SetHeader("AccessKey", apiToken)
return &Client{
- apiToken: apiToken,
- client: client,
+ client: client,
}
}
@@ -32,9 +31,6 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
req := c.client.R()
- req.Method = method
- req.URL = "https://api.bunny.net" + path
- req = req.SetHeader("AccessKey", c.apiToken)
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -50,12 +46,10 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("bunny api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/cachefly/client.go b/internal/pkg/sdk3rd/cachefly/client.go
index 37a82ccc..342e329d 100644
--- a/internal/pkg/sdk3rd/cachefly/client.go
+++ b/internal/pkg/sdk3rd/cachefly/client.go
@@ -11,17 +11,16 @@ import (
)
type Client struct {
- apiToken string
-
client *resty.Client
}
func NewClient(apiToken string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL("https://api.cachefly.com/api/2.5").
+ SetHeader("x-cf-authorization", "Bearer "+apiToken)
return &Client{
- apiToken: apiToken,
- client: client,
+ client: client,
}
}
@@ -32,9 +31,6 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
req := c.client.R()
- req.Method = method
- req.URL = "https://api.cachefly.com/api/2.5" + path
- req = req.SetHeader("x-cf-authorization", "Bearer "+c.apiToken)
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -50,12 +46,10 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("cachefly api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/cdnfly/client.go b/internal/pkg/sdk3rd/cdnfly/client.go
index 5d80395c..c8753ed5 100644
--- a/internal/pkg/sdk3rd/cdnfly/client.go
+++ b/internal/pkg/sdk3rd/cdnfly/client.go
@@ -12,21 +12,17 @@ import (
)
type Client struct {
- apiHost string
- apiKey string
- apiSecret string
-
client *resty.Client
}
func NewClient(apiHost, apiKey, apiSecret string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/")).
+ SetHeader("api-key", apiKey).
+ SetHeader("api-secret", apiSecret)
return &Client{
- apiHost: strings.TrimRight(apiHost, "/"),
- apiKey: apiKey,
- apiSecret: apiSecret,
- client: client,
+ client: client,
}
}
@@ -42,11 +38,6 @@ func (c *Client) WithTLSConfig(config *tls.Config) *Client {
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
req := c.client.R()
- req.Method = method
- req.URL = c.apiHost + path
- req = req.
- SetHeader("api-key", c.apiKey).
- SetHeader("api-secret", c.apiSecret)
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -62,12 +53,10 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("cdnfly api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/dnsla/client.go b/internal/pkg/sdk3rd/dnsla/client.go
index a0659011..d9a86fc5 100644
--- a/internal/pkg/sdk3rd/dnsla/client.go
+++ b/internal/pkg/sdk3rd/dnsla/client.go
@@ -11,19 +11,16 @@ import (
)
type Client struct {
- apiId string
- apiSecret string
-
client *resty.Client
}
func NewClient(apiId, apiSecret string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL("https://api.dns.la/api").
+ SetBasicAuth(apiId, apiSecret)
return &Client{
- apiId: apiId,
- apiSecret: apiSecret,
- client: client,
+ client: client,
}
}
@@ -33,9 +30,7 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
}
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
- req := c.client.R().SetBasicAuth(c.apiId, c.apiSecret)
- req.Method = method
- req.URL = "https://api.dns.la/api" + path
+ req := c.client.R()
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -51,12 +46,10 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("dnsla api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/dogecloud/client.go b/internal/pkg/sdk3rd/dogecloud/client.go
index 46f3513d..75342907 100644
--- a/internal/pkg/sdk3rd/dogecloud/client.go
+++ b/internal/pkg/sdk3rd/dogecloud/client.go
@@ -164,8 +164,8 @@ func (c *Client) sendReq(method string, path string, data map[string]interface{}
if err != nil {
return nil, err
}
- req.Header.Add("Content-Type", mime)
- req.Header.Add("Authorization", auth)
+ req.Header.Set("Content-Type", mime)
+ req.Header.Set("Authorization", auth)
client := http.Client{}
resp, err := client.Do(req)
@@ -174,10 +174,10 @@ func (c *Client) sendReq(method string, path string, data map[string]interface{}
}
defer resp.Body.Close()
- r, err := io.ReadAll(resp.Body)
+ bytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
- return r, nil
+ return bytes, nil
}
diff --git a/internal/pkg/sdk3rd/flexcdn/api.go b/internal/pkg/sdk3rd/flexcdn/api.go
new file mode 100644
index 00000000..5008fdf4
--- /dev/null
+++ b/internal/pkg/sdk3rd/flexcdn/api.go
@@ -0,0 +1,48 @@
+package flexcdn
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "time"
+)
+
+func (c *Client) ensureAccessTokenExists() error {
+ c.accessTokenMtx.Lock()
+ defer c.accessTokenMtx.Unlock()
+ if c.accessToken != "" && c.accessTokenExp.After(time.Now()) {
+ return nil
+ }
+
+ req := &getAPIAccessTokenRequest{
+ Type: c.apiRole,
+ AccessKeyId: c.accessKeyId,
+ AccessKey: c.accessKey,
+ }
+ res, err := c.sendRequest(http.MethodPost, "/APIAccessTokenService/getAPIAccessToken", req)
+ if err != nil {
+ return err
+ }
+
+ resp := &getAPIAccessTokenResponse{}
+ if err := json.Unmarshal(res.Body(), &resp); err != nil {
+ return fmt.Errorf("flexcdn api error: failed to unmarshal response: %w", err)
+ } else if resp.GetCode() != 200 {
+ return fmt.Errorf("flexcdn get access token failed: code='%d', message='%s'", resp.GetCode(), resp.GetMessage())
+ }
+
+ c.accessToken = resp.Data.Token
+ c.accessTokenExp = time.Unix(resp.Data.ExpiresAt, 0)
+
+ return nil
+}
+
+func (c *Client) UpdateSSLCert(req *UpdateSSLCertRequest) (*UpdateSSLCertResponse, error) {
+ if err := c.ensureAccessTokenExists(); err != nil {
+ return nil, err
+ }
+
+ resp := &UpdateSSLCertResponse{}
+ err := c.sendRequestWithResult(http.MethodPost, "/SSLCertService/updateSSLCert", req, resp)
+ return resp, err
+}
diff --git a/internal/pkg/sdk3rd/flexcdn/client.go b/internal/pkg/sdk3rd/flexcdn/client.go
new file mode 100644
index 00000000..beae469a
--- /dev/null
+++ b/internal/pkg/sdk3rd/flexcdn/client.go
@@ -0,0 +1,102 @@
+package flexcdn
+
+import (
+ "crypto/tls"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/go-resty/resty/v2"
+)
+
+type Client struct {
+ apiRole string
+ accessKeyId string
+ accessKey string
+
+ accessToken string
+ accessTokenExp time.Time
+ accessTokenMtx sync.Mutex
+
+ client *resty.Client
+}
+
+func NewClient(apiHost, apiRole, accessKeyId, accessKey string) *Client {
+ client := &Client{
+ apiRole: apiRole,
+ accessKeyId: accessKeyId,
+ accessKey: accessKey,
+ }
+ client.client = resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/")).
+ SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
+ if client.accessToken != "" {
+ req.Header.Set("X-Cloud-Access-Token", client.accessToken)
+ }
+
+ return nil
+ })
+
+ return client
+}
+
+func (c *Client) WithTimeout(timeout time.Duration) *Client {
+ c.client.SetTimeout(timeout)
+ return c
+}
+
+func (c *Client) WithTLSConfig(config *tls.Config) *Client {
+ c.client.SetTLSClientConfig(config)
+ return c
+}
+
+func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
+ req := c.client.R()
+ if strings.EqualFold(method, http.MethodGet) {
+ qs := make(map[string]string)
+ if params != nil {
+ temp := make(map[string]any)
+ jsonb, _ := json.Marshal(params)
+ json.Unmarshal(jsonb, &temp)
+ for k, v := range temp {
+ if v != nil {
+ qs[k] = fmt.Sprintf("%v", v)
+ }
+ }
+ }
+
+ req = req.SetQueryParams(qs)
+ } else {
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
+ }
+
+ resp, err := req.Execute(method, path)
+ if err != nil {
+ return resp, fmt.Errorf("flexcdn api error: failed to send request: %w", err)
+ } else if resp.IsError() {
+ return resp, fmt.Errorf("flexcdn api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String())
+ }
+
+ return resp, nil
+}
+
+func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error {
+ resp, err := c.sendRequest(method, path, params)
+ if err != nil {
+ if resp != nil {
+ json.Unmarshal(resp.Body(), &result)
+ }
+ return err
+ }
+
+ if err := json.Unmarshal(resp.Body(), &result); err != nil {
+ return fmt.Errorf("flexcdn api error: failed to unmarshal response: %w", err)
+ } else if errcode := result.GetCode(); errcode != 200 {
+ return fmt.Errorf("flexcdn api error: code='%d', message='%s'", errcode, result.GetMessage())
+ }
+
+ return nil
+}
diff --git a/internal/pkg/sdk3rd/flexcdn/models.go b/internal/pkg/sdk3rd/flexcdn/models.go
new file mode 100644
index 00000000..c976eccc
--- /dev/null
+++ b/internal/pkg/sdk3rd/flexcdn/models.go
@@ -0,0 +1,52 @@
+package flexcdn
+
+type BaseResponse interface {
+ GetCode() int32
+ GetMessage() string
+}
+
+type baseResponse struct {
+ Code int32 `json:"code"`
+ Message string `json:"message"`
+}
+
+func (r *baseResponse) GetCode() int32 {
+ return r.Code
+}
+
+func (r *baseResponse) GetMessage() string {
+ return r.Message
+}
+
+type getAPIAccessTokenRequest struct {
+ Type string `json:"type"`
+ AccessKeyId string `json:"accessKeyId"`
+ AccessKey string `json:"accessKey"`
+}
+
+type getAPIAccessTokenResponse struct {
+ baseResponse
+ Data *struct {
+ Token string `json:"token"`
+ ExpiresAt int64 `json:"expiresAt"`
+ } `json:"data,omitempty"`
+}
+
+type UpdateSSLCertRequest struct {
+ SSLCertId int64 `json:"sslCertId"`
+ IsOn bool `json:"isOn"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ ServerName string `json:"serverName"`
+ IsCA bool `json:"isCA"`
+ CertData string `json:"certData"`
+ KeyData string `json:"keyData"`
+ TimeBeginAt int64 `json:"timeBeginAt"`
+ TimeEndAt int64 `json:"timeEndAt"`
+ DNSNames []string `json:"dnsNames"`
+ CommonNames []string `json:"commonNames"`
+}
+
+type UpdateSSLCertResponse struct {
+ baseResponse
+}
diff --git a/internal/pkg/sdk3rd/goedge/api.go b/internal/pkg/sdk3rd/goedge/api.go
index f0f60944..4589f70c 100644
--- a/internal/pkg/sdk3rd/goedge/api.go
+++ b/internal/pkg/sdk3rd/goedge/api.go
@@ -7,7 +7,13 @@ import (
"time"
)
-func (c *Client) getAccessToken() error {
+func (c *Client) ensureAccessTokenExists() error {
+ c.accessTokenMtx.Lock()
+ defer c.accessTokenMtx.Unlock()
+ if c.accessToken != "" && c.accessTokenExp.After(time.Now()) {
+ return nil
+ }
+
req := &getAPIAccessTokenRequest{
Type: c.apiRole,
AccessKeyId: c.accessKeyId,
@@ -22,22 +28,18 @@ func (c *Client) getAccessToken() error {
if err := json.Unmarshal(res.Body(), &resp); err != nil {
return fmt.Errorf("goedge api error: failed to unmarshal response: %w", err)
} else if resp.GetCode() != 200 {
- return fmt.Errorf("goedge get access token failed: code: %d, message: %s", resp.GetCode(), resp.GetMessage())
+ return fmt.Errorf("goedge get access token failed: code='%d', message='%s'", resp.GetCode(), resp.GetMessage())
}
- c.accessTokenMtx.Lock()
c.accessToken = resp.Data.Token
c.accessTokenExp = time.Unix(resp.Data.ExpiresAt, 0)
- c.accessTokenMtx.Unlock()
return nil
}
func (c *Client) UpdateSSLCert(req *UpdateSSLCertRequest) (*UpdateSSLCertResponse, error) {
- if c.accessToken == "" || c.accessTokenExp.Before(time.Now()) {
- if err := c.getAccessToken(); err != nil {
- return nil, err
- }
+ if err := c.ensureAccessTokenExists(); err != nil {
+ return nil, err
}
resp := &UpdateSSLCertResponse{}
diff --git a/internal/pkg/sdk3rd/goedge/client.go b/internal/pkg/sdk3rd/goedge/client.go
index e0a2ce49..3dc961e3 100644
--- a/internal/pkg/sdk3rd/goedge/client.go
+++ b/internal/pkg/sdk3rd/goedge/client.go
@@ -13,7 +13,6 @@ import (
)
type Client struct {
- apiHost string
apiRole string
accessKeyId string
accessKey string
@@ -26,15 +25,22 @@ type Client struct {
}
func NewClient(apiHost, apiRole, accessKeyId, accessKey string) *Client {
- client := resty.New()
-
- return &Client{
- apiHost: strings.TrimRight(apiHost, "/"),
+ client := &Client{
apiRole: apiRole,
accessKeyId: accessKeyId,
accessKey: accessKey,
- client: client,
}
+ client.client = resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/")).
+ SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
+ if client.accessToken != "" {
+ req.Header.Set("X-Edge-Access-Token", client.accessToken)
+ }
+
+ return nil
+ })
+
+ return client
}
func (c *Client) WithTimeout(timeout time.Duration) *Client {
@@ -48,9 +54,7 @@ func (c *Client) WithTLSConfig(config *tls.Config) *Client {
}
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
- req := c.client.R().SetBasicAuth(c.accessKeyId, c.accessKey)
- req.Method = method
- req.URL = c.apiHost + path
+ req := c.client.R()
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -64,17 +68,12 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
}
}
- req = req.
- SetQueryParams(qs).
- SetHeader("X-Edge-Access-Token", c.accessToken)
+ req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetHeader("X-Edge-Access-Token", c.accessToken).
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("goedge api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/lecdn/v3/client/api.go b/internal/pkg/sdk3rd/lecdn/v3/client/api.go
new file mode 100644
index 00000000..89f9cdc0
--- /dev/null
+++ b/internal/pkg/sdk3rd/lecdn/v3/client/api.go
@@ -0,0 +1,50 @@
+package client
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+)
+
+func (c *Client) ensureAccessTokenExists() error {
+ c.accessTokenMtx.Lock()
+ defer c.accessTokenMtx.Unlock()
+ if c.accessToken != "" {
+ return nil
+ }
+
+ req := &loginRequest{
+ Email: c.username,
+ Username: c.username,
+ Password: c.password,
+ }
+ res, err := c.sendRequest(http.MethodPost, "/login", req)
+ if err != nil {
+ return err
+ }
+
+ resp := &loginResponse{}
+ if err := json.Unmarshal(res.Body(), &resp); err != nil {
+ return fmt.Errorf("lecdn api error: failed to unmarshal response: %w", err)
+ } else if resp.GetCode() != 200 {
+ return fmt.Errorf("lecdn get token failed: code='%d', message='%s'", resp.GetCode(), resp.GetMessage())
+ }
+
+ c.accessToken = resp.Data.Token
+
+ return nil
+}
+
+func (c *Client) UpdateCertificate(certId int64, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
+ if certId == 0 {
+ return nil, fmt.Errorf("lecdn api error: invalid parameter: CertId")
+ }
+
+ if err := c.ensureAccessTokenExists(); err != nil {
+ return nil, err
+ }
+
+ resp := &UpdateCertificateResponse{}
+ err := c.sendRequestWithResult(http.MethodPut, fmt.Sprintf("/certificate/%d", certId), req, resp)
+ return resp, err
+}
diff --git a/internal/pkg/sdk3rd/lecdn/v3/client/client.go b/internal/pkg/sdk3rd/lecdn/v3/client/client.go
new file mode 100644
index 00000000..ad3a752e
--- /dev/null
+++ b/internal/pkg/sdk3rd/lecdn/v3/client/client.go
@@ -0,0 +1,99 @@
+package client
+
+import (
+ "crypto/tls"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/go-resty/resty/v2"
+)
+
+type Client struct {
+ username string
+ password string
+
+ accessToken string
+ accessTokenMtx sync.Mutex
+
+ client *resty.Client
+}
+
+func NewClient(apiHost, username, password string) *Client {
+ client := &Client{
+ username: username,
+ password: password,
+ }
+ client.client = resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/") + "/prod-api").
+ SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
+ if client.accessToken != "" {
+ req.Header.Set("Authorization", "Bearer "+client.accessToken)
+ }
+
+ return nil
+ })
+
+ return client
+}
+
+func (c *Client) WithTimeout(timeout time.Duration) *Client {
+ c.client.SetTimeout(timeout)
+ return c
+}
+
+func (c *Client) WithTLSConfig(config *tls.Config) *Client {
+ c.client.SetTLSClientConfig(config)
+ return c
+}
+
+func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
+ req := c.client.R()
+ if strings.EqualFold(method, http.MethodGet) {
+ qs := make(map[string]string)
+ if params != nil {
+ temp := make(map[string]any)
+ jsonb, _ := json.Marshal(params)
+ json.Unmarshal(jsonb, &temp)
+ for k, v := range temp {
+ if v != nil {
+ qs[k] = fmt.Sprintf("%v", v)
+ }
+ }
+ }
+
+ req = req.SetQueryParams(qs)
+ } else {
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
+ }
+
+ resp, err := req.Execute(method, path)
+ if err != nil {
+ return resp, fmt.Errorf("lecdn api error: failed to send request: %w", err)
+ } else if resp.IsError() {
+ return resp, fmt.Errorf("lecdn api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String())
+ }
+
+ return resp, nil
+}
+
+func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error {
+ resp, err := c.sendRequest(method, path, params)
+ if err != nil {
+ if resp != nil {
+ json.Unmarshal(resp.Body(), &result)
+ }
+ return err
+ }
+
+ if err := json.Unmarshal(resp.Body(), &result); err != nil {
+ return fmt.Errorf("lecdn api error: failed to unmarshal response: %w", err)
+ } else if errcode := result.GetCode(); errcode != 200 {
+ return fmt.Errorf("lecdn api error: code='%d', message='%s'", errcode, result.GetMessage())
+ }
+
+ return nil
+}
diff --git a/internal/pkg/sdk3rd/lecdn/v3/client/models.go b/internal/pkg/sdk3rd/lecdn/v3/client/models.go
new file mode 100644
index 00000000..6d63ea79
--- /dev/null
+++ b/internal/pkg/sdk3rd/lecdn/v3/client/models.go
@@ -0,0 +1,47 @@
+package client
+
+type BaseResponse interface {
+ GetCode() int32
+ GetMessage() string
+}
+
+type baseResponse struct {
+ Code int32 `json:"code"`
+ Message string `json:"msg"`
+}
+
+func (r *baseResponse) GetCode() int32 {
+ return r.Code
+}
+
+func (r *baseResponse) GetMessage() string {
+ return r.Message
+}
+
+type loginRequest struct {
+ Email string `json:"email"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+}
+
+type loginResponse struct {
+ baseResponse
+ Data *struct {
+ UserId int64 `json:"user_id"`
+ Username string `json:"username"`
+ Token string `json:"token"`
+ } `json:"data,omitempty"`
+}
+
+type UpdateCertificateRequest struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Type string `json:"type"`
+ SSLPEM string `json:"ssl_pem"`
+ SSLKey string `json:"ssl_key"`
+ AutoRenewal bool `json:"auto_renewal"`
+}
+
+type UpdateCertificateResponse struct {
+ baseResponse
+}
diff --git a/internal/pkg/sdk3rd/lecdn/v3/master/api.go b/internal/pkg/sdk3rd/lecdn/v3/master/api.go
new file mode 100644
index 00000000..00f24a70
--- /dev/null
+++ b/internal/pkg/sdk3rd/lecdn/v3/master/api.go
@@ -0,0 +1,49 @@
+package master
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+)
+
+func (c *Client) ensureAccessTokenExists() error {
+ c.accessTokenMtx.Lock()
+ defer c.accessTokenMtx.Unlock()
+ if c.accessToken != "" {
+ return nil
+ }
+
+ req := &loginRequest{
+ Username: c.username,
+ Password: c.password,
+ }
+ res, err := c.sendRequest(http.MethodPost, "/auth/login", req)
+ if err != nil {
+ return err
+ }
+
+ resp := &loginResponse{}
+ if err := json.Unmarshal(res.Body(), &resp); err != nil {
+ return fmt.Errorf("lecdn api error: failed to unmarshal response: %w", err)
+ } else if resp.GetCode() != 200 {
+ return fmt.Errorf("lecdn get token failed: code='%d', message='%s'", resp.GetCode(), resp.GetMessage())
+ }
+
+ c.accessToken = resp.Data.Token
+
+ return nil
+}
+
+func (c *Client) UpdateCertificate(certId int64, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
+ if certId == 0 {
+ return nil, fmt.Errorf("lecdn api error: invalid parameter: CertId")
+ }
+
+ if err := c.ensureAccessTokenExists(); err != nil {
+ return nil, err
+ }
+
+ resp := &UpdateCertificateResponse{}
+ err := c.sendRequestWithResult(http.MethodPut, fmt.Sprintf("/certificate/%d", certId), req, resp)
+ return resp, err
+}
diff --git a/internal/pkg/sdk3rd/lecdn/v3/master/client.go b/internal/pkg/sdk3rd/lecdn/v3/master/client.go
new file mode 100644
index 00000000..2da0c0c4
--- /dev/null
+++ b/internal/pkg/sdk3rd/lecdn/v3/master/client.go
@@ -0,0 +1,99 @@
+package master
+
+import (
+ "crypto/tls"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/go-resty/resty/v2"
+)
+
+type Client struct {
+ username string
+ password string
+
+ accessToken string
+ accessTokenMtx sync.Mutex
+
+ client *resty.Client
+}
+
+func NewClient(apiHost, username, password string) *Client {
+ client := &Client{
+ username: username,
+ password: password,
+ }
+ client.client = resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/") + "/prod-api").
+ SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
+ if client.accessToken != "" {
+ req.Header.Set("Authorization", "Bearer "+client.accessToken)
+ }
+
+ return nil
+ })
+
+ return client
+}
+
+func (c *Client) WithTimeout(timeout time.Duration) *Client {
+ c.client.SetTimeout(timeout)
+ return c
+}
+
+func (c *Client) WithTLSConfig(config *tls.Config) *Client {
+ c.client.SetTLSClientConfig(config)
+ return c
+}
+
+func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
+ req := c.client.R()
+ if strings.EqualFold(method, http.MethodGet) {
+ qs := make(map[string]string)
+ if params != nil {
+ temp := make(map[string]any)
+ jsonb, _ := json.Marshal(params)
+ json.Unmarshal(jsonb, &temp)
+ for k, v := range temp {
+ if v != nil {
+ qs[k] = fmt.Sprintf("%v", v)
+ }
+ }
+ }
+
+ req = req.SetQueryParams(qs)
+ } else {
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
+ }
+
+ resp, err := req.Execute(method, path)
+ if err != nil {
+ return resp, fmt.Errorf("lecdn api error: failed to send request: %w", err)
+ } else if resp.IsError() {
+ return resp, fmt.Errorf("lecdn api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String())
+ }
+
+ return resp, nil
+}
+
+func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error {
+ resp, err := c.sendRequest(method, path, params)
+ if err != nil {
+ if resp != nil {
+ json.Unmarshal(resp.Body(), &result)
+ }
+ return err
+ }
+
+ if err := json.Unmarshal(resp.Body(), &result); err != nil {
+ return fmt.Errorf("lecdn api error: failed to unmarshal response: %w", err)
+ } else if errcode := result.GetCode(); errcode != 200 {
+ return fmt.Errorf("lecdn api error: code='%d', message='%s'", errcode, result.GetMessage())
+ }
+
+ return nil
+}
diff --git a/internal/pkg/sdk3rd/lecdn/v3/master/models.go b/internal/pkg/sdk3rd/lecdn/v3/master/models.go
new file mode 100644
index 00000000..2e896f42
--- /dev/null
+++ b/internal/pkg/sdk3rd/lecdn/v3/master/models.go
@@ -0,0 +1,47 @@
+package master
+
+type BaseResponse interface {
+ GetCode() int32
+ GetMessage() string
+}
+
+type baseResponse struct {
+ Code int32 `json:"code"`
+ Message string `json:"message"`
+}
+
+func (r *baseResponse) GetCode() int32 {
+ return r.Code
+}
+
+func (r *baseResponse) GetMessage() string {
+ return r.Message
+}
+
+type loginRequest struct {
+ Username string `json:"username"`
+ Password string `json:"password"`
+}
+
+type loginResponse struct {
+ baseResponse
+ Data *struct {
+ UserId int64 `json:"user_id"`
+ Username string `json:"username"`
+ Token string `json:"token"`
+ } `json:"data,omitempty"`
+}
+
+type UpdateCertificateRequest struct {
+ ClientId int64 `json:"client_id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Type string `json:"type"`
+ SSLPEM string `json:"ssl_pem"`
+ SSLKey string `json:"ssl_key"`
+ AutoRenewal bool `json:"auto_renewal"`
+}
+
+type UpdateCertificateResponse struct {
+ baseResponse
+}
diff --git a/internal/pkg/sdk3rd/netlify/client.go b/internal/pkg/sdk3rd/netlify/client.go
index e3110077..d270e35e 100644
--- a/internal/pkg/sdk3rd/netlify/client.go
+++ b/internal/pkg/sdk3rd/netlify/client.go
@@ -11,17 +11,16 @@ import (
)
type Client struct {
- apiToken string
-
client *resty.Client
}
func NewClient(apiToken string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL("https://api.netlify.com/api/v1").
+ SetHeader("Authorization", "Bearer "+apiToken)
return &Client{
- apiToken: apiToken,
- client: client,
+ client: client,
}
}
@@ -31,9 +30,7 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
}
func (c *Client) sendRequest(method string, path string, queryParams interface{}, payloadParams interface{}) (*resty.Response, error) {
- req := c.client.R().SetHeader("Authorization", "Bearer "+c.apiToken)
- req.Method = method
- req.URL = "https://api.netlify.com/api/v1" + path
+ req := c.client.R()
if queryParams != nil {
qs := make(map[string]string)
@@ -63,12 +60,10 @@ func (c *Client) sendRequest(method string, path string, queryParams interface{}
req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(payloadParams)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(payloadParams)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("netlify api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/rainyun/client.go b/internal/pkg/sdk3rd/rainyun/client.go
index eb34efd1..80113f0d 100644
--- a/internal/pkg/sdk3rd/rainyun/client.go
+++ b/internal/pkg/sdk3rd/rainyun/client.go
@@ -11,16 +11,15 @@ import (
)
type Client struct {
- apiKey string
-
client *resty.Client
}
func NewClient(apiKey string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL("https://api.v2.rainyun.com").
+ SetHeader("x-api-key", apiKey)
return &Client{
- apiKey: apiKey,
client: client,
}
}
@@ -31,21 +30,17 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
}
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
- req := c.client.R().SetHeader("x-api-key", c.apiKey)
- req.Method = method
- req.URL = "https://api.v2.rainyun.com" + path
+ req := c.client.R()
if strings.EqualFold(method, http.MethodGet) {
if params != nil {
jsonb, _ := json.Marshal(params)
req = req.SetQueryParam("options", string(jsonb))
}
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("rainyun api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/ratpanel/client.go b/internal/pkg/sdk3rd/ratpanel/client.go
index e0562410..47202a04 100644
--- a/internal/pkg/sdk3rd/ratpanel/client.go
+++ b/internal/pkg/sdk3rd/ratpanel/client.go
@@ -20,7 +20,7 @@ type Client struct {
client *resty.Client
}
-func NewClient(apiHost string, accessTokenId uint, accessToken string) *Client {
+func NewClient(apiHost string, accessTokenId int32, accessToken string) *Client {
client := resty.New().
SetBaseURL(strings.TrimRight(apiHost, "/")+"/api").
SetHeader("Accept", "application/json").
@@ -81,8 +81,6 @@ func (c *Client) WithTLSConfig(config *tls.Config) *Client {
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
req := c.client.R()
- req.Method = method
- req.URL = path
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -98,12 +96,10 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("ratpanel api error: failed to send request: %w", err)
} else if resp.IsError() {
@@ -123,9 +119,9 @@ func (c *Client) sendRequestWithResult(method string, path string, params interf
}
if err = json.Unmarshal(resp.Body(), &result); err != nil {
- return fmt.Errorf("ratpanel api error: failed to parse response: %w", err)
- } else if errmessage := result.GetMessage(); errmessage != "success" {
- return fmt.Errorf("ratpanel api error: %d - %s", resp.StatusCode(), errmessage)
+ return fmt.Errorf("ratpanel api error: failed to unmarshal response: %w", err)
+ } else if errmsg := result.GetMessage(); errmsg != "success" {
+ return fmt.Errorf("ratpanel api error: message='%s'", errmsg)
}
return nil
diff --git a/internal/pkg/sdk3rd/safeline/client.go b/internal/pkg/sdk3rd/safeline/client.go
index 0412514c..efcd3bd6 100644
--- a/internal/pkg/sdk3rd/safeline/client.go
+++ b/internal/pkg/sdk3rd/safeline/client.go
@@ -11,19 +11,16 @@ import (
)
type Client struct {
- apiHost string
- apiToken string
-
client *resty.Client
}
func NewClient(apiHost, apiToken string) *Client {
- client := resty.New()
+ client := resty.New().
+ SetBaseURL(strings.TrimRight(apiHost, "/")).
+ SetHeader("X-SLCE-API-TOKEN", apiToken)
return &Client{
- apiHost: strings.TrimRight(apiHost, "/"),
- apiToken: apiToken,
- client: client,
+ client: client,
}
}
@@ -38,12 +35,10 @@ func (c *Client) WithTLSConfig(config *tls.Config) *Client {
}
func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) {
- url := c.apiHost + path
req := c.client.R().
SetHeader("Content-Type", "application/json").
- SetHeader("X-SLCE-API-TOKEN", c.apiToken).
SetBody(params)
- resp, err := req.Post(url)
+ resp, err := req.Post(path)
if err != nil {
return resp, fmt.Errorf("safeline api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/upyun/console/api.go b/internal/pkg/sdk3rd/upyun/console/api.go
index 32b4626e..ce62d3a6 100644
--- a/internal/pkg/sdk3rd/upyun/console/api.go
+++ b/internal/pkg/sdk3rd/upyun/console/api.go
@@ -7,7 +7,11 @@ import (
"net/http"
)
-func (c *Client) getCookie() error {
+func (c *Client) ensureCookieExists() error {
+ if c.loginCookie != "" {
+ return nil
+ }
+
req := &signinRequest{Username: c.username, Password: c.password}
res, err := c.sendRequest(http.MethodPost, "/accounts/signin/", req)
if err != nil {
@@ -27,10 +31,8 @@ func (c *Client) getCookie() error {
}
func (c *Client) UploadHttpsCertificate(req *UploadHttpsCertificateRequest) (*UploadHttpsCertificateResponse, error) {
- if c.loginCookie == "" {
- if err := c.getCookie(); err != nil {
- return nil, err
- }
+ if err := c.ensureCookieExists(); err != nil {
+ return nil, err
}
resp := &UploadHttpsCertificateResponse{}
@@ -39,10 +41,8 @@ func (c *Client) UploadHttpsCertificate(req *UploadHttpsCertificateRequest) (*Up
}
func (c *Client) GetHttpsCertificateManager(certificateId string) (*GetHttpsCertificateManagerResponse, error) {
- if c.loginCookie == "" {
- if err := c.getCookie(); err != nil {
- return nil, err
- }
+ if err := c.ensureCookieExists(); err != nil {
+ return nil, err
}
req := &GetHttpsCertificateManagerRequest{CertificateId: certificateId}
@@ -52,10 +52,8 @@ func (c *Client) GetHttpsCertificateManager(certificateId string) (*GetHttpsCert
}
func (c *Client) UpdateHttpsCertificateManager(req *UpdateHttpsCertificateManagerRequest) (*UpdateHttpsCertificateManagerResponse, error) {
- if c.loginCookie == "" {
- if err := c.getCookie(); err != nil {
- return nil, err
- }
+ if err := c.ensureCookieExists(); err != nil {
+ return nil, err
}
resp := &UpdateHttpsCertificateManagerResponse{}
@@ -64,10 +62,8 @@ func (c *Client) UpdateHttpsCertificateManager(req *UpdateHttpsCertificateManage
}
func (c *Client) GetHttpsServiceManager(domain string) (*GetHttpsServiceManagerResponse, error) {
- if c.loginCookie == "" {
- if err := c.getCookie(); err != nil {
- return nil, err
- }
+ if err := c.ensureCookieExists(); err != nil {
+ return nil, err
}
req := &GetHttpsServiceManagerRequest{Domain: domain}
@@ -77,10 +73,8 @@ func (c *Client) GetHttpsServiceManager(domain string) (*GetHttpsServiceManagerR
}
func (c *Client) MigrateHttpsDomain(req *MigrateHttpsDomainRequest) (*MigrateHttpsDomainResponse, error) {
- if c.loginCookie == "" {
- if err := c.getCookie(); err != nil {
- return nil, err
- }
+ if err := c.ensureCookieExists(); err != nil {
+ return nil, err
}
resp := &MigrateHttpsDomainResponse{}
diff --git a/internal/pkg/sdk3rd/upyun/console/client.go b/internal/pkg/sdk3rd/upyun/console/client.go
index 7a7ea7de..b207549e 100644
--- a/internal/pkg/sdk3rd/upyun/console/client.go
+++ b/internal/pkg/sdk3rd/upyun/console/client.go
@@ -20,13 +20,21 @@ type Client struct {
}
func NewClient(username, password string) *Client {
- client := resty.New()
-
- return &Client{
+ client := &Client{
username: username,
password: password,
- client: client,
}
+ client.client = resty.New().
+ SetBaseURL("https://console.upyun.com").
+ SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
+ if client.loginCookie != "" {
+ req.Header.Set("Cookie", client.loginCookie)
+ }
+
+ return nil
+ })
+
+ return client
}
func (c *Client) WithTimeout(timeout time.Duration) *Client {
@@ -35,9 +43,7 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
}
func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) {
- req := c.client.R().SetBasicAuth(c.username, c.password)
- req.Method = method
- req.URL = "https://console.upyun.com" + path
+ req := c.client.R()
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -51,17 +57,12 @@ func (c *Client) sendRequest(method string, path string, params interface{}) (*r
}
}
- req = req.
- SetQueryParams(qs).
- SetHeader("Cookie", c.loginCookie)
+ req = req.SetQueryParams(qs)
} else {
- req = req.
- SetHeader("Content-Type", "application/json").
- SetHeader("Cookie", c.loginCookie).
- SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("upyun api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/sdk3rd/wangsu/cdn/api.go b/internal/pkg/sdk3rd/wangsu/cdn/api.go
index 0da647c8..997c05bf 100644
--- a/internal/pkg/sdk3rd/wangsu/cdn/api.go
+++ b/internal/pkg/sdk3rd/wangsu/cdn/api.go
@@ -1,70 +1,15 @@
package cdn
import (
- "fmt"
"net/http"
- "net/url"
-
- "github.com/go-resty/resty/v2"
)
-func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
- resp := &CreateCertificateResponse{}
- r, err := c.client.SendRequestWithResult(http.MethodPost, "/cdn/certificates", req, resp, func(r *resty.Request) {
- r.SetHeader("x-cnc-timestamp", fmt.Sprintf("%d", req.Timestamp))
- })
+func (c *Client) BatchUpdateCertificateConfig(req *BatchUpdateCertificateConfigRequest) (*BatchUpdateCertificateConfigResponse, error) {
+ resp := &BatchUpdateCertificateConfigResponse{}
+ _, err := c.client.SendRequestWithResult(http.MethodPut, "/api/config/certificate/batch", req, resp)
if err != nil {
return resp, err
}
- resp.CertificateUrl = r.Header().Get("Location")
- return resp, err
-}
-
-func (c *Client) UpdateCertificate(certificateId string, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
- if certificateId == "" {
- return nil, fmt.Errorf("wangsu api error: invalid parameter: certificateId")
- }
-
- resp := &UpdateCertificateResponse{}
- r, err := c.client.SendRequestWithResult(http.MethodPatch, fmt.Sprintf("/cdn/certificates/%s", url.PathEscape(certificateId)), req, resp, func(r *resty.Request) {
- r.SetHeader("x-cnc-timestamp", fmt.Sprintf("%d", req.Timestamp))
- })
- if err != nil {
- return resp, err
- }
-
- resp.CertificateUrl = r.Header().Get("Location")
- return resp, err
-}
-
-func (c *Client) GetHostnameDetail(hostname string) (*GetHostnameDetailResponse, error) {
- if hostname == "" {
- return nil, fmt.Errorf("wangsu api error: invalid parameter: hostname")
- }
-
- resp := &GetHostnameDetailResponse{}
- _, err := c.client.SendRequestWithResult(http.MethodGet, fmt.Sprintf("/cdn/hostnames/%s", url.PathEscape(hostname)), nil, resp)
- return resp, err
-}
-
-func (c *Client) CreateDeploymentTask(req *CreateDeploymentTaskRequest) (*CreateDeploymentTaskResponse, error) {
- resp := &CreateDeploymentTaskResponse{}
- r, err := c.client.SendRequestWithResult(http.MethodPost, "/cdn/deploymentTasks", req, resp)
- if err != nil {
- return resp, err
- }
-
- resp.DeploymentTaskUrl = r.Header().Get("Location")
- return resp, err
-}
-
-func (c *Client) GetDeploymentTaskDetail(deploymentTaskId string) (*GetDeploymentTaskDetailResponse, error) {
- if deploymentTaskId == "" {
- return nil, fmt.Errorf("wangsu api error: invalid parameter: deploymentTaskId")
- }
-
- resp := &GetDeploymentTaskDetailResponse{}
- _, err := c.client.SendRequestWithResult(http.MethodGet, fmt.Sprintf("/cdn/deploymentTasks/%s", url.PathEscape(deploymentTaskId)), nil, resp)
return resp, err
}
diff --git a/internal/pkg/sdk3rd/wangsu/cdn/models.go b/internal/pkg/sdk3rd/wangsu/cdn/models.go
index a9a9ec74..5bf934af 100644
--- a/internal/pkg/sdk3rd/wangsu/cdn/models.go
+++ b/internal/pkg/sdk3rd/wangsu/cdn/models.go
@@ -5,7 +5,7 @@ import (
)
type baseResponse struct {
- RequestId *string `json:"-"`
+ RequestId *string `json:"requestId,omitempty"`
Code *string `json:"code,omitempty"`
Message *string `json:"message,omitempty"`
}
@@ -16,93 +16,11 @@ func (r *baseResponse) SetRequestId(requestId string) {
r.RequestId = &requestId
}
-type CertificateVersion struct {
- Comments *string `json:"comments,omitempty"`
- PrivateKey *string `json:"privateKey,omitempty"`
- Certificate *string `json:"certificate,omitempty"`
- ChainCert *string `json:"chainCert,omitempty"`
- IdentificationInfo *CertificateVersionIdentificationInfo `json:"identificationInfo,omitempty"`
+type BatchUpdateCertificateConfigRequest struct {
+ CertificateId int64 `json:"certificateId" required:"true"`
+ DomainNames []string `json:"domainNames" required:"true"`
}
-type CertificateVersionIdentificationInfo struct {
- Country *string `json:"country,omitempty"`
- State *string `json:"state,omitempty"`
- City *string `json:"city,omitempty"`
- Company *string `json:"company,omitempty"`
- Department *string `json:"department,omitempty"`
- CommonName *string `json:"commonName,omitempty" required:"true"`
- Email *string `json:"email,omitempty"`
- SubjectAlternativeNames *[]string `json:"subjectAlternativeNames,omitempty" required:"true"`
-}
-
-type CreateCertificateRequest struct {
- Timestamp int64 `json:"-"`
- Name *string `json:"name,omitempty" required:"true"`
- Description *string `json:"description,omitempty"`
- AutoRenew *string `json:"autoRenew,omitempty"`
- ForceRenew *bool `json:"forceRenew,omitempty"`
- NewVersion *CertificateVersion `json:"newVersion,omitempty" required:"true"`
-}
-
-type CreateCertificateResponse struct {
+type BatchUpdateCertificateConfigResponse struct {
baseResponse
- CertificateUrl string `json:"location,omitempty"`
-}
-
-type UpdateCertificateRequest struct {
- Timestamp int64 `json:"-"`
- Name *string `json:"name,omitempty"`
- Description *string `json:"description,omitempty"`
- AutoRenew *string `json:"autoRenew,omitempty"`
- ForceRenew *bool `json:"forceRenew,omitempty"`
- NewVersion *CertificateVersion `json:"newVersion,omitempty" required:"true"`
-}
-
-type UpdateCertificateResponse struct {
- baseResponse
- CertificateUrl string `json:"location,omitempty"`
-}
-
-type HostnameProperty struct {
- PropertyId string `json:"propertyId"`
- Version int32 `json:"version"`
- CertificateId *string `json:"certificateId,omitempty"`
-}
-
-type GetHostnameDetailResponse struct {
- baseResponse
- Hostname string `json:"hostname"`
- PropertyInProduction *HostnameProperty `json:"propertyInProduction,omitempty"`
- PropertyInStaging *HostnameProperty `json:"propertyInStaging,omitempty"`
-}
-
-type DeploymentTaskAction struct {
- Action *string `json:"action,omitempty" required:"true"`
- PropertyId *string `json:"propertyId,omitempty"`
- CertificateId *string `json:"certificateId,omitempty"`
- Version *int32 `json:"version,omitempty"`
-}
-
-type CreateDeploymentTaskRequest struct {
- Name *string `json:"name,omitempty"`
- Target *string `json:"target,omitempty" required:"true"`
- Actions *[]DeploymentTaskAction `json:"actions,omitempty" required:"true"`
- Webhook *string `json:"webhook,omitempty"`
-}
-
-type CreateDeploymentTaskResponse struct {
- baseResponse
- DeploymentTaskUrl string `json:"location,omitempty"`
-}
-
-type GetDeploymentTaskDetailResponse struct {
- baseResponse
- Name string `json:"name"`
- Target string `json:"target"`
- Actions []DeploymentTaskAction `json:"actions"`
- Status string `json:"status"`
- StatusDetails string `json:"statusDetails"`
- SubmissionTime string `json:"submissionTime"`
- FinishTime string `json:"finishTime"`
- ApiRequestId string `json:"apiRequestId"`
}
diff --git a/internal/pkg/sdk3rd/wangsu/cdnpro/api.go b/internal/pkg/sdk3rd/wangsu/cdnpro/api.go
new file mode 100644
index 00000000..c6f8da04
--- /dev/null
+++ b/internal/pkg/sdk3rd/wangsu/cdnpro/api.go
@@ -0,0 +1,70 @@
+package cdnpro
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+
+ "github.com/go-resty/resty/v2"
+)
+
+func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
+ resp := &CreateCertificateResponse{}
+ rres, err := c.client.SendRequestWithResult(http.MethodPost, "/cdn/certificates", req, resp, func(r *resty.Request) {
+ r.SetHeader("x-cnc-timestamp", fmt.Sprintf("%d", req.Timestamp))
+ })
+ if err != nil {
+ return resp, err
+ }
+
+ resp.CertificateUrl = rres.Header().Get("Location")
+ return resp, err
+}
+
+func (c *Client) UpdateCertificate(certificateId string, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
+ if certificateId == "" {
+ return nil, fmt.Errorf("wangsu api error: invalid parameter: certificateId")
+ }
+
+ resp := &UpdateCertificateResponse{}
+ rres, err := c.client.SendRequestWithResult(http.MethodPatch, fmt.Sprintf("/cdn/certificates/%s", url.PathEscape(certificateId)), req, resp, func(r *resty.Request) {
+ r.SetHeader("x-cnc-timestamp", fmt.Sprintf("%d", req.Timestamp))
+ })
+ if err != nil {
+ return resp, err
+ }
+
+ resp.CertificateUrl = rres.Header().Get("Location")
+ return resp, err
+}
+
+func (c *Client) GetHostnameDetail(hostname string) (*GetHostnameDetailResponse, error) {
+ if hostname == "" {
+ return nil, fmt.Errorf("wangsu api error: invalid parameter: hostname")
+ }
+
+ resp := &GetHostnameDetailResponse{}
+ _, err := c.client.SendRequestWithResult(http.MethodGet, fmt.Sprintf("/cdn/hostnames/%s", url.PathEscape(hostname)), nil, resp)
+ return resp, err
+}
+
+func (c *Client) CreateDeploymentTask(req *CreateDeploymentTaskRequest) (*CreateDeploymentTaskResponse, error) {
+ resp := &CreateDeploymentTaskResponse{}
+ rres, err := c.client.SendRequestWithResult(http.MethodPost, "/cdn/deploymentTasks", req, resp)
+ if err != nil {
+ return resp, err
+ }
+
+ resp.DeploymentTaskUrl = rres.Header().Get("Location")
+ return resp, err
+}
+
+func (c *Client) GetDeploymentTaskDetail(deploymentTaskId string) (*GetDeploymentTaskDetailResponse, error) {
+ if deploymentTaskId == "" {
+ return nil, fmt.Errorf("wangsu api error: invalid parameter: deploymentTaskId")
+ }
+
+ resp := &GetDeploymentTaskDetailResponse{}
+ _, err := c.client.SendRequestWithResult(http.MethodGet, fmt.Sprintf("/cdn/deploymentTasks/%s", url.PathEscape(deploymentTaskId)), nil, resp)
+ return resp, err
+}
diff --git a/internal/pkg/sdk3rd/wangsu/cdnpro/client.go b/internal/pkg/sdk3rd/wangsu/cdnpro/client.go
new file mode 100644
index 00000000..b5c0f530
--- /dev/null
+++ b/internal/pkg/sdk3rd/wangsu/cdnpro/client.go
@@ -0,0 +1,20 @@
+package cdnpro
+
+import (
+ "time"
+
+ "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/openapi"
+)
+
+type Client struct {
+ client *openapi.Client
+}
+
+func NewClient(accessKey, secretKey string) *Client {
+ return &Client{client: openapi.NewClient(accessKey, secretKey)}
+}
+
+func (c *Client) WithTimeout(timeout time.Duration) *Client {
+ c.client.WithTimeout(timeout)
+ return c
+}
diff --git a/internal/pkg/sdk3rd/wangsu/cdnpro/models.go b/internal/pkg/sdk3rd/wangsu/cdnpro/models.go
new file mode 100644
index 00000000..9cb1e648
--- /dev/null
+++ b/internal/pkg/sdk3rd/wangsu/cdnpro/models.go
@@ -0,0 +1,108 @@
+package cdnpro
+
+import (
+ "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/openapi"
+)
+
+type baseResponse struct {
+ RequestId *string `json:"requestId,omitempty"`
+ Code *string `json:"code,omitempty"`
+ Message *string `json:"message,omitempty"`
+}
+
+var _ openapi.Result = (*baseResponse)(nil)
+
+func (r *baseResponse) SetRequestId(requestId string) {
+ r.RequestId = &requestId
+}
+
+type CertificateVersion struct {
+ Comments *string `json:"comments,omitempty"`
+ PrivateKey *string `json:"privateKey,omitempty"`
+ Certificate *string `json:"certificate,omitempty"`
+ ChainCert *string `json:"chainCert,omitempty"`
+ IdentificationInfo *CertificateVersionIdentificationInfo `json:"identificationInfo,omitempty"`
+}
+
+type CertificateVersionIdentificationInfo struct {
+ Country *string `json:"country,omitempty"`
+ State *string `json:"state,omitempty"`
+ City *string `json:"city,omitempty"`
+ Company *string `json:"company,omitempty"`
+ Department *string `json:"department,omitempty"`
+ CommonName *string `json:"commonName,omitempty" required:"true"`
+ Email *string `json:"email,omitempty"`
+ SubjectAlternativeNames *[]string `json:"subjectAlternativeNames,omitempty" required:"true"`
+}
+
+type CreateCertificateRequest struct {
+ Timestamp int64 `json:"-"`
+ Name *string `json:"name,omitempty" required:"true"`
+ Description *string `json:"description,omitempty"`
+ AutoRenew *string `json:"autoRenew,omitempty"`
+ ForceRenew *bool `json:"forceRenew,omitempty"`
+ NewVersion *CertificateVersion `json:"newVersion,omitempty" required:"true"`
+}
+
+type CreateCertificateResponse struct {
+ baseResponse
+ CertificateUrl string `json:"location,omitempty"`
+}
+
+type UpdateCertificateRequest struct {
+ Timestamp int64 `json:"-"`
+ Name *string `json:"name,omitempty"`
+ Description *string `json:"description,omitempty"`
+ AutoRenew *string `json:"autoRenew,omitempty"`
+ ForceRenew *bool `json:"forceRenew,omitempty"`
+ NewVersion *CertificateVersion `json:"newVersion,omitempty" required:"true"`
+}
+
+type UpdateCertificateResponse struct {
+ baseResponse
+ CertificateUrl string `json:"location,omitempty"`
+}
+
+type HostnameProperty struct {
+ PropertyId string `json:"propertyId"`
+ Version int32 `json:"version"`
+ CertificateId *string `json:"certificateId,omitempty"`
+}
+
+type GetHostnameDetailResponse struct {
+ baseResponse
+ Hostname string `json:"hostname"`
+ PropertyInProduction *HostnameProperty `json:"propertyInProduction,omitempty"`
+ PropertyInStaging *HostnameProperty `json:"propertyInStaging,omitempty"`
+}
+
+type DeploymentTaskAction struct {
+ Action *string `json:"action,omitempty" required:"true"`
+ PropertyId *string `json:"propertyId,omitempty"`
+ CertificateId *string `json:"certificateId,omitempty"`
+ Version *int32 `json:"version,omitempty"`
+}
+
+type CreateDeploymentTaskRequest struct {
+ Name *string `json:"name,omitempty"`
+ Target *string `json:"target,omitempty" required:"true"`
+ Actions *[]DeploymentTaskAction `json:"actions,omitempty" required:"true"`
+ Webhook *string `json:"webhook,omitempty"`
+}
+
+type CreateDeploymentTaskResponse struct {
+ baseResponse
+ DeploymentTaskUrl string `json:"location,omitempty"`
+}
+
+type GetDeploymentTaskDetailResponse struct {
+ baseResponse
+ Name string `json:"name"`
+ Target string `json:"target"`
+ Actions []DeploymentTaskAction `json:"actions"`
+ Status string `json:"status"`
+ StatusDetails string `json:"statusDetails"`
+ SubmissionTime string `json:"submissionTime"`
+ FinishTime string `json:"finishTime"`
+ ApiRequestId string `json:"apiRequestId"`
+}
diff --git a/internal/pkg/sdk3rd/wangsu/certificate/api.go b/internal/pkg/sdk3rd/wangsu/certificate/api.go
new file mode 100644
index 00000000..037fb6e7
--- /dev/null
+++ b/internal/pkg/sdk3rd/wangsu/certificate/api.go
@@ -0,0 +1,42 @@
+package certificate
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+)
+
+func (c *Client) ListCertificates() (*ListCertificatesResponse, error) {
+ resp := &ListCertificatesResponse{}
+ _, err := c.client.SendRequestWithResult(http.MethodGet, "/api/certificate", nil, resp)
+ if err != nil {
+ return resp, err
+ }
+
+ return resp, err
+}
+
+func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
+ resp := &CreateCertificateResponse{}
+ rres, err := c.client.SendRequestWithResult(http.MethodPost, "/api/certificate", req, resp)
+ if err != nil {
+ return resp, err
+ }
+
+ resp.CertificateUrl = rres.Header().Get("Location")
+ return resp, err
+}
+
+func (c *Client) UpdateCertificate(certificateId string, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
+ if certificateId == "" {
+ return nil, fmt.Errorf("wangsu api error: invalid parameter: certificateId")
+ }
+
+ resp := &UpdateCertificateResponse{}
+ _, err := c.client.SendRequestWithResult(http.MethodPut, fmt.Sprintf("/api/certificate/%s", url.PathEscape(certificateId)), req, resp)
+ if err != nil {
+ return resp, err
+ }
+
+ return resp, err
+}
diff --git a/internal/pkg/sdk3rd/wangsu/certificate/client.go b/internal/pkg/sdk3rd/wangsu/certificate/client.go
new file mode 100644
index 00000000..19f4cfaa
--- /dev/null
+++ b/internal/pkg/sdk3rd/wangsu/certificate/client.go
@@ -0,0 +1,20 @@
+package certificate
+
+import (
+ "time"
+
+ "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/openapi"
+)
+
+type Client struct {
+ client *openapi.Client
+}
+
+func NewClient(accessKey, secretKey string) *Client {
+ return &Client{client: openapi.NewClient(accessKey, secretKey)}
+}
+
+func (c *Client) WithTimeout(timeout time.Duration) *Client {
+ c.client.WithTimeout(timeout)
+ return c
+}
diff --git a/internal/pkg/sdk3rd/wangsu/certificate/models.go b/internal/pkg/sdk3rd/wangsu/certificate/models.go
new file mode 100644
index 00000000..4e882e7c
--- /dev/null
+++ b/internal/pkg/sdk3rd/wangsu/certificate/models.go
@@ -0,0 +1,52 @@
+package certificate
+
+import (
+ "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/openapi"
+)
+
+type baseResponse struct {
+ RequestId *string `json:"requestId,omitempty"`
+ Code *string `json:"code,omitempty"`
+ Message *string `json:"message,omitempty"`
+}
+
+var _ openapi.Result = (*baseResponse)(nil)
+
+func (r *baseResponse) SetRequestId(requestId string) {
+ r.RequestId = &requestId
+}
+
+type CreateCertificateRequest struct {
+ Name *string `json:"name,omitempty" required:"true"`
+ Certificate *string `json:"certificate,omitempty" required:"true"`
+ PrivateKey *string `json:"privateKey,omitempty"`
+ Comment *string `json:"comment,omitempty" `
+}
+
+type CreateCertificateResponse struct {
+ baseResponse
+ CertificateUrl string `json:"location,omitempty"`
+}
+
+type UpdateCertificateRequest struct {
+ Name *string `json:"name,omitempty" required:"true"`
+ Certificate *string `json:"certificate,omitempty"`
+ PrivateKey *string `json:"privateKey,omitempty"`
+ Comment *string `json:"comment,omitempty" `
+}
+
+type UpdateCertificateResponse struct {
+ baseResponse
+}
+
+type ListCertificatesResponse struct {
+ baseResponse
+ Certificates []*struct {
+ CertificateId string `json:"certificate-id"`
+ Name string `json:"name"`
+ Comment string `json:"comment"`
+ ValidityFrom string `json:"certificate-validity-from"`
+ ValidityTo string `json:"certificate-validity-to"`
+ Serial string `json:"certificate-serial"`
+ } `json:"ssl-certificates,omitempty"`
+}
diff --git a/internal/pkg/sdk3rd/wangsu/openapi/client.go b/internal/pkg/sdk3rd/wangsu/openapi/client.go
index 95d17bb0..a8f4f2af 100644
--- a/internal/pkg/sdk3rd/wangsu/openapi/client.go
+++ b/internal/pkg/sdk3rd/wangsu/openapi/client.go
@@ -134,8 +134,6 @@ func (c *Client) WithTimeout(timeout time.Duration) *Client {
func (c *Client) sendRequest(method string, path string, params interface{}, configureReq ...func(req *resty.Request)) (*resty.Response, error) {
req := c.client.R()
- req.Method = method
- req.URL = path
if strings.EqualFold(method, http.MethodGet) {
qs := make(map[string]string)
if params != nil {
@@ -151,14 +149,16 @@ func (c *Client) sendRequest(method string, path string, params interface{}, con
req = req.SetQueryParams(qs)
} else {
- req = req.SetBody(params)
+ req = req.SetHeader("Content-Type", "application/json").SetBody(params)
}
- for _, fn := range configureReq {
- fn(req)
+ if configureReq != nil {
+ for _, fn := range configureReq {
+ fn(req)
+ }
}
- resp, err := req.Send()
+ resp, err := req.Execute(method, path)
if err != nil {
return resp, fmt.Errorf("wangsu api error: failed to send request: %w", err)
} else if resp.IsError() {
diff --git a/internal/pkg/utils/map/getter.go b/internal/pkg/utils/map/getter.go
index f30f6d33..512da3ee 100644
--- a/internal/pkg/utils/map/getter.go
+++ b/internal/pkg/utils/map/getter.go
@@ -68,31 +68,42 @@ func GetOrDefaultInt32(dict map[string]any, key string, defaultValue int32) int3
}
if value, ok := dict[key]; ok {
- if result, ok := value.(int32); ok {
- if result != 0 {
- return result
+ var result int32
+
+ switch v := value.(type) {
+ case int:
+ result = int32(v)
+ case int8:
+ result = int32(v)
+ case int16:
+ result = int32(v)
+ case int32:
+ result = v
+ case int64:
+ result = int32(v)
+ case uint:
+ result = int32(v)
+ case uint8:
+ result = int32(v)
+ case uint16:
+ result = int32(v)
+ case uint32:
+ result = int32(v)
+ case uint64:
+ result = int32(v)
+ case float32:
+ result = int32(v)
+ case float64:
+ result = int32(v)
+ case string:
+ // 兼容字符串类型的值
+ if t, err := strconv.ParseInt(v, 10, 32); err == nil {
+ result = int32(t)
}
}
- if result, ok := value.(int64); ok {
- if result != 0 {
- return int32(result)
- }
- }
-
- if result, ok := value.(int); ok {
- if result != 0 {
- return int32(result)
- }
- }
-
- // 兼容字符串类型的值
- if str, ok := value.(string); ok {
- if result, err := strconv.ParseInt(str, 10, 32); err == nil {
- if result != 0 {
- return int32(result)
- }
- }
+ if result != 0 {
+ return int32(result)
}
}
@@ -126,31 +137,42 @@ func GetOrDefaultInt64(dict map[string]any, key string, defaultValue int64) int6
}
if value, ok := dict[key]; ok {
- if result, ok := value.(int64); ok {
- if result != 0 {
- return result
+ var result int64
+
+ switch v := value.(type) {
+ case int:
+ result = int64(v)
+ case int8:
+ result = int64(v)
+ case int16:
+ result = int64(v)
+ case int32:
+ result = int64(v)
+ case int64:
+ result = v
+ case uint:
+ result = int64(v)
+ case uint8:
+ result = int64(v)
+ case uint16:
+ result = int64(v)
+ case uint32:
+ result = int64(v)
+ case uint64:
+ result = int64(v)
+ case float32:
+ result = int64(v)
+ case float64:
+ result = int64(v)
+ case string:
+ // 兼容字符串类型的值
+ if t, err := strconv.ParseInt(v, 10, 32); err == nil {
+ result = t
}
}
- if result, ok := value.(int32); ok {
- if result != 0 {
- return int64(result)
- }
- }
-
- if result, ok := value.(int); ok {
- if result != 0 {
- return int64(result)
- }
- }
-
- // 兼容字符串类型的值
- if str, ok := value.(string); ok {
- if result, err := strconv.ParseInt(str, 10, 64); err == nil {
- if result != 0 {
- return result
- }
- }
+ if result != 0 {
+ return int64(result)
}
}
diff --git a/internal/repository/certificate.go b/internal/repository/certificate.go
index 13d2c094..95bfd713 100644
--- a/internal/repository/certificate.go
+++ b/internal/repository/certificate.go
@@ -101,7 +101,7 @@ func (r *CertificateRepository) Save(ctx context.Context, certificate *domain.Ce
record.Set("serialNumber", certificate.SerialNumber)
record.Set("certificate", certificate.Certificate)
record.Set("privateKey", certificate.PrivateKey)
- record.Set("issuer", certificate.Issuer)
+ record.Set("issuerOrg", certificate.IssuerOrg)
record.Set("issuerCertificate", certificate.IssuerCertificate)
record.Set("keyAlgorithm", string(certificate.KeyAlgorithm))
record.Set("effectAt", certificate.EffectAt)
@@ -162,7 +162,7 @@ func (r *CertificateRepository) castRecordToModel(record *core.Record) (*domain.
SerialNumber: record.GetString("serialNumber"),
Certificate: record.GetString("certificate"),
PrivateKey: record.GetString("privateKey"),
- Issuer: record.GetString("issuer"),
+ IssuerOrg: record.GetString("issuerOrg"),
IssuerCertificate: record.GetString("issuerCertificate"),
KeyAlgorithm: domain.CertificateKeyAlgorithmType(record.GetString("keyAlgorithm")),
EffectAt: record.GetDateTime("effectAt").Time(),
diff --git a/internal/workflow/node-processor/apply_node.go b/internal/workflow/node-processor/apply_node.go
index 97b7575d..ff8c573d 100644
--- a/internal/workflow/node-processor/apply_node.go
+++ b/internal/workflow/node-processor/apply_node.go
@@ -66,14 +66,14 @@ func (n *applyNode) Process(ctx context.Context) error {
}
// 解析证书并生成实体
- certX509, err := certutil.ParseCertificateFromPEM(applyResult.CertificateFullChain)
+ certX509, err := certutil.ParseCertificateFromPEM(applyResult.FullChainCertificate)
if err != nil {
n.logger.Warn("failed to parse certificate, may be the CA responded error")
return err
}
certificate := &domain.Certificate{
Source: domain.CertificateSourceTypeWorkflow,
- Certificate: applyResult.CertificateFullChain,
+ Certificate: applyResult.FullChainCertificate,
PrivateKey: applyResult.PrivateKey,
IssuerCertificate: applyResult.IssuerCertificate,
ACMEAccountUrl: applyResult.ACMEAccountUrl,
diff --git a/migrations/1747389600_upgrade.go b/migrations/1747389600_upgrade.go
new file mode 100644
index 00000000..a145679a
--- /dev/null
+++ b/migrations/1747389600_upgrade.go
@@ -0,0 +1,73 @@
+package migrations
+
+import (
+ "github.com/pocketbase/pocketbase/core"
+ m "github.com/pocketbase/pocketbase/migrations"
+)
+
+func init() {
+ m.Register(func(app core.App) error {
+ // update collection `certificate`
+ {
+ collection, err := app.FindCollectionByNameOrId("4szxr9x43tpj6np")
+ if err != nil {
+ return err
+ }
+
+ if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{
+ "autogeneratePattern": "",
+ "hidden": false,
+ "id": "text2910474005",
+ "max": 0,
+ "min": 0,
+ "name": "issuerOrg",
+ "pattern": "",
+ "presentable": false,
+ "primaryKey": false,
+ "required": false,
+ "system": false,
+ "type": "text"
+ }`)); err != nil {
+ return err
+ }
+
+ if err := app.Save(collection); err != nil {
+ return err
+ }
+ }
+
+ // migrate data
+ {
+ accesses, err := app.FindAllRecords("access")
+ if err != nil {
+ return err
+ }
+
+ for _, access := range accesses {
+ changed := false
+
+ if access.GetString("provider") == "1panel" {
+ config := make(map[string]any)
+ if err := access.UnmarshalJSONField("config", &config); err != nil {
+ return err
+ }
+
+ config["apiVersion"] = "v1"
+ access.Set("config", config)
+ changed = true
+ }
+
+ if changed {
+ err = app.Save(access)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+
+ return nil
+ }, func(app core.App) error {
+ return nil
+ })
+}
diff --git a/ui/public/imgs/providers/acmeca.svg b/ui/public/imgs/providers/acmeca.svg
new file mode 100644
index 00000000..260530c9
--- /dev/null
+++ b/ui/public/imgs/providers/acmeca.svg
@@ -0,0 +1 @@
+
diff --git a/ui/public/imgs/providers/baotawaf.svg b/ui/public/imgs/providers/baotawaf.svg
new file mode 100644
index 00000000..34ab8ec8
--- /dev/null
+++ b/ui/public/imgs/providers/baotawaf.svg
@@ -0,0 +1 @@
+
diff --git a/ui/public/imgs/providers/flexcdn.png b/ui/public/imgs/providers/flexcdn.png
new file mode 100644
index 00000000..00805598
Binary files /dev/null and b/ui/public/imgs/providers/flexcdn.png differ
diff --git a/ui/public/imgs/providers/lecdn.svg b/ui/public/imgs/providers/lecdn.svg
new file mode 100644
index 00000000..f9c18fa7
--- /dev/null
+++ b/ui/public/imgs/providers/lecdn.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/public/imgs/providers/ratpanel.png b/ui/public/imgs/providers/ratpanel.png
new file mode 100644
index 00000000..f89808dd
Binary files /dev/null and b/ui/public/imgs/providers/ratpanel.png differ
diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx
index 1b618cbc..fdf4f93f 100644
--- a/ui/src/components/access/AccessForm.tsx
+++ b/ui/src/components/access/AccessForm.tsx
@@ -12,6 +12,7 @@ import { ACCESS_PROVIDERS, ACCESS_USAGES, type AccessProvider } from "@/domain/p
import { useAntdForm, useAntdFormName } from "@/hooks";
import AccessForm1PanelConfig from "./AccessForm1PanelConfig";
+import AccessFormACMECAConfig from "./AccessFormACMECAConfig";
import AccessFormACMEHttpReqConfig from "./AccessFormACMEHttpReqConfig";
import AccessFormAliyunConfig from "./AccessFormAliyunConfig";
import AccessFormAWSConfig from "./AccessFormAWSConfig";
@@ -19,6 +20,7 @@ import AccessFormAzureConfig from "./AccessFormAzureConfig";
import AccessFormBaiduCloudConfig from "./AccessFormBaiduCloudConfig";
import AccessFormBaishanConfig from "./AccessFormBaishanConfig";
import AccessFormBaotaPanelConfig from "./AccessFormBaotaPanelConfig";
+import AccessFormBaotaWAFConfig from "./AccessFormBaotaWAFConfig";
import AccessFormBunnyConfig from "./AccessFormBunnyConfig";
import AccessFormBytePlusConfig from "./AccessFormBytePlusConfig";
import AccessFormCacheFlyConfig from "./AccessFormCacheFlyConfig";
@@ -33,6 +35,7 @@ import AccessFormDogeCloudConfig from "./AccessFormDogeCloudConfig";
import AccessFormDynv6Config from "./AccessFormDynv6Config";
import AccessFormEdgioConfig from "./AccessFormEdgioConfig";
import AccessFormEmailConfig from "./AccessFormEmailConfig";
+import AccessFormFlexCDNConfig from "./AccessFormFlexCDNConfig";
import AccessFormGcoreConfig from "./AccessFormGcoreConfig";
import AccessFormGnameConfig from "./AccessFormGnameConfig";
import AccessFormGoDaddyConfig from "./AccessFormGoDaddyConfig";
@@ -42,6 +45,7 @@ import AccessFormHuaweiCloudConfig from "./AccessFormHuaweiCloudConfig";
import AccessFormJDCloudConfig from "./AccessFormJDCloudConfig";
import AccessFormKubernetesConfig from "./AccessFormKubernetesConfig";
import AccessFormLarkBotConfig from "./AccessFormLarkBotConfig";
+import AccessFormLeCDNConfig from "./AccessFormLeCDNConfig";
import AccessFormMattermostConfig from "./AccessFormMattermostConfig";
import AccessFormNamecheapConfig from "./AccessFormNamecheapConfig";
import AccessFormNameDotComConfig from "./AccessFormNameDotComConfig";
@@ -54,6 +58,7 @@ import AccessFormPowerDNSConfig from "./AccessFormPowerDNSConfig";
import AccessFormProxmoxVEConfig from "./AccessFormProxmoxVEConfig";
import AccessFormQiniuConfig from "./AccessFormQiniuConfig";
import AccessFormRainYunConfig from "./AccessFormRainYunConfig";
+import AccessFormRatPanelConfig from "./AccessFormRatPanelConfig";
import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig";
import AccessFormSSHConfig from "./AccessFormSSHConfig";
import AccessFormSSLComConfig from "./AccessFormSSLComConfig";
@@ -176,6 +181,8 @@ const AccessForm = forwardRef(({ className,
switch (fieldProvider) {
case ACCESS_PROVIDERS["1PANEL"]:
return ;
+ case ACCESS_PROVIDERS.ACMECA:
+ return ;
case ACCESS_PROVIDERS.ACMEHTTPREQ:
return ;
case ACCESS_PROVIDERS.ALIYUN:
@@ -190,6 +197,8 @@ const AccessForm = forwardRef(({ className,
return ;
case ACCESS_PROVIDERS.BAOTAPANEL:
return ;
+ case ACCESS_PROVIDERS.BAOTAWAF:
+ return ;
case ACCESS_PROVIDERS.BUNNY:
return ;
case ACCESS_PROVIDERS.BYTEPLUS:
@@ -214,6 +223,12 @@ const AccessForm = forwardRef(({ className,
return ;
case ACCESS_PROVIDERS.DYNV6:
return ;
+ case ACCESS_PROVIDERS.EDGIO:
+ return ;
+ case ACCESS_PROVIDERS.EMAIL:
+ return ;
+ case ACCESS_PROVIDERS.FLEXCDN:
+ return ;
case ACCESS_PROVIDERS.GCORE:
return ;
case ACCESS_PROVIDERS.GNAME:
@@ -224,10 +239,6 @@ const AccessForm = forwardRef(({ className,
return ;
case ACCESS_PROVIDERS.GOOGLETRUSTSERVICES:
return ;
- case ACCESS_PROVIDERS.EDGIO:
- return ;
- case ACCESS_PROVIDERS.EMAIL:
- return ;
case ACCESS_PROVIDERS.HUAWEICLOUD:
return ;
case ACCESS_PROVIDERS.JDCLOUD:
@@ -236,6 +247,8 @@ const AccessForm = forwardRef(({ className,
return ;
case ACCESS_PROVIDERS.LARKBOT:
return ;
+ case ACCESS_PROVIDERS.LECDN:
+ return ;
case ACCESS_PROVIDERS.MATTERMOST:
return ;
case ACCESS_PROVIDERS.NAMECHEAP:
@@ -260,6 +273,8 @@ const AccessForm = forwardRef(({ className,
return ;
case ACCESS_PROVIDERS.RAINYUN:
return ;
+ case ACCESS_PROVIDERS.RATPANEL:
+ return ;
case ACCESS_PROVIDERS.SAFELINE:
return ;
case ACCESS_PROVIDERS.SSH:
diff --git a/ui/src/components/access/AccessForm1PanelConfig.tsx b/ui/src/components/access/AccessForm1PanelConfig.tsx
index c0762bbd..29481f15 100644
--- a/ui/src/components/access/AccessForm1PanelConfig.tsx
+++ b/ui/src/components/access/AccessForm1PanelConfig.tsx
@@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next";
-import { Form, type FormInstance, Input, Switch } from "antd";
+import { Form, type FormInstance, Input, Select, Switch } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
@@ -18,6 +18,7 @@ export type AccessForm1PanelConfigProps = {
const initFormModel = (): AccessForm1PanelConfigFieldValues => {
return {
apiUrl: "http://:20410/",
+ apiVersion: "v1",
apiKey: "",
};
};
@@ -27,6 +28,7 @@ const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialVal
const formSchema = z.object({
apiUrl: z.string().url(t("common.errmsg.url_invalid")),
+ apiVersion: z.string().nonempty(t("access.form.1panel_api_version.placeholder")),
apiKey: z
.string()
.min(1, t("access.form.1panel_api_key.placeholder"))
@@ -53,6 +55,10 @@ const AccessForm1PanelConfig = ({ form: formInst, formName, disabled, initialVal
+
+
+
;
+
+export type AccessFormACMECAConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: AccessFormACMECAConfigFieldValues;
+ onValuesChange?: (values: AccessFormACMECAConfigFieldValues) => void;
+};
+
+const initFormModel = (): AccessFormACMECAConfigFieldValues => {
+ return {
+ endpoint: "https://example.com/acme/directory",
+ };
+};
+
+const AccessFormACMECAConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormACMECAConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ endpoint: z.string().url(t("common.errmsg.url_invalid")),
+ eabKid: z.string().trim().nullish(),
+ eabHmacKey: z.string().trim().nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+ );
+};
+
+export default AccessFormACMECAConfig;
diff --git a/ui/src/components/access/AccessFormACMEHttpReqConfig.tsx b/ui/src/components/access/AccessFormACMEHttpReqConfig.tsx
index 03cf163a..57cbc22d 100644
--- a/ui/src/components/access/AccessFormACMEHttpReqConfig.tsx
+++ b/ui/src/components/access/AccessFormACMEHttpReqConfig.tsx
@@ -84,7 +84,7 @@ const AccessFormACMEHttpReqConfig = ({ form: formInst, formName, disabled, initi
rules={[formRule]}
tooltip={}
>
-
+
}
>
-
+
);
diff --git a/ui/src/components/access/AccessFormBaotaPanelConfig.tsx b/ui/src/components/access/AccessFormBaotaPanelConfig.tsx
index d03c0f1b..dd355b5e 100644
--- a/ui/src/components/access/AccessFormBaotaPanelConfig.tsx
+++ b/ui/src/components/access/AccessFormBaotaPanelConfig.tsx
@@ -27,11 +27,7 @@ const AccessFormBaotaPanelConfig = ({ form: formInst, formName, disabled, initia
const formSchema = z.object({
apiUrl: z.string().url(t("common.errmsg.url_invalid")),
- apiKey: z
- .string()
- .min(1, t("access.form.baotapanel_api_key.placeholder"))
- .max(64, t("common.errmsg.string_max", { max: 64 }))
- .trim(),
+ apiKey: z.string().nonempty(t("access.form.baotapanel_api_key.placeholder")).trim(),
allowInsecureConnections: z.boolean().nullish(),
});
const formRule = createSchemaFieldRule(formSchema);
diff --git a/ui/src/components/access/AccessFormBaotaWAFConfig.tsx b/ui/src/components/access/AccessFormBaotaWAFConfig.tsx
new file mode 100644
index 00000000..e87ed596
--- /dev/null
+++ b/ui/src/components/access/AccessFormBaotaWAFConfig.tsx
@@ -0,0 +1,71 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, Switch } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { type AccessConfigForBaotaWAF } from "@/domain/access";
+
+type AccessFormBaotaWAFConfigFieldValues = Nullish;
+
+export type AccessFormBaotaWAFConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: AccessFormBaotaWAFConfigFieldValues;
+ onValuesChange?: (values: AccessFormBaotaWAFConfigFieldValues) => void;
+};
+
+const initFormModel = (): AccessFormBaotaWAFConfigFieldValues => {
+ return {
+ apiUrl: "http://:8379/",
+ apiKey: "",
+ };
+};
+
+const AccessFormBaotaWAFConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormBaotaWAFConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ apiUrl: z.string().url(t("common.errmsg.url_invalid")),
+ apiKey: z.string().nonempty(t("access.form.baotawaf_api_key.placeholder")).trim(),
+ allowInsecureConnections: z.boolean().nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+ );
+};
+
+export default AccessFormBaotaWAFConfig;
diff --git a/ui/src/components/access/AccessFormCloudflareConfig.tsx b/ui/src/components/access/AccessFormCloudflareConfig.tsx
index a06d753d..79b33e3a 100644
--- a/ui/src/components/access/AccessFormCloudflareConfig.tsx
+++ b/ui/src/components/access/AccessFormCloudflareConfig.tsx
@@ -66,7 +66,7 @@ const AccessFormCloudflareConfig = ({ form: formInst, formName, disabled, initia
rules={[formRule]}
tooltip={}
>
-
+
);
diff --git a/ui/src/components/access/AccessFormFlexCDNConfig.tsx b/ui/src/components/access/AccessFormFlexCDNConfig.tsx
new file mode 100644
index 00000000..6ca020bf
--- /dev/null
+++ b/ui/src/components/access/AccessFormFlexCDNConfig.tsx
@@ -0,0 +1,90 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, Radio, Switch } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { type AccessConfigForFlexCDN } from "@/domain/access";
+
+type AccessFormFlexCDNConfigFieldValues = Nullish;
+
+export type AccessFormFlexCDNConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: AccessFormFlexCDNConfigFieldValues;
+ onValuesChange?: (values: AccessFormFlexCDNConfigFieldValues) => void;
+};
+
+const initFormModel = (): AccessFormFlexCDNConfigFieldValues => {
+ return {
+ apiUrl: "http://:8000/",
+ apiRole: "user",
+ accessKeyId: "",
+ accessKey: "",
+ };
+};
+
+const AccessFormFlexCDNConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormFlexCDNConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ apiUrl: z.string().url(t("common.errmsg.url_invalid")),
+ role: z.union([z.literal("user"), z.literal("admin")], {
+ message: t("access.form.flexcdn_api_role.placeholder"),
+ }),
+ accessKeyId: z.string().nonempty(t("access.form.flexcdn_access_key_id.placeholder")).trim(),
+ accessKey: z.string().nonempty(t("access.form.flexcdn_access_key.placeholder")).trim(),
+ allowInsecureConnections: z.boolean().nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+
+
+
+
+
+ ({ label: t(`access.form.flexcdn_api_role.option.${s}.label`), value: s }))} />
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+ );
+};
+
+export default AccessFormFlexCDNConfig;
diff --git a/ui/src/components/access/AccessFormGoEdgeConfig.tsx b/ui/src/components/access/AccessFormGoEdgeConfig.tsx
index ced9b09a..9c03f2be 100644
--- a/ui/src/components/access/AccessFormGoEdgeConfig.tsx
+++ b/ui/src/components/access/AccessFormGoEdgeConfig.tsx
@@ -32,16 +32,8 @@ const AccessFormGoEdgeConfig = ({ form: formInst, formName, disabled, initialVal
role: z.union([z.literal("user"), z.literal("admin")], {
message: t("access.form.goedge_api_role.placeholder"),
}),
- accessKeyId: z
- .string()
- .min(1, t("access.form.goedge_access_key_id.placeholder"))
- .max(64, t("common.errmsg.string_max", { max: 64 }))
- .trim(),
- accessKey: z
- .string()
- .min(1, t("access.form.goedge_access_key.placeholder"))
- .max(64, t("common.errmsg.string_max", { max: 64 }))
- .trim(),
+ accessKeyId: z.string().nonempty(t("access.form.goedge_access_key_id.placeholder")).trim(),
+ accessKey: z.string().nonempty(t("access.form.goedge_access_key.placeholder")).trim(),
allowInsecureConnections: z.boolean().nullish(),
});
const formRule = createSchemaFieldRule(formSchema);
diff --git a/ui/src/components/access/AccessFormLeCDNConfig.tsx b/ui/src/components/access/AccessFormLeCDNConfig.tsx
new file mode 100644
index 00000000..4af5a639
--- /dev/null
+++ b/ui/src/components/access/AccessFormLeCDNConfig.tsx
@@ -0,0 +1,85 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, Radio, Select, Switch } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { type AccessConfigForLeCDN } from "@/domain/access";
+
+type AccessFormLeCDNConfigFieldValues = Nullish;
+
+export type AccessFormLeCDNConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: AccessFormLeCDNConfigFieldValues;
+ onValuesChange?: (values: AccessFormLeCDNConfigFieldValues) => void;
+};
+
+const initFormModel = (): AccessFormLeCDNConfigFieldValues => {
+ return {
+ apiUrl: "http://:5090/",
+ apiVersion: "v3",
+ apiRole: "user",
+ username: "",
+ password: "",
+ };
+};
+
+const AccessFormLeCDNConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormLeCDNConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ apiUrl: z.string().url(t("common.errmsg.url_invalid")),
+ role: z.union([z.literal("client"), z.literal("master")], {
+ message: t("access.form.lecdn_api_role.placeholder"),
+ }),
+ username: z.string().nonempty(t("access.form.lecdn_username.placeholder")).trim(),
+ password: z.string().nonempty(t("access.form.lecdn_password.placeholder")).trim(),
+ allowInsecureConnections: z.boolean().nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ ({ label: t(`access.form.lecdn_api_role.option.${s}.label`), value: s }))} />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default AccessFormLeCDNConfig;
diff --git a/ui/src/components/access/AccessFormProxmoxVEConfig.tsx b/ui/src/components/access/AccessFormProxmoxVEConfig.tsx
index afdc02de..d0a66745 100644
--- a/ui/src/components/access/AccessFormProxmoxVEConfig.tsx
+++ b/ui/src/components/access/AccessFormProxmoxVEConfig.tsx
@@ -65,7 +65,7 @@ const AccessFormProxmoxVEConfig = ({ form: formInst, formName, disabled, initial
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/access/AccessFormRatPanelConfig.tsx b/ui/src/components/access/AccessFormRatPanelConfig.tsx
new file mode 100644
index 00000000..ca3d2182
--- /dev/null
+++ b/ui/src/components/access/AccessFormRatPanelConfig.tsx
@@ -0,0 +1,82 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, Switch } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { type AccessConfigForRatPanel } from "@/domain/access";
+
+type AccessFormRatPanelConfigFieldValues = Nullish;
+
+export type AccessFormRatPanelConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: AccessFormRatPanelConfigFieldValues;
+ onValuesChange?: (values: AccessFormRatPanelConfigFieldValues) => void;
+};
+
+const initFormModel = (): AccessFormRatPanelConfigFieldValues => {
+ return {
+ apiUrl: "http://:8888/",
+ accessTokenId: 1,
+ accessToken: "",
+ };
+};
+
+const AccessFormRatPanelConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormRatPanelConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ apiUrl: z.string().url(t("common.errmsg.url_invalid")),
+ accessTokenId: z.preprocess((v) => Number(v), z.number().positive(t("access.form.ratpanel_access_token_id.placeholder"))),
+ accessToken: z.string().nonempty(t("access.form.ratpanel_access_token.placeholder")).trim(),
+ allowInsecureConnections: z.boolean().nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+
+
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+ );
+};
+
+export default AccessFormRatPanelConfig;
diff --git a/ui/src/components/access/AccessFormUCloudConfig.tsx b/ui/src/components/access/AccessFormUCloudConfig.tsx
index 495d21b9..fd623925 100644
--- a/ui/src/components/access/AccessFormUCloudConfig.tsx
+++ b/ui/src/components/access/AccessFormUCloudConfig.tsx
@@ -81,7 +81,7 @@ const AccessFormUCloudConfig = ({ form: formInst, formName, disabled, initialVal
rules={[formRule]}
tooltip={}
>
-
+
);
diff --git a/ui/src/components/access/AccessFormVercelConfig.tsx b/ui/src/components/access/AccessFormVercelConfig.tsx
index b1ed7b6f..4483a9f9 100644
--- a/ui/src/components/access/AccessFormVercelConfig.tsx
+++ b/ui/src/components/access/AccessFormVercelConfig.tsx
@@ -66,7 +66,7 @@ const AccessFormVercelConfig = ({ form: formInst, formName, disabled, initialVal
rules={[formRule]}
tooltip={}
>
-
+
);
diff --git a/ui/src/components/access/AccessFormWebhookConfig.tsx b/ui/src/components/access/AccessFormWebhookConfig.tsx
index 0dea7f7c..6e6ec87a 100644
--- a/ui/src/components/access/AccessFormWebhookConfig.tsx
+++ b/ui/src/components/access/AccessFormWebhookConfig.tsx
@@ -67,7 +67,6 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa
}
return true;
}, t("access.form.webhook_headers.errmsg.invalid")),
- allowInsecureConnections: z.boolean().nullish(),
defaultDataForDeployment: z
.string()
.nullish()
@@ -96,11 +95,12 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa
return false;
}
}, t("access.form.webhook_default_data.errmsg.json_invalid")),
+ allowInsecureConnections: z.boolean().nullish(),
});
const formRule = createSchemaFieldRule(formSchema);
- const handleWebhookHeadersBlur = (e: React.FocusEvent) => {
- let value = e.target.value;
+ const handleWebhookHeadersBlur = () => {
+ let value = formInst.getFieldValue("headers");
value = value.trim();
value = value.replace(/(?}
>
-
+
diff --git a/ui/src/components/certificate/CertificateDetail.tsx b/ui/src/components/certificate/CertificateDetail.tsx
index 1023bf16..2fc0d9d0 100644
--- a/ui/src/components/certificate/CertificateDetail.tsx
+++ b/ui/src/components/certificate/CertificateDetail.tsx
@@ -42,7 +42,7 @@ const CertificateDetail = ({ data, ...props }: CertificateDetailProps) => {
-
+
diff --git a/ui/src/components/provider/DeploymentProviderPicker.tsx b/ui/src/components/provider/DeploymentProviderPicker.tsx
index 0ea5a97c..b1bcd6fe 100644
--- a/ui/src/components/provider/DeploymentProviderPicker.tsx
+++ b/ui/src/components/provider/DeploymentProviderPicker.tsx
@@ -72,8 +72,10 @@ const DeploymentProviderPicker = ({ className, style, autoFocus, filter, placeho
DEPLOYMENT_CATEGORIES.LOADBALANCE,
DEPLOYMENT_CATEGORIES.FIREWALL,
DEPLOYMENT_CATEGORIES.AV,
+ DEPLOYMENT_CATEGORIES.APIGATEWAY,
DEPLOYMENT_CATEGORIES.SERVERLESS,
DEPLOYMENT_CATEGORIES.WEBSITE,
+ DEPLOYMENT_CATEGORIES.SSL,
DEPLOYMENT_CATEGORIES.NAS,
DEPLOYMENT_CATEGORIES.OTHER,
].map((key) => ({
diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx
index 9e4ade18..49ed12ec 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx
@@ -27,6 +27,7 @@ import DeployNodeConfigFormAliyunDCDNConfig from "./DeployNodeConfigFormAliyunDC
import DeployNodeConfigFormAliyunDDoSConfig from "./DeployNodeConfigFormAliyunDDoSConfig";
import DeployNodeConfigFormAliyunESAConfig from "./DeployNodeConfigFormAliyunESAConfig";
import DeployNodeConfigFormAliyunFCConfig from "./DeployNodeConfigFormAliyunFCConfig";
+import DeployNodeConfigFormAliyunGAConfig from "./DeployNodeConfigFormAliyunGAConfig";
import DeployNodeConfigFormAliyunLiveConfig from "./DeployNodeConfigFormAliyunLiveConfig";
import DeployNodeConfigFormAliyunNLBConfig from "./DeployNodeConfigFormAliyunNLBConfig";
import DeployNodeConfigFormAliyunOSSConfig from "./DeployNodeConfigFormAliyunOSSConfig";
@@ -41,11 +42,13 @@ import DeployNodeConfigFormBaiduCloudCDNConfig from "./DeployNodeConfigFormBaidu
import DeployNodeConfigFormBaishanCDNConfig from "./DeployNodeConfigFormBaishanCDNConfig";
import DeployNodeConfigFormBaotaPanelConsoleConfig from "./DeployNodeConfigFormBaotaPanelConsoleConfig";
import DeployNodeConfigFormBaotaPanelSiteConfig from "./DeployNodeConfigFormBaotaPanelSiteConfig";
+import DeployNodeConfigFormBaotaWAFSiteConfig from "./DeployNodeConfigFormBaotaWAFSiteConfig";
import DeployNodeConfigFormBunnyCDNConfig from "./DeployNodeConfigFormBunnyCDNConfig.tsx";
import DeployNodeConfigFormBytePlusCDNConfig from "./DeployNodeConfigFormBytePlusCDNConfig";
import DeployNodeConfigFormCdnflyConfig from "./DeployNodeConfigFormCdnflyConfig";
import DeployNodeConfigFormDogeCloudCDNConfig from "./DeployNodeConfigFormDogeCloudCDNConfig";
import DeployNodeConfigFormEdgioApplicationsConfig from "./DeployNodeConfigFormEdgioApplicationsConfig";
+import DeployNodeConfigFormFlexCDNConfig from "./DeployNodeConfigFormFlexCDNConfig";
import DeployNodeConfigFormGcoreCDNConfig from "./DeployNodeConfigFormGcoreCDNConfig";
import DeployNodeConfigFormGoEdgeConfig from "./DeployNodeConfigFormGoEdgeConfig";
import DeployNodeConfigFormHuaweiCloudCDNConfig from "./DeployNodeConfigFormHuaweiCloudCDNConfig";
@@ -56,6 +59,7 @@ import DeployNodeConfigFormJDCloudCDNConfig from "./DeployNodeConfigFormJDCloudC
import DeployNodeConfigFormJDCloudLiveConfig from "./DeployNodeConfigFormJDCloudLiveConfig";
import DeployNodeConfigFormJDCloudVODConfig from "./DeployNodeConfigFormJDCloudVODConfig";
import DeployNodeConfigFormKubernetesSecretConfig from "./DeployNodeConfigFormKubernetesSecretConfig";
+import DeployNodeConfigFormLeCDNConfig from "./DeployNodeConfigFormLeCDNConfig";
import DeployNodeConfigFormLocalConfig from "./DeployNodeConfigFormLocalConfig";
import DeployNodeConfigFormNetlifySiteConfig from "./DeployNodeConfigFormNetlifySiteConfig";
import DeployNodeConfigFormProxmoxVEConfig from "./DeployNodeConfigFormProxmoxVEConfig";
@@ -63,6 +67,7 @@ import DeployNodeConfigFormQiniuCDNConfig from "./DeployNodeConfigFormQiniuCDNCo
import DeployNodeConfigFormQiniuKodoConfig from "./DeployNodeConfigFormQiniuKodoConfig";
import DeployNodeConfigFormQiniuPiliConfig from "./DeployNodeConfigFormQiniuPiliConfig";
import DeployNodeConfigFormRainYunRCDNConfig from "./DeployNodeConfigFormRainYunRCDNConfig";
+import DeployNodeConfigFormRatPanelSiteConfig from "./DeployNodeConfigFormRatPanelSiteConfig";
import DeployNodeConfigFormSafeLineConfig from "./DeployNodeConfigFormSafeLineConfig";
import DeployNodeConfigFormSSHConfig from "./DeployNodeConfigFormSSHConfig.tsx";
import DeployNodeConfigFormTencentCloudCDNConfig from "./DeployNodeConfigFormTencentCloudCDNConfig.tsx";
@@ -87,7 +92,9 @@ import DeployNodeConfigFormVolcEngineDCDNConfig from "./DeployNodeConfigFormVolc
import DeployNodeConfigFormVolcEngineImageXConfig from "./DeployNodeConfigFormVolcEngineImageXConfig.tsx";
import DeployNodeConfigFormVolcEngineLiveConfig from "./DeployNodeConfigFormVolcEngineLiveConfig.tsx";
import DeployNodeConfigFormVolcEngineTOSConfig from "./DeployNodeConfigFormVolcEngineTOSConfig.tsx";
+import DeployNodeConfigFormWangsuCDNConfig from "./DeployNodeConfigFormWangsuCDNConfig.tsx";
import DeployNodeConfigFormWangsuCDNProConfig from "./DeployNodeConfigFormWangsuCDNProConfig.tsx";
+import DeployNodeConfigFormWangsuCertificateConfig from "./DeployNodeConfigFormWangsuCertificateConfig.tsx";
import DeployNodeConfigFormWebhookConfig from "./DeployNodeConfigFormWebhookConfig.tsx";
type DeployNodeConfigFormFieldValues = Partial;
@@ -201,6 +208,8 @@ const DeployNodeConfigForm = forwardRef;
case DEPLOYMENT_PROVIDERS.ALIYUN_FC:
return ;
+ case DEPLOYMENT_PROVIDERS.ALIYUN_GA:
+ return ;
case DEPLOYMENT_PROVIDERS.ALIYUN_LIVE:
return ;
case DEPLOYMENT_PROVIDERS.ALIYUN_NLB:
@@ -229,6 +238,8 @@ const DeployNodeConfigForm = forwardRef;
case DEPLOYMENT_PROVIDERS.BAOTAPANEL_SITE:
return ;
+ case DEPLOYMENT_PROVIDERS.BAOTAWAF_SITE:
+ return ;
case DEPLOYMENT_PROVIDERS.BUNNY_CDN:
return ;
case DEPLOYMENT_PROVIDERS.BYTEPLUS_CDN:
@@ -239,6 +250,8 @@ const DeployNodeConfigForm = forwardRef;
case DEPLOYMENT_PROVIDERS.EDGIO_APPLICATIONS:
return ;
+ case DEPLOYMENT_PROVIDERS.FLEXCDN:
+ return ;
case DEPLOYMENT_PROVIDERS.GCORE_CDN:
return ;
case DEPLOYMENT_PROVIDERS.GOEDGE:
@@ -259,6 +272,8 @@ const DeployNodeConfigForm = forwardRef;
case DEPLOYMENT_PROVIDERS.KUBERNETES_SECRET:
return ;
+ case DEPLOYMENT_PROVIDERS.LECDN:
+ return ;
case DEPLOYMENT_PROVIDERS.LOCAL:
return ;
case DEPLOYMENT_PROVIDERS.NETLIFY_SITE:
@@ -273,6 +288,8 @@ const DeployNodeConfigForm = forwardRef;
case DEPLOYMENT_PROVIDERS.RAINYUN_RCDN:
return ;
+ case DEPLOYMENT_PROVIDERS.RATPANEL_SITE:
+ return ;
case DEPLOYMENT_PROVIDERS.SAFELINE:
return ;
case DEPLOYMENT_PROVIDERS.SSH:
@@ -321,8 +338,12 @@ const DeployNodeConfigForm = forwardRef;
case DEPLOYMENT_PROVIDERS.VOLCENGINE_TOS:
return ;
+ case DEPLOYMENT_PROVIDERS.WANGSU_CDN:
+ return ;
case DEPLOYMENT_PROVIDERS.WANGSU_CDNPRO:
return ;
+ case DEPLOYMENT_PROVIDERS.WANGSU_CERTIFICATE:
+ return ;
case DEPLOYMENT_PROVIDERS.WEBHOOK:
return ;
}
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAWSACMConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAWSACMConfig.tsx
index f0964493..2e539453 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormAWSACMConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormAWSACMConfig.tsx
@@ -28,7 +28,7 @@ const DeployNodeConfigFormAWSACMConfig = ({ form: formInst, formName, disabled,
.string({ message: t("workflow_node.deploy.form.aws_acm_region.placeholder") })
.nonempty(t("workflow_node.deploy.form.aws_acm_region.placeholder"))
.trim(),
- certificateArn: z.string({ message: t("workflow_node.deploy.form.aws_acm_certificate_arn.placeholder") }).nullish(),
+ certificateArn: z.string().nullish(),
});
const formRule = createSchemaFieldRule(formSchema);
@@ -60,7 +60,7 @@ const DeployNodeConfigFormAWSACMConfig = ({ form: formInst, formName, disabled,
rules={[formRule]}
tooltip={}
>
-
+
);
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx
index 3afcb7a1..bbfca5e6 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx
@@ -132,7 +132,7 @@ const DeployNodeConfigFormAliyunALBConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx
index 2c2e43b6..e666800e 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx
@@ -132,7 +132,7 @@ const DeployNodeConfigFormAliyunCLBConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunGAConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunGAConfig.tsx
new file mode 100644
index 00000000..20dd1ae1
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunGAConfig.tsx
@@ -0,0 +1,118 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+import { validDomainName } from "@/utils/validators";
+
+type DeployNodeConfigFormAliyunGAConfigFieldValues = Nullish<{
+ resourceType: string;
+ acceleratorId?: string;
+ listenerId?: string;
+ domain?: string;
+}>;
+
+export type DeployNodeConfigFormAliyunGAConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormAliyunGAConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormAliyunGAConfigFieldValues) => void;
+};
+
+const RESOURCE_TYPE_ACCELERATOR = "accelerator" as const;
+const RESOURCE_TYPE_LISTENER = "listener" as const;
+
+const initFormModel = (): DeployNodeConfigFormAliyunGAConfigFieldValues => {
+ return {};
+};
+
+const DeployNodeConfigFormAliyunGAConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormAliyunGAConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.union([z.literal(RESOURCE_TYPE_ACCELERATOR), z.literal(RESOURCE_TYPE_LISTENER)], {
+ message: t("workflow_node.deploy.form.aliyun_ga_resource_type.placeholder"),
+ }),
+ acceleratorId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim(),
+ listenerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldResourceType !== RESOURCE_TYPE_LISTENER || !!v?.trim(), t("workflow_node.deploy.form.aliyun_ga_listener_id.placeholder")),
+ domain: z
+ .string()
+ .nullish()
+ .refine((v) => {
+ if (![RESOURCE_TYPE_ACCELERATOR, RESOURCE_TYPE_LISTENER].includes(fieldResourceType)) return true;
+ return !v || validDomainName(v!);
+ }, t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+
+
+
+
+ }
+ >
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+
+ );
+};
+
+export default DeployNodeConfigFormAliyunGAConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx
index 5f81cf71..a46c7327 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunWAFConfig.tsx
@@ -102,7 +102,7 @@ const DeployNodeConfigFormAliyunWAFConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
);
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAzureKeyVaultConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAzureKeyVaultConfig.tsx
index 2a54bb99..bd2347df 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormAzureKeyVaultConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormAzureKeyVaultConfig.tsx
@@ -35,7 +35,7 @@ const DeployNodeConfigFormAzureKeyVaultConfig = ({
.nonempty(t("workflow_node.deploy.form.azure_keyvault_name.placeholder"))
.trim(),
certificateName: z
- .string({ message: t("workflow_node.deploy.form.azure_keyvault_certificate_name.placeholder") })
+ .string()
.nullish()
.refine((v) => {
if (!v) return true;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx
index 7bd40b82..875d254b 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx
@@ -135,7 +135,7 @@ const DeployNodeConfigFormBaiduCloudAppBLBConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx
index 20bb22f1..99c0b059 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx
@@ -135,7 +135,7 @@ const DeployNodeConfigFormBaiduCloudBLBConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx
index ad05b6a8..7d32bef5 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx
@@ -73,7 +73,7 @@ const DeployNodeConfigFormBaishanCDNConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
);
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaotaWAFSiteConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaotaWAFSiteConfig.tsx
new file mode 100644
index 00000000..6f992fb8
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaotaWAFSiteConfig.tsx
@@ -0,0 +1,78 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, InputNumber } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validPortNumber } from "@/utils/validators";
+
+type DeployNodeConfigFormBaotaWAFSiteConfigFieldValues = Nullish<{
+ siteName: string;
+ sitePort: number;
+}>;
+
+export type DeployNodeConfigFormBaotaWAFSiteConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormBaotaWAFSiteConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormBaotaWAFSiteConfigFieldValues) => void;
+};
+
+const initFormModel = (): DeployNodeConfigFormBaotaWAFSiteConfigFieldValues => {
+ return {
+ siteName: "",
+ sitePort: 443,
+ };
+};
+
+const DeployNodeConfigFormBaotaWAFSiteConfig = ({
+ form: formInst,
+ formName,
+ disabled,
+ initialValues,
+ onValuesChange,
+}: DeployNodeConfigFormBaotaWAFSiteConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ siteName: z.string().nonempty(t("workflow_node.deploy.form.baotawaf_site_name.placeholder")).trim(),
+ sitePort: z.preprocess(
+ (v) => Number(v),
+ z
+ .number()
+ .int(t("workflow_node.deploy.form.baotawaf_site_port.placeholder"))
+ .refine((v) => validPortNumber(v), t("common.errmsg.port_invalid"))
+ ),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+ }
+ >
+
+
+
+
+
+
+
+ );
+};
+
+export default DeployNodeConfigFormBaotaWAFSiteConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormCdnflyConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormCdnflyConfig.tsx
index 45662e75..4d6ae25c 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormCdnflyConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormCdnflyConfig.tsx
@@ -79,13 +79,23 @@ const DeployNodeConfigFormCdnflyConfig = ({ form: formInst, formName, disabled,
-
+ }
+ >
-
+ }
+ >
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormFlexCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormFlexCDNConfig.tsx
new file mode 100644
index 00000000..e24652be
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormFlexCDNConfig.tsx
@@ -0,0 +1,84 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+
+type DeployNodeConfigFormFlexCDNConfigFieldValues = Nullish<{
+ resourceType: string;
+ certificateId?: string | number;
+}>;
+
+export type DeployNodeConfigFormFlexCDNConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormFlexCDNConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormFlexCDNConfigFieldValues) => void;
+};
+
+const RESOURCE_TYPE_CERTIFICATE = "certificate" as const;
+
+const initFormModel = (): DeployNodeConfigFormFlexCDNConfigFieldValues => {
+ return {
+ resourceType: RESOURCE_TYPE_CERTIFICATE,
+ certificateId: "",
+ };
+};
+
+const DeployNodeConfigFormFlexCDNConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormFlexCDNConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.literal(RESOURCE_TYPE_CERTIFICATE, {
+ message: t("workflow_node.deploy.form.flexcdn_resource_type.placeholder"),
+ }),
+ certificateId: z
+ .union([z.string(), z.number().int()])
+ .nullish()
+ .refine((v) => {
+ if (fieldResourceType !== RESOURCE_TYPE_CERTIFICATE) return true;
+ return /^\d+$/.test(v + "") && +v! > 0;
+ }, t("workflow_node.deploy.form.flexcdn_certificate_id.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+
+
+
+
+
+ }
+ >
+
+
+
+
+ );
+};
+
+export default DeployNodeConfigFormFlexCDNConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormGcoreCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormGcoreCDNConfig.tsx
index 4d548949..f21a4bb9 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormGcoreCDNConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormGcoreCDNConfig.tsx
@@ -67,7 +67,7 @@ const DeployNodeConfigFormGcoreCDNConfig = ({ form: formInst, formName, disabled
rules={[formRule]}
tooltip={}
>
-
+
);
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormGoEdgeConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormGoEdgeConfig.tsx
index 89dffb5f..5e0f7f85 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormGoEdgeConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormGoEdgeConfig.tsx
@@ -68,7 +68,12 @@ const DeployNodeConfigFormGoEdgeConfig = ({ form: formInst, formName, disabled,
-
+ }
+ >
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx
index f54477ce..22c5bf08 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx
@@ -132,7 +132,7 @@ const DeployNodeConfigFormJDCloudALBConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormLeCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormLeCDNConfig.tsx
new file mode 100644
index 00000000..0636cedf
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormLeCDNConfig.tsx
@@ -0,0 +1,103 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+
+type DeployNodeConfigFormLeCDNConfigFieldValues = Nullish<{
+ resourceType: string;
+ certificateId?: string | number;
+ clientId?: string | number;
+}>;
+
+export type DeployNodeConfigFormLeCDNConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormLeCDNConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormLeCDNConfigFieldValues) => void;
+};
+
+const RESOURCE_TYPE_CERTIFICATE = "certificate" as const;
+
+const initFormModel = (): DeployNodeConfigFormLeCDNConfigFieldValues => {
+ return {
+ resourceType: RESOURCE_TYPE_CERTIFICATE,
+ certificateId: "",
+ clientId: "",
+ };
+};
+
+const DeployNodeConfigFormLeCDNConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormLeCDNConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.literal(RESOURCE_TYPE_CERTIFICATE, {
+ message: t("workflow_node.deploy.form.lecdn_resource_type.placeholder"),
+ }),
+ certificateId: z
+ .union([z.string(), z.number().int()])
+ .nullish()
+ .refine((v) => {
+ if (fieldResourceType !== RESOURCE_TYPE_CERTIFICATE) return true;
+ return /^\d+$/.test(v + "") && +v! > 0;
+ }, t("workflow_node.deploy.form.lecdn_certificate_id.placeholder")),
+ clientId: z
+ .union([z.string(), z.number().int()])
+ .nullish()
+ .refine((v) => {
+ if (fieldResourceType !== RESOURCE_TYPE_CERTIFICATE) return true;
+ if (v == null || v === "") return true;
+ return /^\d+$/.test(v + "") && +v! > 0;
+ }, t("workflow_node.deploy.form.lecdn_client_id.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+
+
+
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+
+ );
+};
+
+export default DeployNodeConfigFormLeCDNConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx
index 75853eb7..282503e5 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormLocalConfig.tsx
@@ -351,7 +351,7 @@ const DeployNodeConfigFormLocalConfig = ({ form: formInst, formName, disabled, i
rules={[formRule]}
tooltip={}
>
-
+
}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormRatPanelSiteConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormRatPanelSiteConfig.tsx
new file mode 100644
index 00000000..03f86913
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormRatPanelSiteConfig.tsx
@@ -0,0 +1,63 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+type DeployNodeConfigFormRatPanelSiteConfigFieldValues = Nullish<{
+ siteName: string;
+}>;
+
+export type DeployNodeConfigFormRatPanelSiteConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormRatPanelSiteConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormRatPanelSiteConfigFieldValues) => void;
+};
+
+const initFormModel = (): DeployNodeConfigFormRatPanelSiteConfigFieldValues => {
+ return {
+ siteName: "",
+ };
+};
+
+const DeployNodeConfigFormRatPanelSiteConfig = ({
+ form: formInst,
+ formName,
+ disabled,
+ initialValues,
+ onValuesChange,
+}: DeployNodeConfigFormRatPanelSiteConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ siteName: z.string().nonempty(t("workflow_node.deploy.form.ratpanel_site_name.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+ }
+ >
+
+
+
+ );
+};
+
+export default DeployNodeConfigFormRatPanelSiteConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx
index e99a2431..49110ce9 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx
@@ -363,7 +363,7 @@ const DeployNodeConfigFormSSHConfig = ({ form: formInst, formName, disabled, ini
rules={[formRule]}
tooltip={}
>
-
+
}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormSafeLineConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormSafeLineConfig.tsx
index 2da3ef16..c5905e14 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormSafeLineConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormSafeLineConfig.tsx
@@ -68,7 +68,12 @@ const DeployNodeConfigFormSafeLineConfig = ({ form: formInst, formName, disabled
-
+ }
+ >
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx
index 2e7dc127..760c6fac 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx
@@ -144,7 +144,7 @@ const DeployNodeConfigFormTencentCloudCLBConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormVolcEngineALBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormVolcEngineALBConfig.tsx
index 348f4d8d..650323ab 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormVolcEngineALBConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormVolcEngineALBConfig.tsx
@@ -140,7 +140,7 @@ const DeployNodeConfigFormVolcEngineALBConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCDNConfig.tsx
new file mode 100644
index 00000000..57d0d381
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCDNConfig.tsx
@@ -0,0 +1,146 @@
+import { memo } from "react";
+import { useTranslation } from "react-i18next";
+import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons";
+import { Button, Form, type FormInstance, Input, Space } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import ModalForm from "@/components/ModalForm";
+import MultipleInput from "@/components/MultipleInput";
+import { useAntdForm } from "@/hooks";
+import { validDomainName } from "@/utils/validators";
+
+type DeployNodeConfigFormWangsuCDNConfigFieldValues = Nullish<{
+ domains: string;
+}>;
+
+export type DeployNodeConfigFormWangsuCDNConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormWangsuCDNConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormWangsuCDNConfigFieldValues) => void;
+};
+
+const MULTIPLE_INPUT_DELIMITER = ";";
+
+const initFormModel = (): DeployNodeConfigFormWangsuCDNConfigFieldValues => {
+ return {
+ domains: "",
+ };
+};
+
+const DeployNodeConfigFormWangsuCDNConfig = ({
+ form: formInst,
+ formName,
+ disabled,
+ initialValues,
+ onValuesChange,
+}: DeployNodeConfigFormWangsuCDNConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domains: z
+ .string()
+ .nullish()
+ .refine((v) => {
+ if (!v) return false;
+ return String(v)
+ .split(MULTIPLE_INPUT_DELIMITER)
+ .every((e) => validDomainName(e));
+ }, t("workflow_node.deploy.form.wangsu_cdn_domains.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const fieldDomains = Form.useWatch("domains", formInst);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+ }
+ >
+
+
+ {
+ formInst.setFieldValue("domains", e.target.value);
+ }}
+ onClear={() => {
+ formInst.setFieldValue("domains", "");
+ }}
+ />
+
+
+
+
+ }
+ onChange={(value) => {
+ formInst.setFieldValue("domains", value);
+ }}
+ />
+
+
+
+ );
+};
+
+const SiteNamesModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domains: z.array(z.string()).refine((v) => {
+ return v.every((e) => validDomainName(e));
+ }, t("workflow_node.deploy.form.wangsu_cdn_domains.errmsg.invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const { form: formInst, formProps } = useAntdForm({
+ name: "workflowNodeDeployConfigFormWangsuCDNNamesModalInput",
+ initialValues: { domains: value?.split(MULTIPLE_INPUT_DELIMITER) },
+ onSubmit: (values) => {
+ onChange?.(
+ values.domains
+ .map((e) => e.trim())
+ .filter((e) => !!e)
+ .join(MULTIPLE_INPUT_DELIMITER)
+ );
+ },
+ });
+
+ return (
+
+
+
+
+
+ );
+});
+
+export default DeployNodeConfigFormWangsuCDNConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCDNProConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCDNProConfig.tsx
index 90bdb064..e89e1e8d 100644
--- a/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCDNProConfig.tsx
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCDNProConfig.tsx
@@ -5,37 +5,37 @@ import { z } from "zod";
import { validDomainName } from "@/utils/validators";
-type DeployNodeConfigFormBaishanCDNConfigFieldValues = Nullish<{
+type DeployNodeConfigFormWangsuCDNProConfigFieldValues = Nullish<{
environment: string;
domain: string;
certificateId?: string;
webhookId?: string;
}>;
-export type DeployNodeConfigFormBaishanCDNConfigProps = {
+export type DeployNodeConfigFormWangsuCDNProConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
- initialValues?: DeployNodeConfigFormBaishanCDNConfigFieldValues;
- onValuesChange?: (values: DeployNodeConfigFormBaishanCDNConfigFieldValues) => void;
+ initialValues?: DeployNodeConfigFormWangsuCDNProConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormWangsuCDNProConfigFieldValues) => void;
};
const ENVIRONMENT_PRODUCTION = "production" as const;
const ENVIRONMENT_STAGING = "stating" as const;
-const initFormModel = (): DeployNodeConfigFormBaishanCDNConfigFieldValues => {
+const initFormModel = (): DeployNodeConfigFormWangsuCDNProConfigFieldValues => {
return {
environment: ENVIRONMENT_PRODUCTION,
};
};
-const DeployNodeConfigFormBaishanCDNConfig = ({
+const DeployNodeConfigFormWangsuCDNProConfig = ({
form: formInst,
formName,
disabled,
initialValues,
onValuesChange,
-}: DeployNodeConfigFormBaishanCDNConfigProps) => {
+}: DeployNodeConfigFormWangsuCDNProConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@@ -89,7 +89,7 @@ const DeployNodeConfigFormBaishanCDNConfig = ({
rules={[formRule]}
tooltip={}
>
-
+
}
>
-
+
);
};
-export default DeployNodeConfigFormBaishanCDNConfig;
+export default DeployNodeConfigFormWangsuCDNProConfig;
diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCertificateConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCertificateConfig.tsx
new file mode 100644
index 00000000..739e4b28
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeConfigFormWangsuCertificateConfig.tsx
@@ -0,0 +1,61 @@
+import { useTranslation } from "react-i18next";
+import { Form, type FormInstance, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+type DeployNodeConfigFormWangsuCertificateConfigFieldValues = Nullish<{
+ certificateId?: string;
+}>;
+
+export type DeployNodeConfigFormWangsuCertificateConfigProps = {
+ form: FormInstance;
+ formName: string;
+ disabled?: boolean;
+ initialValues?: DeployNodeConfigFormWangsuCertificateConfigFieldValues;
+ onValuesChange?: (values: DeployNodeConfigFormWangsuCertificateConfigFieldValues) => void;
+};
+
+const initFormModel = (): DeployNodeConfigFormWangsuCertificateConfigFieldValues => {
+ return {};
+};
+
+const DeployNodeConfigFormWangsuCertificateConfig = ({
+ form: formInst,
+ formName,
+ disabled,
+ initialValues,
+ onValuesChange,
+}: DeployNodeConfigFormWangsuCertificateConfigProps) => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ certificateId: z.string().nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ const handleFormChange = (_: unknown, values: z.infer) => {
+ onValuesChange?.(values);
+ };
+
+ return (
+ }
+ >
+
+
+
+ );
+};
+
+export default DeployNodeConfigFormWangsuCertificateConfig;
diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts
index 9e2d7c35..f60f39c8 100644
--- a/ui/src/domain/access.ts
+++ b/ui/src/domain/access.ts
@@ -7,6 +7,7 @@ export interface AccessModel extends BaseModel {
*/ Record &
(
| AccessConfigFor1Panel
+ | AccessConfigForACMECA
| AccessConfigForACMEHttpReq
| AccessConfigForAliyun
| AccessConfigForAWS
@@ -14,6 +15,7 @@ export interface AccessModel extends BaseModel {
| AccessConfigForBaiduCloud
| AccessConfigForBaishan
| AccessConfigForBaotaPanel
+ | AccessConfigForBaotaWAF
| AccessConfigForBunny
| AccessConfigForBytePlus
| AccessConfigForCacheFly
@@ -28,6 +30,7 @@ export interface AccessModel extends BaseModel {
| AccessConfigForDynv6
| AccessConfigForEdgio
| AccessConfigForEmail
+ | AccessConfigForFlexCDN
| AccessConfigForGcore
| AccessConfigForGname
| AccessConfigForGoDaddy
@@ -37,6 +40,7 @@ export interface AccessModel extends BaseModel {
| AccessConfigForJDCloud
| AccessConfigForKubernetes
| AccessConfigForLarkBot
+ | AccessConfigForLeCDN
| AccessConfigForMattermost
| AccessConfigForNamecheap
| AccessConfigForNameDotCom
@@ -48,6 +52,7 @@ export interface AccessModel extends BaseModel {
| AccessConfigForProxmoxVE
| AccessConfigForQiniu
| AccessConfigForRainYun
+ | AccessConfigForRatPanel
| AccessConfigForSafeLine
| AccessConfigForSSH
| AccessConfigForSSLCom
@@ -69,10 +74,17 @@ export interface AccessModel extends BaseModel {
// #region AccessConfig
export type AccessConfigFor1Panel = {
apiUrl: string;
+ apiVersion: string;
apiKey: string;
allowInsecureConnections?: boolean;
};
+export type AccessConfigForACMECA = {
+ endpoint: string;
+ eabKid?: string;
+ eabHmacKey?: string;
+};
+
export type AccessConfigForACMEHttpReq = {
endpoint: string;
mode?: string;
@@ -112,6 +124,12 @@ export type AccessConfigForBaotaPanel = {
allowInsecureConnections?: boolean;
};
+export type AccessConfigForBaotaWAF = {
+ apiUrl: string;
+ apiKey: string;
+ allowInsecureConnections?: boolean;
+};
+
export type AccessConfigForBunny = {
apiKey: string;
};
@@ -185,6 +203,14 @@ export type AccessConfigForEmail = {
defaultReceiverAddress?: string;
};
+export type AccessConfigForFlexCDN = {
+ apiUrl: string;
+ apiRole: string;
+ accessKeyId: string;
+ accessKey: string;
+ allowInsecureConnections?: boolean;
+};
+
export type AccessConfigForGcore = {
apiToken: string;
};
@@ -230,6 +256,15 @@ export type AccessConfigForLarkBot = {
webhookUrl: string;
};
+export type AccessConfigForLeCDN = {
+ apiUrl: string;
+ apiVersion: string;
+ apiRole: string;
+ username: string;
+ password: string;
+ allowInsecureConnections?: boolean;
+};
+
export type AccessConfigForMattermost = {
serverUrl: string;
username: string;
@@ -292,6 +327,13 @@ export type AccessConfigForRainYun = {
apiKey: string;
};
+export type AccessConfigForRatPanel = {
+ apiUrl: string;
+ accessTokenId: number;
+ accessToken: string;
+ allowInsecureConnections?: boolean;
+};
+
export type AccessConfigForSafeLine = {
apiUrl: string;
apiToken: string;
diff --git a/ui/src/domain/certificate.ts b/ui/src/domain/certificate.ts
index 563d2476..c4bc8710 100644
--- a/ui/src/domain/certificate.ts
+++ b/ui/src/domain/certificate.ts
@@ -6,7 +6,7 @@ export interface CertificateModel extends BaseModel {
serialNumber: string;
certificate: string;
privateKey: string;
- issuer: string;
+ issuerOrg: string;
keyAlgorithm: string;
effectAt: ISO8601String;
expireAt: ISO8601String;
diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts
index 878814f5..15542455 100644
--- a/ui/src/domain/provider.ts
+++ b/ui/src/domain/provider.ts
@@ -5,6 +5,7 @@
*/
export const ACCESS_PROVIDERS = Object.freeze({
["1PANEL"]: "1panel",
+ ACMECA: "acmeca",
ACMEHTTPREQ: "acmehttpreq",
ALIYUN: "aliyun",
AWS: "aws",
@@ -12,6 +13,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
BAIDUCLOUD: "baiducloud",
BAISHAN: "baishan",
BAOTAPANEL: "baotapanel",
+ BAOTAWAF: "baotawaf",
BUNNY: "bunny",
BYTEPLUS: "byteplus",
BUYPASS: "buypass",
@@ -27,6 +29,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
DYNV6: "dynv6",
EDGIO: "edgio",
EMAIL: "email",
+ FLEXCDN: "flexcdn",
GCORE: "gcore",
GNAME: "gname",
GODADDY: "godaddy",
@@ -36,6 +39,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
JDCLOUD: "jdcloud",
KUBERNETES: "k8s",
LARKBOT: "larkbot",
+ LECDN: "lecdn",
LETSENCRYPT: "letsencrypt",
LETSENCRYPTSTAGING: "letsencryptstaging",
LOCAL: "local",
@@ -51,6 +55,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
PROXMOXVE: "proxmoxve",
QINIU: "qiniu",
RAINYUN: "rainyun",
+ RATPANEL: "ratpanel",
SAFELINE: "safeline",
SSH: "ssh",
SSLCOM: "sslcom",
@@ -120,10 +125,14 @@ export const accessProvidersMap: Map = new
[CA_PROVIDERS.GOOGLETRUSTSERVICES],
[CA_PROVIDERS.SSLCOM],
[CA_PROVIDERS.ZEROSSL],
+ [CA_PROVIDERS.ACMECA],
].map(([type, builtin]) => [
type,
{
@@ -345,6 +357,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
ALIYUN_DDOS: `${ACCESS_PROVIDERS.ALIYUN}-ddospro`,
ALIYUN_ESA: `${ACCESS_PROVIDERS.ALIYUN}-esa`,
ALIYUN_FC: `${ACCESS_PROVIDERS.ALIYUN}-fc`,
+ ALIYUN_GA: `${ACCESS_PROVIDERS.ALIYUN}-ga`,
ALIYUN_LIVE: `${ACCESS_PROVIDERS.ALIYUN}-live`,
ALIYUN_NLB: `${ACCESS_PROVIDERS.ALIYUN}-nlb`,
ALIYUN_OSS: `${ACCESS_PROVIDERS.ALIYUN}-oss`,
@@ -360,12 +373,15 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
BAISHAN_CDN: `${ACCESS_PROVIDERS.BAISHAN}-cdn`,
BAOTAPANEL_CONSOLE: `${ACCESS_PROVIDERS.BAOTAPANEL}-console`,
BAOTAPANEL_SITE: `${ACCESS_PROVIDERS.BAOTAPANEL}-site`,
+ BAOTAWAF_CONSOLE: `${ACCESS_PROVIDERS.BAOTAWAF}-console`,
+ BAOTAWAF_SITE: `${ACCESS_PROVIDERS.BAOTAWAF}-site`,
BUNNY_CDN: `${ACCESS_PROVIDERS.BUNNY}-cdn`,
BYTEPLUS_CDN: `${ACCESS_PROVIDERS.BYTEPLUS}-cdn`,
CACHEFLY: `${ACCESS_PROVIDERS.CACHEFLY}`,
CDNFLY: `${ACCESS_PROVIDERS.CDNFLY}`,
DOGECLOUD_CDN: `${ACCESS_PROVIDERS.DOGECLOUD}-cdn`,
EDGIO_APPLICATIONS: `${ACCESS_PROVIDERS.EDGIO}-applications`,
+ FLEXCDN: `${ACCESS_PROVIDERS.FLEXCDN}`,
GCORE_CDN: `${ACCESS_PROVIDERS.GCORE}-cdn`,
GOEDGE: `${ACCESS_PROVIDERS.GOEDGE}`,
HUAWEICLOUD_CDN: `${ACCESS_PROVIDERS.HUAWEICLOUD}-cdn`,
@@ -377,6 +393,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
JDCLOUD_LIVE: `${ACCESS_PROVIDERS.JDCLOUD}-live`,
JDCLOUD_VOD: `${ACCESS_PROVIDERS.JDCLOUD}-vod`,
KUBERNETES_SECRET: `${ACCESS_PROVIDERS.KUBERNETES}-secret`,
+ LECDN: `${ACCESS_PROVIDERS.LECDN}`,
LOCAL: `${ACCESS_PROVIDERS.LOCAL}`,
NETLIFY_SITE: `${ACCESS_PROVIDERS.NETLIFY}-site`,
PROXMOXVE: `${ACCESS_PROVIDERS.PROXMOXVE}`,
@@ -384,6 +401,8 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
QINIU_KODO: `${ACCESS_PROVIDERS.QINIU}-kodo`,
QINIU_PILI: `${ACCESS_PROVIDERS.QINIU}-pili`,
RAINYUN_RCDN: `${ACCESS_PROVIDERS.RAINYUN}-rcdn`,
+ RATPANEL_CONSOLE: `${ACCESS_PROVIDERS.RATPANEL}-console`,
+ RATPANEL_SITE: `${ACCESS_PROVIDERS.RATPANEL}-site`,
SAFELINE: `${ACCESS_PROVIDERS.SAFELINE}`,
SSH: `${ACCESS_PROVIDERS.SSH}`,
TENCENTCLOUD_CDN: `${ACCESS_PROVIDERS.TENCENTCLOUD}-cdn`,
@@ -409,7 +428,9 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
VOLCENGINE_IMAGEX: `${ACCESS_PROVIDERS.VOLCENGINE}-imagex`,
VOLCENGINE_LIVE: `${ACCESS_PROVIDERS.VOLCENGINE}-live`,
VOLCENGINE_TOS: `${ACCESS_PROVIDERS.VOLCENGINE}-tos`,
+ WANGSU_CDN: `${ACCESS_PROVIDERS.WANGSU}-cdn`,
WANGSU_CDNPRO: `${ACCESS_PROVIDERS.WANGSU}-cdnpro`,
+ WANGSU_CERTIFICATE: `${ACCESS_PROVIDERS.WANGSU}-certificate`,
WEBHOOK: `${ACCESS_PROVIDERS.WEBHOOK}`,
} as const);
@@ -422,8 +443,10 @@ export const DEPLOYMENT_CATEGORIES = Object.freeze({
LOADBALANCE: "loadbalance",
FIREWALL: "firewall",
AV: "av",
+ APIGATEWAY: "apigw",
SERVERLESS: "serverless",
WEBSITE: "website",
+ SSL: "ssl",
NAS: "nas",
OTHER: "other",
} as const);
@@ -461,9 +484,10 @@ export const deploymentProvidersMap: Map [
diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json
index 32ae2885..589b2572 100644
--- a/ui/src/i18n/locales/en/nls.access.json
+++ b/ui/src/i18n/locales/en/nls.access.json
@@ -36,12 +36,21 @@
"access.form.notification_channel.placeholder": "Please select a notification channel",
"access.form.1panel_api_url.label": "1Panel URL",
"access.form.1panel_api_url.placeholder": "Please enter 1Panel URL",
+ "access.form.1panel_api_version.label": "1Panel version",
+ "access.form.1panel_api_version.placeholder": "Please select 1Panel version",
"access.form.1panel_api_key.label": "1Panel API key",
"access.form.1panel_api_key.placeholder": "Please enter 1Panel API key",
"access.form.1panel_api_key.tooltip": "For more information, see https://docs.1panel.pro/dev_manual/api_manual/",
"access.form.1panel_allow_insecure_conns.label": "Insecure SSL/TLS connections",
"access.form.1panel_allow_insecure_conns.switch.on": "Allow",
"access.form.1panel_allow_insecure_conns.switch.off": "Disallow",
+ "access.form.acmeca_endpoint.label": "Endpoint",
+ "access.form.acmeca_endpoint.placeholder": "Please enter endpoint",
+ "access.form.acmeca_endpoint.tooltip": "For more information, see https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.1",
+ "access.form.acmeca_eab_kid.label": "ACME EAB KID (Optional)",
+ "access.form.acmeca_eab_kid.placeholder": "Please enter ACME EAB KID",
+ "access.form.acmeca_eab_hmac_key.label": "ACME EAB HMAC key (Optional)",
+ "access.form.acmeca_eab_hmac_key.placeholder": "Please enter ACME EAB HMAC key",
"access.form.acmehttpreq_endpoint.label": "Endpoint",
"access.form.acmehttpreq_endpoint.placeholder": "Please enter endpoint",
"access.form.acmehttpreq_endpoint.tooltip": "For more information, see https://go-acme.github.io/lego/dns/httpreq/",
@@ -103,6 +112,14 @@
"access.form.baotapanel_allow_insecure_conns.label": "Insecure SSL/TLS connections",
"access.form.baotapanel_allow_insecure_conns.switch.on": "Allow",
"access.form.baotapanel_allow_insecure_conns.switch.off": "Disallow",
+ "access.form.baotawaf_api_url.label": "aaWAF URL",
+ "access.form.baotawaf_api_url.placeholder": "Please enter aaWAF URL",
+ "access.form.baotawaf_api_key.label": "aaWAF API key",
+ "access.form.baotawaf_api_key.placeholder": "Please enter aaWAF API key",
+ "access.form.baotawaf_api_key.tooltip": "For more information, see https://github.com/aaPanel/aaWAF/blob/main/API.md",
+ "access.form.baotawaf_allow_insecure_conns.label": "Insecure SSL/TLS connections",
+ "access.form.baotawaf_allow_insecure_conns.switch.on": "Allow",
+ "access.form.baotawaf_allow_insecure_conns.switch.off": "Disallow",
"access.form.byteplus_access_key.label": "BytePlus AccessKey",
"access.form.byteplus_access_key.placeholder": "Please enter BytePlus AccessKey",
"access.form.byteplus_access_key.tooltip": "For more information, see https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys",
@@ -112,8 +129,8 @@
"access.form.cachefly_api_token.label": "CacheFly API token",
"access.form.cachefly_api_token.placeholder": "Please enter CacheFly API token",
"access.form.cachefly_api_token.tooltip": "For more information, see https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228",
- "access.form.cdnfly_api_url.label": "Cdnfly API URL",
- "access.form.cdnfly_api_url.placeholder": "Please enter Cdnfly API URL",
+ "access.form.cdnfly_api_url.label": "Cdnfly URL",
+ "access.form.cdnfly_api_url.placeholder": "Please enter Cdnfly URL",
"access.form.cdnfly_api_key.label": "Cdnfly user API key",
"access.form.cdnfly_api_key.placeholder": "Please enter Cdnfly user API key",
"access.form.cdnfly_api_key.tooltip": "For more information, see https://doc.cdnfly.cn/shiyongjieshao.html",
@@ -184,6 +201,21 @@
"access.form.email_default_sender_address.placeholder": "Please enter default sender email address",
"access.form.email_default_receiver_address.label": "Default receiver email address (Optional)",
"access.form.email_default_receiver_address.placeholder": "Please enter default receiver email address",
+ "access.form.flexcdn_api_url.label": "FlexCDN URL",
+ "access.form.flexcdn_api_url.placeholder": "Please enter FlexCDN URL",
+ "access.form.flexcdn_api_role.label": "FlexCDN user role",
+ "access.form.flexcdn_api_role.placeholder": "Please select FlexCDN user role",
+ "access.form.flexcdn_api_role.option.user.label": "Platform user",
+ "access.form.flexcdn_api_role.option.admin.label": "Administrator user",
+ "access.form.flexcdn_access_key_id.label": "FlexCDN AccessKeyId",
+ "access.form.flexcdn_access_key_id.placeholder": "Please enter FlexCDN AccessKeyId",
+ "access.form.flexcdn_access_key_id.tooltip": "For more information, see https://flexcdn.cn/docs/api/auth",
+ "access.form.flexcdn_access_key.label": "FlexCDN AccessKey",
+ "access.form.flexcdn_access_key.placeholder": "Please enter FlexCDN AccessKey",
+ "access.form.flexcdn_access_key.tooltip": "For more information, see https://flexcdn.cn/docs/api/auth",
+ "access.form.flexcdn_allow_insecure_conns.label": "Insecure SSL/TLS connections",
+ "access.form.flexcdn_allow_insecure_conns.switch.on": "Allow",
+ "access.form.flexcdn_allow_insecure_conns.switch.off": "Disallow",
"access.form.gcore_api_token.label": "Gcore API token",
"access.form.gcore_api_token.placeholder": "Please enter Gcore API token",
"access.form.gcore_api_token.tooltip": "For more information, see https://api.gcore.com/docs/iam#section/Authentication",
@@ -199,8 +231,8 @@
"access.form.godaddy_api_secret.label": "GoDaddy API secret",
"access.form.godaddy_api_secret.placeholder": "Please enter GoDaddy API secret",
"access.form.godaddy_api_secret.tooltip": "For more information, see https://developer.godaddy.com/",
- "access.form.goedge_api_url.label": "GoEdge API URL",
- "access.form.goedge_api_url.placeholder": "Please enter GoEdge API URL",
+ "access.form.goedge_api_url.label": "GoEdge URL",
+ "access.form.goedge_api_url.placeholder": "Please enter GoEdge URL",
"access.form.goedge_api_role.label": "GoEdge user role",
"access.form.goedge_api_role.placeholder": "Please select GoEdge user role",
"access.form.goedge_api_role.option.user.label": "Platform user",
@@ -238,6 +270,21 @@
"access.form.larkbot_webhook_url.label": "Lark bot Webhook URL",
"access.form.larkbot_webhook_url.placeholder": "Please enter Lark bot Webhook URL",
"access.form.larkbot_webhook_url.tooltip": "For more information, see https://www.feishu.cn/hc/en-US/articles/807992406756",
+ "access.form.lecdn_api_url.label": "LeCDN URL",
+ "access.form.lecdn_api_url.placeholder": "Please enter LeCDN URL",
+ "access.form.lecdn_api_version.label": "LeCDN version",
+ "access.form.lecdn_api_version.placeholder": "Please select LeCDN version",
+ "access.form.lecdn_api_role.label": "LeCDN user role",
+ "access.form.lecdn_api_role.placeholder": "Please select LeCDN user role",
+ "access.form.lecdn_api_role.option.client.label": "Client",
+ "access.form.lecdn_api_role.option.master.label": "Master",
+ "access.form.lecdn_username.label": "LeCDN username",
+ "access.form.lecdn_username.placeholder": "Please enter LeCDN username",
+ "access.form.lecdn_password.label": "LeCDN password",
+ "access.form.lecdn_password.placeholder": "Please enter GoEdge password",
+ "access.form.lecdn_allow_insecure_conns.label": "Insecure SSL/TLS connections",
+ "access.form.lecdn_allow_insecure_conns.switch.on": "Allow",
+ "access.form.lecdn_allow_insecure_conns.switch.off": "Disallow",
"access.form.mattermost_server_url.label": "Mattermost server URL",
"access.form.mattermost_server_url.placeholder": "Please enter Mattermost server URL",
"access.form.mattermost_username.label": "Mattermost username",
@@ -262,8 +309,8 @@
"access.form.namesilo_api_key.label": "NameSilo API key",
"access.form.namesilo_api_key.placeholder": "Please enter NameSilo API key",
"access.form.namesilo_api_key.tooltip": "For more information, see https://www.namesilo.com/support/v2/articles/account-options/api-manager",
- "access.form.netlify_api_token.label": "netlify API token",
- "access.form.netlify_api_token.placeholder": "Please enter netlify API token",
+ "access.form.netlify_api_token.label": "Netlify API token",
+ "access.form.netlify_api_token.placeholder": "Please enter Netlify API token",
"access.form.netlify_api_token.tooltip": "For more information, see https://docs.netlify.com/api/get-started/#authentication",
"access.form.netcup_customer_number.label": "netcup customer number",
"access.form.netcup_customer_number.placeholder": "Please enter netcup customer number",
@@ -283,8 +330,8 @@
"access.form.porkbun_secret_api_key.label": "Porkbun secret API key",
"access.form.porkbun_secret_api_key.placeholder": "Please enter Porkbun secret API key",
"access.form.porkbun_secret_api_key.tooltip": "For more information, see https://porkbun.com/api/json/v3/documentation",
- "access.form.powerdns_api_url.label": "PowerDNS API URL",
- "access.form.powerdns_api_url.placeholder": "Please enter PowerDNS API URL",
+ "access.form.powerdns_api_url.label": "PowerDNS URL",
+ "access.form.powerdns_api_url.placeholder": "Please enter PowerDNS URL",
"access.form.powerdns_api_key.label": "PowerDNS API key",
"access.form.powerdns_api_key.placeholder": "Please enter PowerDNS API key",
"access.form.powerdns_api_key.tooltip": "For more information, see https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api",
@@ -311,6 +358,17 @@
"access.form.rainyun_api_key.label": "Rain Yun API key",
"access.form.rainyun_api_key.placeholder": "Please enter Rain Yun API key",
"access.form.rainyun_api_key.tooltip": "For more information, see https://app.rainyun.com/account/settings/api-key",
+ "access.form.ratpanel_api_url.label": "RatPanel URL",
+ "access.form.ratpanel_api_url.placeholder": "Please enter RatPanel URL",
+ "access.form.ratpanel_access_token_id.label": "RatPanel access token ID",
+ "access.form.ratpanel_access_token_id.placeholder": "Please enter RatPanel access token ID",
+ "access.form.ratpanel_access_token_id.tooltip": "For more information, see https://ratpanel.github.io/advanced/api.html",
+ "access.form.ratpanel_access_token.label": "RatPanel access token",
+ "access.form.ratpanel_access_token.placeholder": "Please enter RatPanel access token",
+ "access.form.ratpanel_access_token.tooltip": "For more information, see https://ratpanel.github.io/advanced/api.html",
+ "access.form.ratpanel_allow_insecure_conns.label": "Insecure SSL/TLS connections",
+ "access.form.ratpanel_allow_insecure_conns.switch.on": "Allow",
+ "access.form.ratpanel_allow_insecure_conns.switch.off": "Disallow",
"access.form.safeline_api_url.label": "SafeLine URL",
"access.form.safeline_api_url.placeholder": "Please enter SafeLine URL",
"access.form.safeline_api_token.label": "SafeLine API token",
diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json
index 82eab327..a3bbfecc 100644
--- a/ui/src/i18n/locales/en/nls.provider.json
+++ b/ui/src/i18n/locales/en/nls.provider.json
@@ -2,7 +2,8 @@
"provider.1panel": "1Panel",
"provider.1panel.console": "1Panel - Console",
"provider.1panel.site": "1Panel - Website",
- "provider.acmehttpreq": "Http Request (ACME Proxy)",
+ "provider.acmeca": "ACME Custom CA Endpoint",
+ "provider.acmehttpreq": "ACME Custom HTTP Endpoint",
"provider.aliyun": "Alibaba Cloud",
"provider.aliyun.alb": "Alibaba Cloud - ALB (Application Load Balancer)",
"provider.aliyun.apigw": "Alibaba Cloud - API Gateway",
@@ -15,6 +16,7 @@
"provider.aliyun.dns": "Alibaba Cloud - DNS (Domain Name Service)",
"provider.aliyun.esa": "Alibaba Cloud - ESA (Edge Security Acceleration)",
"provider.aliyun.fc": "Alibaba Cloud - FC (Function Compute)",
+ "provider.aliyun.ga": "Alibaba Cloud - GA (Global Accelerator)",
"provider.aliyun.live": "Alibaba Cloud - ApsaraVideo Live",
"provider.aliyun.nlb": "Alibaba Cloud - NLB (Network Load Balancer)",
"provider.aliyun.oss": "Alibaba Cloud - OSS (Object Storage Service)",
@@ -40,6 +42,9 @@
"provider.baotapanel": "aaPanel (aka BaoTaPanel)",
"provider.baotapanel.console": "aaPanel (aka BaoTaPanel) - Console",
"provider.baotapanel.site": "aaPanel (aka BaoTaPanel) - Website",
+ "provider.baotawaf": "aaWAF (aka BaotaWAF)",
+ "provider.baotawaf.console": "aaWAF (aka BaotaWAF) - Console",
+ "provider.baotawaf.site": "aaWAF (aka BaotaWAF) - Website",
"provider.bunny": "Bunny",
"provider.bunny.cdn": "Bunny - CDN (Content Delivery Network)",
"provider.byteplus": "BytePlus",
@@ -62,6 +67,7 @@
"provider.edgio.applications": "Edgio - Applications",
"provider.email": "Email",
"provider.fastly": "Fastly",
+ "provider.flexcdn": "FlexCDN",
"provider.gcore": "Gcore",
"provider.gcore.cdn": "Gcore - CDN (Content Delivery Network)",
"provider.gname": "GNAME",
@@ -83,6 +89,7 @@
"provider.kubernetes": "Kubernetes",
"provider.kubernetes.secret": "Kubernetes - Secret",
"provider.larkbot": "Lark Bot",
+ "provider.lecdn": "LeCDN",
"provider.letsencrypt": "Let's Encrypt",
"provider.letsencryptstaging": "Let's Encrypt Staging Environment",
"provider.local": "Local deployment",
@@ -91,8 +98,8 @@
"provider.namedotcom": "Name.com",
"provider.namesilo": "NameSilo",
"provider.netcup": "netcup",
- "provider.netlify": "netlify",
- "provider.netlify.site": "netlify - Site",
+ "provider.netlify": "Netlify",
+ "provider.netlify.site": "Netlify - Site",
"provider.ns1": "NS1 (IBM NS1 Connect)",
"provider.porkbun": "Porkbun",
"provider.powerdns": "PowerDNS",
@@ -103,6 +110,9 @@
"provider.qiniu.pili": "Qiniu - Pili",
"provider.rainyun": "Rain Yun",
"provider.rainyun.rcdn": "Rain Yun - RCDN (Rain Content Delivery Network)",
+ "provider.ratpanel": "RatPanel",
+ "provider.ratpanel.console": "RatPanel - Console",
+ "provider.ratpanel.site": "RatPanel - Website",
"provider.safeline": "SafeLine",
"provider.ssh": "SSH deployment",
"provider.sslcom": "SSL.com",
@@ -138,7 +148,9 @@
"provider.volcengine.live": "Volcengine - Live",
"provider.volcengine.tos": "Volcengine - TOS (Tinder Object Storage)",
"provider.wangsu": "Wangsu Cloud",
- "provider.wangsu.cdnpro": "Wangsu Cloud - CDN Pro",
+ "provider.wangsu.cdn": "Wangsu Cloud - CDN (Content Delivery Network)",
+ "provider.wangsu.cdnpro": "Wangsu Cloud - CDN Pro (CDN 360)",
+ "provider.wangsu.certificate_upload": "Wangsu Cloud - Upload to Certificate Management",
"provider.webhook": "Webhook",
"provider.wecombot": "WeCom Bot",
"provider.westcn": "West.cn",
@@ -150,8 +162,10 @@
"provider.category.loadbalance": "Loadbalance",
"provider.category.firewall": "Firewall",
"provider.category.av": "Audio/Video",
+ "provider.category.apigw": "API Gateway",
"provider.category.serverless": "Serverless",
"provider.category.website": "Website",
+ "provider.category.ssl": "SSL",
"provider.category.nas": "NAS",
"provider.category.other": "Other",
diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json
index 7b53e6e4..80237287 100644
--- a/ui/src/i18n/locales/en/nls.workflow.nodes.json
+++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json
@@ -213,6 +213,19 @@
"workflow_node.deploy.form.aliyun_fc_domain.label": "Alibaba Cloud FC domain",
"workflow_node.deploy.form.aliyun_fc_domain.placeholder": "Please enter Alibaba Cloud FC domain name",
"workflow_node.deploy.form.aliyun_fc_domain.tooltip": "For more information, see https://fcnext.console.aliyun.com",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.label": "Resource type",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.option.accelerator.label": "GA accelerator",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.option.listener.label": "GA listener",
+ "workflow_node.deploy.form.aliyun_ga_accelerator_id.label": "Alibaba Cloud GA accelerator ID",
+ "workflow_node.deploy.form.aliyun_ga_accelerator_id.placeholder": "Please enter Alibaba Cloud GA accelerator ID",
+ "workflow_node.deploy.form.aliyun_ga_accelerator_id.tooltip": "For more information, https://ga.console.aliyun.com",
+ "workflow_node.deploy.form.aliyun_ga_listener_id.label": "Alibaba Cloud GA listener ID",
+ "workflow_node.deploy.form.aliyun_ga_listener_id.placeholder": "Please enter Alibaba Cloud GA listener ID",
+ "workflow_node.deploy.form.aliyun_ga_listener_id.tooltip": "For more information, https://ga.console.aliyun.com",
+ "workflow_node.deploy.form.aliyun_ga_snidomain.label": "Alibaba Cloud GA SNI domain (Optional)",
+ "workflow_node.deploy.form.aliyun_ga_snidomain.placeholder": "Please enter Alibaba Cloud GA SNI domain name",
+ "workflow_node.deploy.form.aliyun_ga_snidomain.tooltip": "For more information, https://ga.console.aliyun.com",
"workflow_node.deploy.form.aliyun_live_region.label": "Alibaba Cloud Live region",
"workflow_node.deploy.form.aliyun_live_region.placeholder": "Please enter Alibaba Cloud Live region (e.g. cn-hangzhou)",
"workflow_node.deploy.form.aliyun_live_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/live/product-overview/supported-regions",
@@ -325,13 +338,18 @@
"workflow_node.deploy.form.baotapanel_site_type.option.other.label": "Other sites",
"workflow_node.deploy.form.baotapanel_site_name.label": "aaPanel site name",
"workflow_node.deploy.form.baotapanel_site_name.placeholder": "Please enter aaPanel site name",
- "workflow_node.deploy.form.baotapanel_site_name.tooltip": "Usually equal to the website domain name.",
+ "workflow_node.deploy.form.baotapanel_site_name.tooltip": "You can find it on aaPanel WebUI.",
"workflow_node.deploy.form.baotapanel_site_names.label": "aaPanel site names",
"workflow_node.deploy.form.baotapanel_site_names.placeholder": "Please enter aaPanel site names (separated by semicolons)",
"workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid": "Please enter a valid aaPanel site name",
- "workflow_node.deploy.form.baotapanel_site_names.tooltip": "Usually equal to the websites domain name.",
+ "workflow_node.deploy.form.baotapanel_site_names.tooltip": "You can find it on aaPanel WebUI.",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title": "Change aaPanel site names",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder": "Please enter aaPanel site name",
+ "workflow_node.deploy.form.baotawaf_site_name.label": "aaWAF site name",
+ "workflow_node.deploy.form.baotawaf_site_name.placeholder": "Please enter aaWAF site name",
+ "workflow_node.deploy.form.baotawaf_site_name.tooltip": "You can find it on aaWAF WebUI.",
+ "workflow_node.deploy.form.baotawaf_site_port.label": "aaWAF site SSL port",
+ "workflow_node.deploy.form.baotawaf_site_port.placeholder": "Please enter aaWAF SSL port",
"workflow_node.deploy.form.bunny_cdn_pull_zone_id.label": "Bunny CDN pull zone ID",
"workflow_node.deploy.form.bunny_cdn_pull_zone_id.placeholder": "Please enter Bunny CDN pull zone ID",
"workflow_node.deploy.form.bunny_cdn_pull_zone_id.tooltip": "What is this? See https://dash.bunny.net/cdn",
@@ -347,14 +365,22 @@
"workflow_node.deploy.form.cdnfly_resource_type.option.certificate.label": "Certificate",
"workflow_node.deploy.form.cdnfly_site_id.label": "Cdnfly site ID",
"workflow_node.deploy.form.cdnfly_site_id.placeholder": "Please enter Cdnfly site ID",
+ "workflow_node.deploy.form.cdnfly_site_id.tooltip": "You can find it on Cdnfly WebUI.",
"workflow_node.deploy.form.cdnfly_certificate_id.label": "Cdnfly certificate ID",
"workflow_node.deploy.form.cdnfly_certificate_id.placeholder": "Please enter Cdnfly certificate ID",
+ "workflow_node.deploy.form.cdnfly_certificate_id.tooltip": "You can find it on Cdnfly WebUI.",
"workflow_node.deploy.form.dogecloud_cdn_domain.label": "Doge Cloud CDN domain",
"workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "Please enter Doge Cloud CDN domain name",
"workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "For more information, see https://console.dogecloud.com/",
"workflow_node.deploy.form.edgio_applications_environment_id.label": "Edgio Applications environment ID",
"workflow_node.deploy.form.edgio_applications_environment_id.placeholder": "Please enter Edgio Applications environment ID",
"workflow_node.deploy.form.edgio_applications_environment_id.tooltip": "For more information, see https://edgio.app/",
+ "workflow_node.deploy.form.flexcdn_resource_type.label": "Resource type",
+ "workflow_node.deploy.form.flexcdn_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.flexcdn_resource_type.option.certificate.label": "Certificate",
+ "workflow_node.deploy.form.flexcdn_certificate_id.label": "FlexCDN certificate ID",
+ "workflow_node.deploy.form.flexcdn_certificate_id.placeholder": "Please enter FlexCDN certificate ID",
+ "workflow_node.deploy.form.flexcdn_certificate_id.tooltip": "You can find it on FlexCDN WebUI.",
"workflow_node.deploy.form.gcore_cdn_resource_id.label": "Gcore CDN resource ID",
"workflow_node.deploy.form.gcore_cdn_resource_id.placeholder": "Please enter Gcore CDN resource ID",
"workflow_node.deploy.form.gcore_cdn_resource_id.tooltip": "For more information, see https://cdn.gcore.com/resources/list",
@@ -366,6 +392,7 @@
"workflow_node.deploy.form.goedge_resource_type.option.certificate.label": "Certificate",
"workflow_node.deploy.form.goedge_certificate_id.label": "GoEdge certificate ID",
"workflow_node.deploy.form.goedge_certificate_id.placeholder": "Please enter GoEdge certificate ID",
+ "workflow_node.deploy.form.goedge_certificate_id.tooltip": "You can find it on GoEdge WebUI.",
"workflow_node.deploy.form.huaweicloud_cdn_region.label": "Huawei Cloud CDN region",
"workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "Please enter Huawei Cloud CDN region (e.g. cn-north-1)",
"workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "For more information, see https://console-intl.huaweicloud.com/apiexplorer/#/endpoint",
@@ -443,6 +470,15 @@
"workflow_node.deploy.form.k8s_secret_data_key_for_key.label": "Kubernetes Secret data key for private key",
"workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder": "Please enter Kubernetes Secret data key for private key",
"workflow_node.deploy.form.k8s_secret_data_key_for_key.tooltip": "For more information, see https://kubernetes.io/docs/concepts/configuration/secret/",
+ "workflow_node.deploy.form.lecdn_resource_type.label": "Resource type",
+ "workflow_node.deploy.form.lecdn_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.lecdn_resource_type.option.certificate.label": "Certificate",
+ "workflow_node.deploy.form.lecdn_certificate_id.label": "LeCDN certificate ID",
+ "workflow_node.deploy.form.lecdn_certificate_id.placeholder": "Please enter LeCDN certificate ID",
+ "workflow_node.deploy.form.lecdn_certificate_id.tooltip": "You can find it on LeCDN WebUI.",
+ "workflow_node.deploy.form.lecdn_client_id.label": "LeCDN user ID (Optional)",
+ "workflow_node.deploy.form.lecdn_client_id.placeholder": "Please enter LeCDN user ID",
+ "workflow_node.deploy.form.lecdn_client_id.tooltip": "You can find it on LeCDN WebUI.
Required when using administrator's authorization. It Must be the same as the user to which the certificate belongs.",
"workflow_node.deploy.form.local.guide": "Tips: If you are running Certimate in Docker, the \"Local\" refers to the container rather than the host.",
"workflow_node.deploy.form.local_format.label": "File format",
"workflow_node.deploy.form.local_format.placeholder": "Please select file format",
@@ -489,8 +525,8 @@
"workflow_node.deploy.form.local_preset_scripts.option.ps_binding_iis.label": "PowerShell - Binding IIS",
"workflow_node.deploy.form.local_preset_scripts.option.ps_binding_netsh.label": "PowerShell - Binding netsh",
"workflow_node.deploy.form.local_preset_scripts.option.ps_.label": "PowerShell - Binding RDP",
- "workflow_node.deploy.form.netlify_site_id.label": "netlify site ID",
- "workflow_node.deploy.form.netlify_site_id.placeholder": "Please enter netlify site ID",
+ "workflow_node.deploy.form.netlify_site_id.label": "Netlify site ID",
+ "workflow_node.deploy.form.netlify_site_id.placeholder": "Please enter Netlify site ID",
"workflow_node.deploy.form.netlify_site_id.tooltip": "For more information, see https://docs.netlify.com/api/get-started/#get-site",
"workflow_node.deploy.form.proxmoxve_node_name.label": "Proxmox VE cluster node name",
"workflow_node.deploy.form.proxmoxve_node_name.placeholder": "Please enter Proxmox VE cluster node name",
@@ -513,11 +549,15 @@
"workflow_node.deploy.form.rainyun_rcdn_domain.label": "Rain Yun RCDN domain",
"workflow_node.deploy.form.rainyun_rcdn_domain.placeholder": "Please enter Rain Yun RCDN domain name",
"workflow_node.deploy.form.rainyun_rcdn_domain.tooltip": "For more information, see https://app.rainyun.com/apps/rcdn/list",
+ "workflow_node.deploy.form.ratpanel_site_name.label": "RatPanel site name",
+ "workflow_node.deploy.form.ratpanel_site_name.placeholder": "Please enter RatPanel site name",
+ "workflow_node.deploy.form.ratpanel_site_name.tooltip": "You can find it on RatPanel WebUI.",
"workflow_node.deploy.form.safeline_resource_type.label": "Resource type",
"workflow_node.deploy.form.safeline_resource_type.placeholder": "Please select resource type",
"workflow_node.deploy.form.safeline_resource_type.option.certificate.label": "Certificate",
"workflow_node.deploy.form.safeline_certificate_id.label": "SafeLine certificate ID",
"workflow_node.deploy.form.safeline_certificate_id.placeholder": "Please enter SafeLine certificate ID",
+ "workflow_node.deploy.form.safeline_certificate_id.tooltip": "You can find it on SafeLine WebUI.",
"workflow_node.deploy.form.ssh_format.label": "File format",
"workflow_node.deploy.form.ssh_format.placeholder": "Please select file format",
"workflow_node.deploy.form.ssh_format.option.pem.label": "PEM (*.pem, *.crt, *.key)",
@@ -720,6 +760,11 @@
"workflow_node.deploy.form.volcengine_tos_domain.label": "VolcEngine TOS domain",
"workflow_node.deploy.form.volcengine_tos_domain.placeholder": "Please enter VolcEngine TOS domain name",
"workflow_node.deploy.form.volcengine_tos_domain.tooltip": "For more information, see https://console.volcengine.com/tos",
+ "workflow_node.deploy.form.wangsu_cdn_domains.label": "Wangsu Cloud CDN domains",
+ "workflow_node.deploy.form.wangsu_cdn_domains.placeholder": "Please enter Wangsu Cloud CDN domain names (separated by semicolons)",
+ "workflow_node.deploy.form.wangsu_cdn_domains.tooltip": "For more information, see https://cdn.console.wangsu.com/v2/index/#/property/list",
+ "workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.title": "Change Wangsu Cloud CDN domains",
+ "workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.placeholder": "Please enter Wangsu Cloud CDN domain",
"workflow_node.deploy.form.wangsu_cdnpro_environment.label": "Wangsu Cloud environment",
"workflow_node.deploy.form.wangsu_cdnpro_environment.placeholder": "Please select Wangsu Cloud environment",
"workflow_node.deploy.form.wangsu_cdnpro_environment.option.production.label": "Production environment",
@@ -733,6 +778,9 @@
"workflow_node.deploy.form.wangsu_cdnpro_webhook_id.label": "Wangsu Cloud CDN Webhook ID (Optional)",
"workflow_node.deploy.form.wangsu_cdnpro_webhook_id.placeholder": "Please enter Wangsu Cloud CDN Webhook ID",
"workflow_node.deploy.form.wangsu_cdnpro_webhook_id.tooltip": "For more information, see https://cdnpro.console.wangsu.com/v2/index/#/certificate",
+ "workflow_node.deploy.form.wangsu_certificate_id.label": "Wangsu Cloud certificate ID (Optional)",
+ "workflow_node.deploy.form.wangsu_certificate_id.placeholder": "Please enter Wangsu Cloud certificate ID",
+ "workflow_node.deploy.form.wangsu_certificate_id.tooltip": "For more information, see https://cdn.console.wangsu.com/v2/index#/certificate/list",
"workflow_node.deploy.form.webhook_data.label": "Webhook data (Optional)",
"workflow_node.deploy.form.webhook_data.placeholder": "Please enter Webhook data to override the default value",
"workflow_node.deploy.form.webhook_data.tooltip": "Leave it blank to use the default Webhook data provided by the authorization.",
diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json
index 5af00a92..f4ee2c2a 100644
--- a/ui/src/i18n/locales/zh/nls.access.json
+++ b/ui/src/i18n/locales/zh/nls.access.json
@@ -36,12 +36,21 @@
"access.form.notification_channel.placeholder": "请选择通知渠道",
"access.form.1panel_api_url.label": "1Panel URL",
"access.form.1panel_api_url.placeholder": "请输入 1Panel URL",
+ "access.form.1panel_api_version.label": "1Panel 版本",
+ "access.form.1panel_api_version.placeholder": "请选择 1Panel 版本",
"access.form.1panel_api_key.label": "1Panel 接口密钥",
"access.form.1panel_api_key.placeholder": "请输入 1Panel 接口密钥",
"access.form.1panel_api_key.tooltip": "这是什么?请参阅 https://1panel.cn/docs/dev_manual/api_manual/",
"access.form.1panel_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误",
"access.form.1panel_allow_insecure_conns.switch.on": "允许",
"access.form.1panel_allow_insecure_conns.switch.off": "不允许",
+ "access.form.acmeca_endpoint.label": "服务端点",
+ "access.form.acmeca_endpoint.placeholder": "请输入服务端点",
+ "access.form.acmeca_endpoint.tooltip": "这是什么?请参阅 https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.1",
+ "access.form.acmeca_eab_kid.label": "ACME EAB KID(可选)",
+ "access.form.acmeca_eab_kid.placeholder": "请输入 ACME EAB KID",
+ "access.form.acmeca_eab_hmac_key.label": "ACME EAB HMAC Key(可选)",
+ "access.form.acmeca_eab_hmac_key.placeholder": "请输入 ACME EAB HMAC Key",
"access.form.acmehttpreq_endpoint.label": "服务端点",
"access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点",
"access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 https://go-acme.github.io/lego/dns/httpreq/",
@@ -94,6 +103,14 @@
"access.form.baotapanel_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误",
"access.form.baotapanel_allow_insecure_conns.switch.on": "允许",
"access.form.baotapanel_allow_insecure_conns.switch.off": "不允许",
+ "access.form.baotawaf_api_url.label": "堡塔云 WAF URL",
+ "access.form.baotawaf_api_url.placeholder": "请输入堡塔云 WAF URL",
+ "access.form.baotawaf_api_key.label": "堡塔云 WAF 接口密钥",
+ "access.form.baotawaf_api_key.placeholder": "请输入 堡塔云 WAF 接口密钥",
+ "access.form.baotawaf_api_key.tooltip": "这是什么?请参阅 https://github.com/aaPanel/aaWAF/blob/main/API.md",
+ "access.form.baotawaf_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误",
+ "access.form.baotawaf_allow_insecure_conns.switch.on": "允许",
+ "access.form.baotawaf_allow_insecure_conns.switch.off": "不允许",
"access.form.bunny_api_key.label": "Bunny API Key",
"access.form.bunny_api_key.placeholder": "请输入 Bunny API Key",
"access.form.bunny_api_key.tooltip": "这是什么?请参阅 https://docs.bunny.net/reference/bunnynet-api-overview",
@@ -106,8 +123,8 @@
"access.form.cachefly_api_token.label": "CacheFly API Token",
"access.form.cachefly_api_token.placeholder": "请输入 CacheFly API Token",
"access.form.cachefly_api_token.tooltip": "这是什么?请参阅 https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228",
- "access.form.cdnfly_api_url.label": "Cdnfly API URL",
- "access.form.cdnfly_api_url.placeholder": "请输入 Cdnfly API URL",
+ "access.form.cdnfly_api_url.label": "Cdnfly URL",
+ "access.form.cdnfly_api_url.placeholder": "请输入 Cdnfly URL",
"access.form.cdnfly_api_key.label": "Cdnfly 用户端 API Key",
"access.form.cdnfly_api_key.placeholder": "请输入 Cdnfly 用户端 API Key",
"access.form.cdnfly_api_key.tooltip": "这是什么?请参阅 https://doc.cdnfly.cn/shiyongjieshao.html",
@@ -178,6 +195,21 @@
"access.form.email_default_sender_address.placeholder": "请输入默认的发送邮箱地址",
"access.form.email_default_receiver_address.label": "默认的接收邮箱地址(可选)",
"access.form.email_default_receiver_address.placeholder": "请输入默认的接收邮箱地址",
+ "access.form.flexcdn_api_url.label": "FlexCDN URL",
+ "access.form.flexcdn_api_url.placeholder": "请输入 FlexCDN URL",
+ "access.form.flexcdn_api_role.label": "FlexCDN 用户角色",
+ "access.form.flexcdn_api_role.placeholder": "请选择 FlexCDN 用户角色",
+ "access.form.flexcdn_api_role.option.user.label": "平台用户",
+ "access.form.flexcdn_api_role.option.admin.label": "系统管理员",
+ "access.form.flexcdn_access_key_id.label": "FlexCDN AccessKeyId",
+ "access.form.flexcdn_access_key_id.placeholder": "请输入 FlexCDN AccessKeyId",
+ "access.form.flexcdn_access_key_id.tooltip": "这是什么?请参阅 https://flexcdn.cn/docs/api/auth",
+ "access.form.flexcdn_access_key.label": "FlexCDN AccessKey",
+ "access.form.flexcdn_access_key.placeholder": "请输入 FlexCDN AccessKey",
+ "access.form.flexcdn_access_key.tooltip": "这是什么?请参阅 https://flexcdn.cn/docs/api/auth",
+ "access.form.flexcdn_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误",
+ "access.form.flexcdn_allow_insecure_conns.switch.on": "允许",
+ "access.form.flexcdn_allow_insecure_conns.switch.off": "不允许",
"access.form.gcore_api_token.label": "Gcore API Token",
"access.form.gcore_api_token.placeholder": "请输入 Gcore API Token",
"access.form.gcore_api_token.tooltip": "这是什么?请参阅 https://api.gcore.com/docs/iam#section/Authentication",
@@ -193,8 +225,8 @@
"access.form.godaddy_api_secret.label": "GoDaddy API Secret",
"access.form.godaddy_api_secret.placeholder": "请输入 GoDaddy API Secret",
"access.form.godaddy_api_secret.tooltip": "这是什么?请参阅 https://developer.godaddy.com/",
- "access.form.goedge_api_url.label": "GoEdge API URL",
- "access.form.goedge_api_url.placeholder": "请输入 GoEdge API URL",
+ "access.form.goedge_api_url.label": "GoEdge URL",
+ "access.form.goedge_api_url.placeholder": "请输入 GoEdge URL",
"access.form.goedge_api_role.label": "GoEdge 用户角色",
"access.form.goedge_api_role.placeholder": "请选择 GoEdge 用户角色",
"access.form.goedge_api_role.option.user.label": "平台用户",
@@ -232,6 +264,21 @@
"access.form.larkbot_webhook_url.label": "飞书群机器人 Webhook 地址",
"access.form.larkbot_webhook_url.placeholder": "请输入飞书群机器人 Webhook 地址",
"access.form.larkbot_webhook_url.tooltip": "这是什么?请参阅 https://www.feishu.cn/hc/zh-CN/articles/807992406756",
+ "access.form.lecdn_api_url.label": "LeCDN URL",
+ "access.form.lecdn_api_url.placeholder": "请输入 LeCDN URL",
+ "access.form.lecdn_api_version.label": "LeCDN 版本",
+ "access.form.lecdn_api_version.placeholder": "请选择 LeCDN 版本",
+ "access.form.lecdn_api_role.label": "LeCDN 用户角色",
+ "access.form.lecdn_api_role.placeholder": "请选择 LeCDN 用户角色",
+ "access.form.lecdn_api_role.option.client.label": "客户用户",
+ "access.form.lecdn_api_role.option.master.label": "主控管理员",
+ "access.form.lecdn_username.label": "LeCDN 用户名",
+ "access.form.lecdn_username.placeholder": "请输入 LeCDN 用户名",
+ "access.form.lecdn_password.label": "LeCDN 用户密码",
+ "access.form.lecdn_password.placeholder": "请输入 LeCDN 用户密码",
+ "access.form.lecdn_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误",
+ "access.form.lecdn_allow_insecure_conns.switch.on": "允许",
+ "access.form.lecdn_allow_insecure_conns.switch.off": "不允许",
"access.form.mattermost_server_url.label": "Mattermost 服务地址",
"access.form.mattermost_server_url.placeholder": "请输入 Mattermost 服务地址",
"access.form.mattermost_username.label": "Mattermost 用户名",
@@ -256,8 +303,8 @@
"access.form.namesilo_api_key.label": "NameSilo API Key",
"access.form.namesilo_api_key.placeholder": "请输入 NameSilo API Key",
"access.form.namesilo_api_key.tooltip": "这是什么?请参阅 https://www.namesilo.com/support/v2/articles/account-options/api-manager",
- "access.form.netlify_api_token.label": "netlify API Token",
- "access.form.netlify_api_token.placeholder": "请输入 netlify API Token",
+ "access.form.netlify_api_token.label": "Netlify API Token",
+ "access.form.netlify_api_token.placeholder": "请输入 Netlify API Token",
"access.form.netlify_api_token.tooltip": "这是什么?请参阅 https://docs.netlify.com/api/get-started/#authentication",
"access.form.netcup_customer_number.label": "netcup 客户编号",
"access.form.netcup_customer_number.placeholder": "请输入 netcup 客户编号",
@@ -277,8 +324,8 @@
"access.form.porkbun_secret_api_key.label": "Porkbun Secret API Key",
"access.form.porkbun_secret_api_key.placeholder": "请输入 Porkbun Secret API Key",
"access.form.porkbun_secret_api_key.tooltip": "这是什么?请参阅 https://porkbun.com/api/json/v3/documentation",
- "access.form.powerdns_api_url.label": "PowerDNS API URL",
- "access.form.powerdns_api_url.placeholder": "请输入 PowerDNS API URL",
+ "access.form.powerdns_api_url.label": "PowerDNS URL",
+ "access.form.powerdns_api_url.placeholder": "请输入 PowerDNS URL",
"access.form.powerdns_api_key.label": "PowerDNS API Key",
"access.form.powerdns_api_key.placeholder": "请输入 PowerDNS API Key",
"access.form.powerdns_api_key.tooltip": "这是什么?请参阅 https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api",
@@ -305,6 +352,17 @@
"access.form.rainyun_api_key.label": "雨云 API 密钥",
"access.form.rainyun_api_key.placeholder": "请输入雨云 API 密钥",
"access.form.rainyun_api_key.tooltip": "这是什么?请参阅 https://app.rainyun.com/account/settings/api-key",
+ "access.form.ratpanel_api_url.label": "耗子面板 URL",
+ "access.form.ratpanel_api_url.placeholder": "请输入耗子面板 URL",
+ "access.form.ratpanel_access_token_id.label": "耗子面板 AccessToken ID",
+ "access.form.ratpanel_access_token_id.placeholder": "请输入耗子面板 AccessToken ID",
+ "access.form.ratpanel_access_token_id.tooltip": "这是什么?请参阅 https://ratpanel.github.io/advanced/api.html",
+ "access.form.ratpanel_access_token.label": "耗子面板 AccessToken",
+ "access.form.ratpanel_access_token.placeholder": "请输入耗子面板 AccessToken",
+ "access.form.ratpanel_access_token.tooltip": "这是什么?请参阅 https://ratpanel.github.io/advanced/api.html",
+ "access.form.ratpanel_allow_insecure_conns.label": "忽略 SSL/TLS 证书错误",
+ "access.form.ratpanel_allow_insecure_conns.switch.on": "允许",
+ "access.form.ratpanel_allow_insecure_conns.switch.off": "不允许",
"access.form.safeline_api_url.label": "雷池 URL",
"access.form.safeline_api_url.placeholder": "请输入雷池 URL",
"access.form.safeline_api_token.label": "雷池 API Token",
diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json
index dc635f68..b9fb8777 100644
--- a/ui/src/i18n/locales/zh/nls.provider.json
+++ b/ui/src/i18n/locales/zh/nls.provider.json
@@ -1,8 +1,9 @@
{
"provider.1panel": "1Panel",
- "provider.1panel.console": "1Panel - 面板",
+ "provider.1panel.console": "1Panel - 控制台",
"provider.1panel.site": "1Panel - 网站",
- "provider.acmehttpreq": "Http Request (ACME Proxy)",
+ "provider.acmeca": "ACME 自定义 CA 端点",
+ "provider.acmehttpreq": "ACME 自定义 HTTP 端点",
"provider.aliyun": "阿里云",
"provider.aliyun.alb": "阿里云 - 应用型负载均衡 ALB",
"provider.aliyun.apigw": "阿里云 - API 网关",
@@ -15,6 +16,7 @@
"provider.aliyun.dns": "阿里云 - 云解析 DNS",
"provider.aliyun.esa": "阿里云 - 边缘安全加速 ESA",
"provider.aliyun.fc": "阿里云 - 函数计算 FC",
+ "provider.aliyun.ga": "阿里云 - 全球加速 GA",
"provider.aliyun.live": "阿里云 - 视频直播 Live",
"provider.aliyun.nlb": "阿里云 - 网络型负载均衡 NLB",
"provider.aliyun.oss": "阿里云 - 对象存储 OSS",
@@ -38,8 +40,11 @@
"provider.baishan": "白山云",
"provider.baishan.cdn": "白山云 - 内容分发网络 CDN",
"provider.baotapanel": "宝塔面板",
- "provider.baotapanel.console": "宝塔面板 - 面板",
+ "provider.baotapanel.console": "宝塔面板 - 控制台",
"provider.baotapanel.site": "宝塔面板 - 网站",
+ "provider.baotawaf": "堡塔云 WAF",
+ "provider.baotawaf.console": "堡塔云 WAF - 控制台",
+ "provider.baotawaf.site": "堡塔云 WAF - 网站",
"provider.bunny": "Bunny",
"provider.bunny.cdn": "Bunny - 内容分发网络 CDN",
"provider.byteplus": "BytePlus",
@@ -62,6 +67,7 @@
"provider.edgio.applications": "Edgio - Applications",
"provider.email": "邮件",
"provider.fastly": "Fastly",
+ "provider.flexcdn": "FlexCDN",
"provider.gcore": "Gcore",
"provider.gcore.cdn": "Gcore - 内容分发网络 CDN",
"provider.gname": "GNAME",
@@ -83,6 +89,7 @@
"provider.kubernetes": "Kubernetes",
"provider.kubernetes.secret": "Kubernetes - Secret",
"provider.larkbot": "飞书群机器人",
+ "provider.lecdn": "LeCDN",
"provider.letsencrypt": "Let's Encrypt",
"provider.letsencryptstaging": "Let's Encrypt 测试环境",
"provider.local": "本地部署",
@@ -91,8 +98,8 @@
"provider.namedotcom": "Name.com",
"provider.namesilo": "NameSilo",
"provider.netcup": "netcup",
- "provider.netlify": "netlify",
- "provider.netlify.site": "netlify - Site",
+ "provider.netlify": "Netlify",
+ "provider.netlify.site": "Netlify - Site",
"provider.ns1": "NS1 (IBM NS1 Connect)",
"provider.porkbun": "Porkbun",
"provider.powerdns": "PowerDNS",
@@ -103,6 +110,9 @@
"provider.qiniu.pili": "七牛云 - 视频直播 Pili",
"provider.rainyun": "雨云",
"provider.rainyun.rcdn": "雨云 - 雨盾 CDN",
+ "provider.ratpanel": "耗子面板",
+ "provider.ratpanel.console": "耗子面板 - 控制台",
+ "provider.ratpanel.site": "耗子面板 - 网站",
"provider.safeline": "雷池",
"provider.ssh": "SSH 部署",
"provider.sslcom": "SSL.com",
@@ -138,7 +148,9 @@
"provider.volcengine.live": "火山引擎 - 视频直播 Live",
"provider.volcengine.tos": "火山引擎 - 对象存储 TOS",
"provider.wangsu": "网宿云",
- "provider.wangsu.cdnpro": "网宿云 - CDN Pro",
+ "provider.wangsu.cdn": "网宿云 - 内容分发网络 CDN",
+ "provider.wangsu.cdnpro": "网宿云 - CDN Pro (CDN 360)",
+ "provider.wangsu.certificate_upload": "网宿云 - 上传到证书管理",
"provider.webhook": "Webhook",
"provider.wecombot": "企业微信群机器人",
"provider.westcn": "西部数码",
@@ -150,8 +162,10 @@
"provider.category.loadbalance": "负载均衡",
"provider.category.firewall": "防火墙",
"provider.category.av": "音视频",
+ "provider.category.apigw": "API 网关",
"provider.category.serverless": "Serverless",
"provider.category.website": "网站托管",
+ "provider.category.ssl": "证书托管",
"provider.category.nas": "NAS",
"provider.category.other": "其他",
diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json
index 89cbfc11..faf40816 100644
--- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json
+++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json
@@ -109,18 +109,18 @@
"workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请或上传节点。如果选项为空请先确保前序节点配置正确。",
"workflow_node.deploy.form.params_config.label": "参数设置",
"workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启宝塔面板服务",
- "workflow_node.deploy.form.1panel_site_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.1panel_site_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.1panel_site_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.1panel_site_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.1panel_site_resource_type.option.website.label": "替换指定网站的证书",
"workflow_node.deploy.form.1panel_site_resource_type.option.certificate.label": "替换指定证书",
"workflow_node.deploy.form.1panel_site_website_id.label": "1Panel 网站 ID",
"workflow_node.deploy.form.1panel_site_website_id.placeholder": "请输入 1Panel 网站 ID",
- "workflow_node.deploy.form.1panel_site_website_id.tooltip": "请在 1Panel 管理面板查看。",
+ "workflow_node.deploy.form.1panel_site_website_id.tooltip": "请登录 1Panel 面板查看。",
"workflow_node.deploy.form.1panel_site_certificate_id.label": "1Panel 证书 ID",
"workflow_node.deploy.form.1panel_site_certificate_id.placeholder": "请输入 1Panel 证书 ID",
- "workflow_node.deploy.form.1panel_site_certificate_id.tooltip": "请在 1Panel 管理面板查看。",
- "workflow_node.deploy.form.aliyun_alb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.1panel_site_certificate_id.tooltip": "请登录 1Panel 面板查看。",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书",
"workflow_node.deploy.form.aliyun_alb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书",
"workflow_node.deploy.form.aliyun_alb_region.label": "阿里云 ALB 服务地域",
@@ -170,8 +170,8 @@
"workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-listcontact
不填写时,将使用系统联系人列表中的第一个。",
"workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.title": "修改阿里云联系人 ID",
"workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.placeholder": "请输入阿里云联系人 ID",
- "workflow_node.deploy.form.aliyun_clb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.aliyun_clb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.aliyun_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听的证书",
"workflow_node.deploy.form.aliyun_clb_resource_type.option.listener.label": "替换指定负载均衡监听的证书",
"workflow_node.deploy.form.aliyun_clb_region.label": "阿里云 CLB 服务地域",
@@ -212,14 +212,27 @@
"workflow_node.deploy.form.aliyun_fc_domain.label": "阿里云 FC 自定义域名",
"workflow_node.deploy.form.aliyun_fc_domain.placeholder": "请输入阿里云 FC 自定义域名(支持泛域名)",
"workflow_node.deploy.form.aliyun_fc_domain.tooltip": "这是什么?请参阅 see https://fcnext.console.aliyun.com/",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.placeholder": "请选择证书部署方式",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.option.accelerator.label": "替换指定全球加速器下的全部 HTTPS 监听的证书",
+ "workflow_node.deploy.form.aliyun_ga_resource_type.option.listener.label": "替换指定全球加速器监听器的证书",
+ "workflow_node.deploy.form.aliyun_ga_accelerator_id.label": "阿里云全球加速实例 ID",
+ "workflow_node.deploy.form.aliyun_ga_accelerator_id.placeholder": "请输入阿里云全球加速实例 ID",
+ "workflow_node.deploy.form.aliyun_ga_accelerator_id.tooltip": "这是什么?请参阅 https://ga.console.aliyun.com",
+ "workflow_node.deploy.form.aliyun_ga_listener_id.label": "阿里云全球加速监听 ID",
+ "workflow_node.deploy.form.aliyun_ga_listener_id.placeholder": "请输入阿里云全球加速监听 ID",
+ "workflow_node.deploy.form.aliyun_ga_listener_id.tooltip": "这是什么?请参阅 https://ga.console.aliyun.com",
+ "workflow_node.deploy.form.aliyun_ga_snidomain.label": "阿里云全球加速扩展域名(可选)",
+ "workflow_node.deploy.form.aliyun_ga_snidomain.placeholder": "请输入阿里云全球加速扩展域名",
+ "workflow_node.deploy.form.aliyun_ga_snidomain.tooltip": "这是什么?请参阅 https://ga.console.aliyun.com
不填写时,将替换监听器的默认证书;否则,将替换扩展域名证书。",
"workflow_node.deploy.form.aliyun_live_region.label": "阿里云视频直播服务地域",
"workflow_node.deploy.form.aliyun_live_region.placeholder": "请输入阿里云视频直播服务地域(例如:cn-hangzhou)",
"workflow_node.deploy.form.aliyun_live_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/live/product-overview/supported-regions",
"workflow_node.deploy.form.aliyun_live_domain.label": "阿里云视频直播流域名",
"workflow_node.deploy.form.aliyun_live_domain.placeholder": "请输入阿里云视频直播流域名(支持泛域名)",
"workflow_node.deploy.form.aliyun_live_domain.tooltip": "这是什么?请参阅 https://live.console.aliyun.com",
- "workflow_node.deploy.form.aliyun_nlb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.aliyun_nlb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书",
"workflow_node.deploy.form.aliyun_nlb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书",
"workflow_node.deploy.form.aliyun_nlb_region.label": "阿里云 NLB 服务地域",
@@ -276,8 +289,8 @@
"workflow_node.deploy.form.azure_keyvault_certificate_name.placeholder": "请输入 Azure KeyVault 证书名称",
"workflow_node.deploy.form.azure_keyvault_certificate_name.tooltip": "不填写时,将由 Certimate 自动生成证书名称。",
"workflow_node.deploy.form.azure_keyvault_certificate_name.errmsg.invalid": "证书名称只能包含字母、数字和连字符(-),长度限制为 1 到 127 个字符",
- "workflow_node.deploy.form.baiducloud_appblb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.baiducloud_appblb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.baiducloud_appblb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.baiducloud_appblb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.baiducloud_appblb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/SSL 监听的证书",
"workflow_node.deploy.form.baiducloud_appblb_resource_type.option.listener.label": "替换指定负载均衡监听的证书",
"workflow_node.deploy.form.baiducloud_appblb_region.label": "百度智能云 BLB 服务地域",
@@ -292,8 +305,8 @@
"workflow_node.deploy.form.baiducloud_appblb_snidomain.label": "百度智能云 BLB 扩展域名(可选)",
"workflow_node.deploy.form.baiducloud_appblb_snidomain.placeholder": "请输入百度智能云 BLB 扩展域名(支持泛域名)",
"workflow_node.deploy.form.baiducloud_appblb_snidomain.tooltip": "这是什么?请参阅 https://console.bce.baidu.com/blb/#/appblb/list
不填写时,将替换监听器的默认证书;否则,将替换扩展域名证书。",
- "workflow_node.deploy.form.baiducloud_blb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.baiducloud_blb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.baiducloud_blb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.baiducloud_blb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.baiducloud_blb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/SSL 监听的证书",
"workflow_node.deploy.form.baiducloud_blb_resource_type.option.listener.label": "替换指定负载均衡监听的证书",
"workflow_node.deploy.form.baiducloud_blb_region.label": "百度智能云 BLB 服务地域",
@@ -324,13 +337,18 @@
"workflow_node.deploy.form.baotapanel_site_type.option.other.label": "其他",
"workflow_node.deploy.form.baotapanel_site_name.label": "宝塔面板网站名称",
"workflow_node.deploy.form.baotapanel_site_name.placeholder": "请输入宝塔面板网站名称",
- "workflow_node.deploy.form.baotapanel_site_name.tooltip": "通常为网站域名。",
+ "workflow_node.deploy.form.baotapanel_site_name.tooltip": "请登录宝塔面板查看。",
"workflow_node.deploy.form.baotapanel_site_names.label": "宝塔面板网站名称",
"workflow_node.deploy.form.baotapanel_site_names.placeholder": "请输入宝塔面板网站名称(多个值请用半角分号隔开)",
"workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid": "请输入正确的宝塔面板网站名称",
- "workflow_node.deploy.form.baotapanel_site_names.tooltip": "通常为网站域名。",
+ "workflow_node.deploy.form.baotapanel_site_names.tooltip": "请登录宝塔面板查看。",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title": "修改宝塔面板网站名称",
"workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder": "请输入宝塔面板网站名称",
+ "workflow_node.deploy.form.baotawaf_site_name.label": "堡塔云 WAF 网站名称",
+ "workflow_node.deploy.form.baotawaf_site_name.placeholder": "请输入堡塔云 WAF 网站名称",
+ "workflow_node.deploy.form.baotawaf_site_name.tooltip": "请登录堡塔云 WAF 面板查看。",
+ "workflow_node.deploy.form.baotawaf_site_port.label": "堡塔云 WAF 网站 SSL 端口",
+ "workflow_node.deploy.form.baotawaf_site_port.placeholder": "请输入堡塔云 WAF 网站 SSL 端口",
"workflow_node.deploy.form.bunny_cdn_pull_zone_id.label": "Bunny CDN 拉取区域 ID",
"workflow_node.deploy.form.bunny_cdn_pull_zone_id.placeholder": "请输入 Bunny CDN 拉取区域 ID",
"workflow_node.deploy.form.bunny_cdn_pull_zone_id.tooltip": "这是什么?请参阅 https://dash.bunny.net/cdn",
@@ -340,39 +358,48 @@
"workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN 域名",
"workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "请输入 BytePlus CDN 域名(支持泛域名)",
"workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "这是什么?请参阅 https://console.byteplus.com/cdn",
- "workflow_node.deploy.form.cdnfly_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.cdnfly_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.cdnfly_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.cdnfly_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.cdnfly_resource_type.option.site.label": "替换指定网站的证书",
"workflow_node.deploy.form.cdnfly_resource_type.option.certificate.label": "替换指定证书",
"workflow_node.deploy.form.cdnfly_site_id.label": "Cdnfly 网站 ID",
"workflow_node.deploy.form.cdnfly_site_id.placeholder": "请输入 Cdnfly 网站 ID",
+ "workflow_node.deploy.form.cdnfly_site_id.tooltip": "请登录 Cdnfly 控制台查看。",
"workflow_node.deploy.form.cdnfly_certificate_id.label": "Cdnfly 证书 ID",
"workflow_node.deploy.form.cdnfly_certificate_id.placeholder": "请输入 Cdnfly 证书 ID",
+ "workflow_node.deploy.form.cdnfly_certificate_id.tooltip": "请登录 Cdnfly 控制台查看。",
"workflow_node.deploy.form.dogecloud_cdn_domain.label": "多吉云 CDN 加速域名",
"workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "请输入多吉云 CDN 加速域名",
"workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.dogecloud.com",
"workflow_node.deploy.form.edgio_applications_environment_id.label": "Edgio Applications 环境 ID",
"workflow_node.deploy.form.edgio_applications_environment_id.placeholder": "请输入 Edgio Applications 环境 ID",
"workflow_node.deploy.form.edgio_applications_environment_id.tooltip": "这是什么?请参阅 https://edgio.app/",
+ "workflow_node.deploy.form.flexcdn_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.flexcdn_resource_type.placeholder": "请选择证书部署方式",
+ "workflow_node.deploy.form.flexcdn_resource_type.option.certificate.label": "替换指定证书",
+ "workflow_node.deploy.form.flexcdn_certificate_id.label": "FlexCDN 证书 ID",
+ "workflow_node.deploy.form.flexcdn_certificate_id.placeholder": "请输入 FlexCDN 证书 ID",
+ "workflow_node.deploy.form.flexcdn_certificate_id.tooltip": "请登录 FlexCDN 控制台查看。",
"workflow_node.deploy.form.gcore_cdn_resource_id.label": "Gcore CDN 资源 ID",
"workflow_node.deploy.form.gcore_cdn_resource_id.placeholder": "请输入 Gcore CDN 资源 ID",
"workflow_node.deploy.form.gcore_cdn_resource_id.tooltip": "这是什么?请参阅 https://cdn.gcore.com/resources/list",
"workflow_node.deploy.form.gcore_cdn_certificate_id.label": "Gcore CDN 原证书 ID(可选)",
"workflow_node.deploy.form.gcore_cdn_certificate_id.placeholder": "请输入 Gcore CDN 原证书 ID",
"workflow_node.deploy.form.gcore_cdn_certificate_id.tooltip": "这是什么?请参阅 https://cdn.gcore.com/ssl
不填写时,将上传新证书;否则,将替换原证书。",
- "workflow_node.deploy.form.goedge_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.goedge_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.goedge_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.goedge_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.goedge_resource_type.option.certificate.label": "替换指定证书",
"workflow_node.deploy.form.goedge_certificate_id.label": "GoEdge 证书 ID",
"workflow_node.deploy.form.goedge_certificate_id.placeholder": "请输入 GoEdge 证书 ID",
+ "workflow_node.deploy.form.goedge_certificate_id.tooltip": "请登录 GoEdge 控制台查看。",
"workflow_node.deploy.form.huaweicloud_cdn_region.label": "华为云 CDN 服务区域",
"workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "请输入华为云 CDN 服务区域(例如:cn-north-1)",
"workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint",
"workflow_node.deploy.form.huaweicloud_cdn_domain.label": "华为云 CDN 加速域名",
"workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "请输入华为云 CDN 加速域名",
"workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/cdn",
- "workflow_node.deploy.form.huaweicloud_elb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.huaweicloud_elb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.huaweicloud_elb_resource_type.option.certificate.label": "替换指定证书",
"workflow_node.deploy.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听器的证书",
"workflow_node.deploy.form.huaweicloud_elb_resource_type.option.listener.label": "替换指定监听器的证书",
@@ -388,8 +415,8 @@
"workflow_node.deploy.form.huaweicloud_elb_listener_id.label": "华为云 ELB 监听器 ID",
"workflow_node.deploy.form.huaweicloud_elb_listener_id.placeholder": "请输入华为云 ELB 监听器 ID",
"workflow_node.deploy.form.huaweicloud_elb_listener_id.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/vpc/#/elb/list/grid",
- "workflow_node.deploy.form.huaweicloud_waf_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.huaweicloud_waf_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.huaweicloud_waf_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.huaweicloud_waf_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.huaweicloud_waf_resource_type.option.certificate.label": "替换指定证书",
"workflow_node.deploy.form.huaweicloud_waf_resource_type.option.cloudserver.label": "替换指定云模式防护网站的证书",
"workflow_node.deploy.form.huaweicloud_waf_resource_type.option.premiumhost.label": "替换指定独享模式防护网站的证书",
@@ -402,8 +429,8 @@
"workflow_node.deploy.form.huaweicloud_waf_domain.label": "华为云 WAF 防护域名",
"workflow_node.deploy.form.huaweicloud_waf_domain.placeholder": "请输入华为云 WAF 防护域名(支持泛域名)",
"workflow_node.deploy.form.huaweicloud_waf_domain.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/console/#/waf/domain/list",
- "workflow_node.deploy.form.jdcloud_alb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.jdcloud_alb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.jdcloud_alb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.jdcloud_alb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.jdcloud_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/TLS 监听的证书",
"workflow_node.deploy.form.jdcloud_alb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书",
"workflow_node.deploy.form.jdcloud_alb_region_id.label": "京东云 ALB 服务地域 ID",
@@ -442,6 +469,15 @@
"workflow_node.deploy.form.k8s_secret_data_key_for_key.label": "Kubernetes Secret 数据键(用于存放私钥的字段)",
"workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder": "请输入 Kubernetes Secret 中用于存放私钥的数据键",
"workflow_node.deploy.form.k8s_secret_data_key_for_key.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/",
+ "workflow_node.deploy.form.lecdn_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.lecdn_resource_type.placeholder": "请选择证书部署方式",
+ "workflow_node.deploy.form.lecdn_resource_type.option.certificate.label": "替换指定证书",
+ "workflow_node.deploy.form.lecdn_certificate_id.label": "LeCDN 证书 ID",
+ "workflow_node.deploy.form.lecdn_certificate_id.placeholder": "请输入 LeCDN 证书 ID",
+ "workflow_node.deploy.form.lecdn_certificate_id.tooltip": "请登录 LeCDN 控制台查看。",
+ "workflow_node.deploy.form.lecdn_client_id.label": "LeCDN 客户 ID(可选)",
+ "workflow_node.deploy.form.lecdn_client_id.placeholder": "请输入 LeCDN 客户 ID",
+ "workflow_node.deploy.form.lecdn_client_id.tooltip": "请登录 LeCDN 控制台查看。
使用的是系统管理员的授权信息时必填,需与证书所属客户相同。",
"workflow_node.deploy.form.local.guide": "小贴士:如果你正在使用 Docker 运行 Certimate,“本地”指的是容器内而非宿主机。",
"workflow_node.deploy.form.local_format.label": "文件格式",
"workflow_node.deploy.form.local_format.placeholder": "请选择文件格式",
@@ -488,7 +524,7 @@
"workflow_node.deploy.form.local_preset_scripts.option.ps_binding_iis.label": "PowerShell - 导入并绑定到 IIS",
"workflow_node.deploy.form.local_preset_scripts.option.ps_binding_netsh.label": "PowerShell - 导入并绑定到 netsh",
"workflow_node.deploy.form.local_preset_scripts.option.ps_binding_rdp.label": "PowerShell - 导入并绑定到 RDP",
- "workflow_node.deploy.form.netlify_site_id.label": "netlify 网站 ID",
+ "workflow_node.deploy.form.netlify_site_id.label": "Netlify 网站 ID",
"workflow_node.deploy.form.netlify_site_id.placeholder": "请输入 netlify 网站 ID",
"workflow_node.deploy.form.netlify_site_id.tooltip": "这是什么?请参阅 https://docs.netlify.com/api/get-started/#get-site",
"workflow_node.deploy.form.proxmoxve_node_name.label": "Proxmox VE 集群节点名称",
@@ -512,11 +548,15 @@
"workflow_node.deploy.form.rainyun_rcdn_domain.label": "雨云 RCDN 加速域名",
"workflow_node.deploy.form.rainyun_rcdn_domain.placeholder": "请输入雨云 RCDN 加速域名(支持泛域名)",
"workflow_node.deploy.form.rainyun_rcdn_domain.tooltip": "这是什么?请参阅 https://app.rainyun.com/apps/rcdn/list",
- "workflow_node.deploy.form.safeline_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.safeline_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.ratpanel_site_name.label": "耗子面板网站名称",
+ "workflow_node.deploy.form.ratpanel_site_name.placeholder": "请输入耗子面板网站名称",
+ "workflow_node.deploy.form.ratpanel_site_name.tooltip": "请登录耗子面板查看。",
+ "workflow_node.deploy.form.safeline_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.safeline_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.safeline_resource_type.option.certificate.label": "替换指定证书",
"workflow_node.deploy.form.safeline_certificate_id.label": "雷池证书 ID",
"workflow_node.deploy.form.safeline_certificate_id.placeholder": "请输入雷池证书 ID",
+ "workflow_node.deploy.form.safeline_certificate_id.tooltip": "请登录雷池控制台查看。",
"workflow_node.deploy.form.ssh_format.label": "文件格式",
"workflow_node.deploy.form.ssh_format.placeholder": "请选择文件格式",
"workflow_node.deploy.form.ssh_format.option.pem.label": "PEM 格式(*.pem, *.crt, *.key)",
@@ -564,8 +604,8 @@
"workflow_node.deploy.form.tencentcloud_cdn_domain.label": "腾讯云 CDN 加速域名",
"workflow_node.deploy.form.tencentcloud_cdn_domain.placeholder": "请输入腾讯云 CDN 加速域名(支持泛域名)",
"workflow_node.deploy.form.tencentcloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn",
- "workflow_node.deploy.form.tencentcloud_clb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.tencentcloud_clb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ssl_deploy.label": "通过 SSL 服务部署到云资源实例",
"workflow_node.deploy.form.tencentcloud_clb_resource_type.option.loadbalancer.label": "替换指定实例下的全部 HTTPS/TCPSSL/QUIC 监听器的证书",
"workflow_node.deploy.form.tencentcloud_clb_resource_type.option.listener.label": "替换指定监听器的证书",
@@ -661,8 +701,8 @@
"workflow_node.deploy.form.upyun_file_domain.label": "又拍云云存储加速域名",
"workflow_node.deploy.form.upyun_file_domain.placeholder": "请输入又拍云云存储加速域名",
"workflow_node.deploy.form.upyun_file_domain.tooltip": "这是什么?请参阅 https://console.upyun.com/services/file/",
- "workflow_node.deploy.form.volcengine_alb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.volcengine_alb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.volcengine_alb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.volcengine_alb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.volcengine_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听的证书",
"workflow_node.deploy.form.volcengine_alb_resource_type.option.listener.label": "替换指定监听器的证书",
"workflow_node.deploy.form.volcengine_alb_region.label": "火山引擎 ALB 服务地域",
@@ -682,8 +722,8 @@
"workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/cdn/homepage",
"workflow_node.deploy.form.volcengine_certcenter_region.label": "火山引擎证书中心服务地域",
"workflow_node.deploy.form.volcengine_certcenter_region.placeholder": "请输入火山引擎证书中心服务地域(例如:cn-beijing)",
- "workflow_node.deploy.form.volcengine_clb_resource_type.label": "证书替换方式",
- "workflow_node.deploy.form.volcengine_clb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.volcengine_clb_resource_type.label": "证书部署方式",
+ "workflow_node.deploy.form.volcengine_clb_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.volcengine_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听的证书",
"workflow_node.deploy.form.volcengine_clb_resource_type.option.listener.label": "替换指定监听器的证书",
"workflow_node.deploy.form.volcengine_clb_region.label": "火山引擎 CLB 服务地域",
@@ -719,6 +759,11 @@
"workflow_node.deploy.form.volcengine_tos_domain.label": "火山引擎 TOS 自定义域名",
"workflow_node.deploy.form.volcengine_tos_domain.placeholder": "请输入火山引擎 TOS 自定义域名",
"workflow_node.deploy.form.volcengine_tos_domain.tooltip": "这是什么?请参阅 see https://console.volcengine.com/tos",
+ "workflow_node.deploy.form.wangsu_cdn_domains.label": "网宿云 CDN 加速域名",
+ "workflow_node.deploy.form.wangsu_cdn_domains.placeholder": "请输入网宿云 CDN 加速域名(多个值请用半角分号隔开)",
+ "workflow_node.deploy.form.wangsu_cdn_domains.tooltip": "这是什么?请参阅 https://cdn.console.wangsu.com/v2/index/#/property/list",
+ "workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.title": "修改网宿云 CDN 加速域名",
+ "workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.placeholder": "请输入网宿云 CDN 加速域名",
"workflow_node.deploy.form.wangsu_cdnpro_environment.label": "网宿云环境",
"workflow_node.deploy.form.wangsu_cdnpro_environment.placeholder": "请选择网宿云环境",
"workflow_node.deploy.form.wangsu_cdnpro_environment.option.production.label": "生产环境",
@@ -732,6 +777,9 @@
"workflow_node.deploy.form.wangsu_cdnpro_webhook_id.label": "网宿云 CDN Pro 部署任务 Webhook ID(可选)",
"workflow_node.deploy.form.wangsu_cdnpro_webhook_id.placeholder": "请输入网宿云 CDN Pro 部署任务 Webhook ID",
"workflow_node.deploy.form.wangsu_cdnpro_webhook_id.tooltip": "这是什么?请参阅 https://cdnpro.console.wangsu.com/v2/index/#/certificate",
+ "workflow_node.deploy.form.wangsu_certificate_id.label": "网宿云证书 ID(可选)",
+ "workflow_node.deploy.form.wangsu_certificate_id.placeholder": "请输入网宿云证书 ID",
+ "workflow_node.deploy.form.wangsu_certificate_id.tooltip": "这是什么?请参阅 https://cdn.console.wangsu.com/v2/index#/certificate/list
不填写时,将上传新证书;否则,将替换原证书。",
"workflow_node.deploy.form.webhook_data.label": "Webhook 回调数据(可选)",
"workflow_node.deploy.form.webhook_data.placeholder": "请输入 Webhook 回调数据以覆盖默认值",
"workflow_node.deploy.form.webhook_data.tooltip": "不填写时,将使用所选部署目标授权的默认 Webhook 回调数据。",
diff --git a/ui/src/pages/certificates/CertificateList.tsx b/ui/src/pages/certificates/CertificateList.tsx
index 46bc1745..97eab0ef 100644
--- a/ui/src/pages/certificates/CertificateList.tsx
+++ b/ui/src/pages/certificates/CertificateList.tsx
@@ -126,11 +126,11 @@ const CertificateList = () => {
},
},
{
- key: "issuer",
+ key: "brand",
title: t("certificate.props.brand"),
render: (_, record) => (
- {record.issuer}
+ {record.issuerOrg}
{record.keyAlgorithm}
),