mirror of
https://github.com/certimate-go/certimate.git
synced 2026-10-16 07:05:59 +08:00
feat: plugin migration
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/baishan-cdn"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeBaishanCDN, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForBaishan{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
ApiToken: credentials.ApiToken,
|
||||
DeployTarget: xmaps.GetString(options.ProviderExtendedConfig, "deployTarget"),
|
||||
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
|
||||
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
|
||||
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/ksyun-cdn"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeKsyunCDN, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForKsyun{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
AccessKeyId: credentials.AccessKeyId,
|
||||
SecretAccessKey: credentials.SecretAccessKey,
|
||||
DeployTarget: xmaps.GetString(options.ProviderExtendedConfig, "deployTarget"),
|
||||
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
|
||||
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
|
||||
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/ksyun-kcm"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeKsyunKCM, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForKsyun{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
AccessKeyId: credentials.AccessKeyId,
|
||||
SecretAccessKey: credentials.SecretAccessKey,
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/ksyun-slb"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeKsyunSLB, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForKsyun{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
AccessKeyId: credentials.AccessKeyId,
|
||||
SecretAccessKey: credentials.SecretAccessKey,
|
||||
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
|
||||
DeployTarget: xmaps.GetString(options.ProviderExtendedConfig, "deployTarget"),
|
||||
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/wangsu-cdn"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeWangsuCDN, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForWangsu{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
AccessKeyId: credentials.AccessKeyId,
|
||||
AccessKeySecret: credentials.AccessKeySecret,
|
||||
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
|
||||
Domains: xmaps.GetStringsBySplit(options.ProviderExtendedConfig, "domains", ";"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/wangsu-cdnpro"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeWangsuCDNPro, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForWangsu{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
AccessKeyId: credentials.AccessKeyId,
|
||||
AccessKeySecret: credentials.AccessKeySecret,
|
||||
ApiKey: credentials.ApiKey,
|
||||
Environment: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "environment", "production"),
|
||||
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
|
||||
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
|
||||
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
|
||||
WebhookId: xmaps.GetString(options.ProviderExtendedConfig, "webhookId"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/wangsu-certificate"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeWangsuCertificate, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForWangsu{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
AccessKeyId: credentials.AccessKeyId,
|
||||
AccessKeySecret: credentials.AccessKeySecret,
|
||||
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -105,10 +105,6 @@ type AccessConfigForBaiduCloud struct {
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForBaishan struct {
|
||||
ApiToken string `json:"apiToken"`
|
||||
}
|
||||
|
||||
type AccessConfigForBaotaPanel struct {
|
||||
ServerUrl string `json:"serverUrl"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
@@ -375,11 +371,6 @@ type AccessConfigForKong struct {
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForKsyun struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForLarkBot struct {
|
||||
WebhookUrl string `json:"webhookUrl"`
|
||||
Secret string `json:"secret,omitempty"`
|
||||
@@ -659,12 +650,6 @@ type AccessConfigForVultr struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForWangsu struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForWebhook struct {
|
||||
Url string `json:"url"`
|
||||
Method string `json:"method,omitempty"`
|
||||
|
||||
@@ -28,7 +28,6 @@ const (
|
||||
AccessProviderTypeAxisNow = AccessProviderType("axisnow")
|
||||
AccessProviderTypeAzure = AccessProviderType("azure")
|
||||
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
|
||||
AccessProviderTypeBaishan = AccessProviderType("baishan")
|
||||
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
|
||||
AccessProviderTypeBaotaPanelGo = AccessProviderType("baotapanelgo")
|
||||
AccessProviderTypeBaotaWAF = AccessProviderType("baotawaf")
|
||||
@@ -81,7 +80,6 @@ const (
|
||||
AccessProviderTypeIONOS = AccessProviderType("ionos")
|
||||
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
|
||||
AccessProviderTypeKong = AccessProviderType("kong")
|
||||
AccessProviderTypeKsyun = AccessProviderType("ksyun")
|
||||
AccessProviderTypeLarkBot = AccessProviderType("larkbot")
|
||||
AccessProviderTypeLeCDN = AccessProviderType("lecdn")
|
||||
AccessProviderTypeLetsEncrypt = AccessProviderType("letsencrypt")
|
||||
@@ -130,7 +128,6 @@ const (
|
||||
AccessProviderTypeVercel = AccessProviderType("vercel")
|
||||
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
|
||||
AccessProviderTypeVultr = AccessProviderType("vultr")
|
||||
AccessProviderTypeWangsu = AccessProviderType("wangsu")
|
||||
AccessProviderTypeWebhook = AccessProviderType("webhook")
|
||||
AccessProviderTypeWeComBot = AccessProviderType("wecombot")
|
||||
AccessProviderTypeWestcn = AccessProviderType("westcn")
|
||||
@@ -346,7 +343,6 @@ const (
|
||||
DeploymentProviderTypeBaiduCloudBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-blb")
|
||||
DeploymentProviderTypeBaiduCloudCDN = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-cdn")
|
||||
DeploymentProviderTypeBaiduCloudCert = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-cert")
|
||||
DeploymentProviderTypeBaishanCDN = DeploymentProviderType(AccessProviderTypeBaishan + "-cdn")
|
||||
DeploymentProviderTypeBaotaPanel = DeploymentProviderType(AccessProviderTypeBaotaPanel)
|
||||
DeploymentProviderTypeBaotaPanelConsole = DeploymentProviderType(AccessProviderTypeBaotaPanel + "-console")
|
||||
DeploymentProviderTypeBaotaPanelGo = DeploymentProviderType(AccessProviderTypeBaotaPanelGo)
|
||||
@@ -399,9 +395,6 @@ const (
|
||||
DeploymentProviderTypeJDCloudSSL = DeploymentProviderType(AccessProviderTypeJDCloud + "-ssl")
|
||||
DeploymentProviderTypeJDCloudWAF = DeploymentProviderType(AccessProviderTypeJDCloud + "-waf")
|
||||
DeploymentProviderTypeKong = DeploymentProviderType(AccessProviderTypeKong)
|
||||
DeploymentProviderTypeKsyunCDN = DeploymentProviderType(AccessProviderTypeKsyun + "-cdn")
|
||||
DeploymentProviderTypeKsyunKCM = DeploymentProviderType(AccessProviderTypeKsyun + "-kcm")
|
||||
DeploymentProviderTypeKsyunSLB = DeploymentProviderType(AccessProviderTypeKsyun + "-slb")
|
||||
DeploymentProviderTypeLeCDN = DeploymentProviderType(AccessProviderTypeLeCDN)
|
||||
DeploymentProviderTypeLinodeLOS = DeploymentProviderType(AccessProviderTypeLinode + "-los")
|
||||
DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal)
|
||||
@@ -457,9 +450,6 @@ const (
|
||||
DeploymentProviderTypeVolcEngineTOS = DeploymentProviderType(AccessProviderTypeVolcEngine + "-tos")
|
||||
DeploymentProviderTypeVolcEngineVOD = DeploymentProviderType(AccessProviderTypeVolcEngine + "-vod")
|
||||
DeploymentProviderTypeVolcEngineWAF = DeploymentProviderType(AccessProviderTypeVolcEngine + "-waf")
|
||||
DeploymentProviderTypeWangsuCDN = DeploymentProviderType(AccessProviderTypeWangsu + "-cdn")
|
||||
DeploymentProviderTypeWangsuCDNPro = DeploymentProviderType(AccessProviderTypeWangsu + "-cdnpro")
|
||||
DeploymentProviderTypeWangsuCertificate = DeploymentProviderType(AccessProviderTypeWangsu + "-certificate")
|
||||
DeploymentProviderTypeWebhook = DeploymentProviderType(AccessProviderTypeWebhook)
|
||||
DeploymentProviderTypeYandexCloudCertificateManager = DeploymentProviderType(AccessProviderTypeYandexCloud + "-certificatemanager")
|
||||
)
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package baishancdn_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/certmgr/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/baishan-cdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("BAISHANCDN_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fApiToken string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fApiToken, "APITOKEN")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./baishan_cdn_test.go -args \
|
||||
--BAISHANCDN_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--BAISHANCDN_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--BAISHANCDN_APITOKEN="your-api-token"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
|
||||
ApiToken: fApiToken,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Upload(t, provider, tester.UploadInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package ksyunkcm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/certmgr/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/ksyun-kcm"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("KSYUNKCM_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fSecretAccessKey, "SECRETACCESSKEY")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./ksyun_kcm_test.go -args \
|
||||
--KSYUNKCM_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--KSYUNKCM_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--KSYUNKCM_ACCESSKEYID="your-access-key-id" \
|
||||
--KSYUNKCM_SECRETACCESSKEY="your-secret-access-key"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Upload(t, provider, tester.UploadInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package ksyunslb_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/certmgr/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/ksyun-slb"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("KSYUNSLB_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fRegion string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fSecretAccessKey, "SECRETACCESSKEY")
|
||||
fp.DefineString(&fRegion, "REGION")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./ksyun_slb_test.go -args \
|
||||
--KSYUNSLB_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--KSYUNSLB_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--KSYUNSLB_ACCESSKEYID="your-access-key-id" \
|
||||
--KSYUNSLB_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--KSYUNSLB_REGION="cn-beijing-6"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
Region: fRegion,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Upload(t, provider, tester.UploadInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package wangsucertificate_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/certmgr/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/wangsu-certificate"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("WANGSUCERTIFICATE_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fAccessKeySecret, "ACCESSKEYSECRET")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./wangsu_certificate_test.go -args \
|
||||
--WANGSUCERTIFICATE_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--WANGSUCERTIFICATE_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--WANGSUCERTIFICATE_ACCESSKEYID="your-access-key-id" \
|
||||
--WANGSUCERTIFICATE_ACCESSKEYSECRET="your-access-key-secret"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Upload", func(t *testing.T) {
|
||||
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Upload(t, provider, tester.UploadInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package baishancdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
baishansdk "github.com/certimate-go/certimate/pkg/sdk3rd/baishan"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Certmgr
|
||||
UploadResult = core.CertmgrUploadResult
|
||||
ReplaceResult = core.CertmgrReplaceResult
|
||||
)
|
||||
|
||||
type CertmgrConfig struct {
|
||||
// 白山云 API Token。
|
||||
ApiToken string `json:"apiToken"`
|
||||
}
|
||||
|
||||
type Certmgr struct {
|
||||
config *CertmgrConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *baishansdk.Client
|
||||
}
|
||||
|
||||
var _ Provider = (*Certmgr)(nil)
|
||||
|
||||
func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.ApiToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
return &Certmgr{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Certmgr) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
|
||||
// 生成新证书名(需符合白山云命名规则)
|
||||
certName := fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
|
||||
|
||||
// 新增证书
|
||||
// REF: https://portal.baishancloud.com/track/document/downloadPdf/1441
|
||||
certId := ""
|
||||
uploadDomainCertificateReq := &baishansdk.UploadDomainCertificateRequest{
|
||||
Name: lo.ToPtr(certName),
|
||||
Certificate: lo.ToPtr(certPEM),
|
||||
Key: lo.ToPtr(privkeyPEM),
|
||||
}
|
||||
uploadDomainCertificateResp, err := d.sdkClient.UploadDomainCertificateWithContext(ctx, uploadDomainCertificateReq)
|
||||
d.logger.Debug("sdk request 'cdn.UploadDomainCertificate'", slog.Any("request", uploadDomainCertificateReq), slog.Any("response", uploadDomainCertificateResp))
|
||||
if err != nil {
|
||||
if uploadDomainCertificateResp != nil {
|
||||
if uploadDomainCertificateResp.GetCode() == 400699 && strings.Contains(uploadDomainCertificateResp.GetMessage(), "this certificate is exists") {
|
||||
// 证书已存在,忽略新增证书接口错误
|
||||
re := regexp.MustCompile(`\d+`)
|
||||
certId = re.FindString(uploadDomainCertificateResp.GetMessage())
|
||||
}
|
||||
}
|
||||
|
||||
if certId == "" {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.SetDomainCertificate': %w", err)
|
||||
}
|
||||
} else {
|
||||
certId = uploadDomainCertificateResp.Data.CertId.String()
|
||||
}
|
||||
|
||||
return &UploadResult{
|
||||
CertId: certId,
|
||||
CertName: certName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
|
||||
// 替换证书
|
||||
// REF: https://portal.baishancloud.com/track/document/downloadPdf/1441
|
||||
uploadDomainCertificateReq := &baishansdk.UploadDomainCertificateRequest{
|
||||
CertificateId: lo.ToPtr(certIdOrName),
|
||||
Name: lo.ToPtr(fmt.Sprintf("certimate_%d", time.Now().UnixMilli())),
|
||||
Certificate: lo.ToPtr(certPEM),
|
||||
Key: lo.ToPtr(privkeyPEM),
|
||||
}
|
||||
uploadDomainCertificateResp, err := d.sdkClient.UploadDomainCertificateWithContext(ctx, uploadDomainCertificateReq)
|
||||
d.logger.Debug("sdk request 'cdn.UploadDomainCertificate'", slog.Any("request", uploadDomainCertificateReq), slog.Any("response", uploadDomainCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.UploadDomainCertificate': %w", err)
|
||||
}
|
||||
|
||||
return &ReplaceResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(apiToken string) (*baishansdk.Client, error) {
|
||||
client, err := baishansdk.NewClient(
|
||||
baishansdk.WithApiToken(apiToken),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
package ksyunkcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
ksyunkcmsdk "github.com/certimate-go/certimate/pkg/sdk3rd/ksyun/kcm"
|
||||
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Certmgr
|
||||
UploadResult = core.CertmgrUploadResult
|
||||
ReplaceResult = core.CertmgrReplaceResult
|
||||
)
|
||||
|
||||
type CertmgrConfig struct {
|
||||
// 金山云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 金山云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 金山云项目 ID。
|
||||
ProjectId int64 `json:"projectId,omitempty"`
|
||||
}
|
||||
|
||||
type Certmgr struct {
|
||||
config *CertmgrConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ksyunkcmsdk.Client
|
||||
}
|
||||
|
||||
var _ Provider = (*Certmgr)(nil)
|
||||
|
||||
func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
return &Certmgr{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
c.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
|
||||
// 避免重复上传
|
||||
if upres, upok, err := c.tryGetResultIfCertExists(ctx, certPEM); err != nil {
|
||||
return nil, err
|
||||
} else if upok {
|
||||
c.logger.Info("ssl certificate already exists")
|
||||
return upres, nil
|
||||
}
|
||||
|
||||
// 上传证书
|
||||
uploadCertificateReq := &ksyunkcmsdk.UploadCertificateRequest{
|
||||
ProjectId: lo.ToPtr(c.config.ProjectId),
|
||||
CertName: lo.ToPtr(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
||||
CertFile: lo.ToPtr(certPEM),
|
||||
CertKey: lo.ToPtr(privkeyPEM),
|
||||
}
|
||||
uploadCertificateResp, err := c.sdkClient.UploadCertificateWithContext(ctx, uploadCertificateReq)
|
||||
c.logger.Debug("sdk request 'kcm.UploadCertificate'", slog.Any("request", uploadCertificateReq), slog.Any("response", uploadCertificateResp))
|
||||
if err != nil {
|
||||
if uploadCertificateResp != nil &&
|
||||
uploadCertificateResp.Error != nil && uploadCertificateResp.Error.Message == "重复的证书文件" {
|
||||
if upres, upok, err := c.tryGetResultIfCertExists(ctx, certPEM); err != nil {
|
||||
return nil, err
|
||||
} else if !upok {
|
||||
return nil, fmt.Errorf("could not find ssl certificate, may be upload failed")
|
||||
} else {
|
||||
c.logger.Info("ssl certificate already exists")
|
||||
return upres, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'kcm.UploadCertificate': %w", err)
|
||||
}
|
||||
|
||||
return &UploadResult{
|
||||
CertId: uploadCertificateResp.Ret.CertId,
|
||||
CertName: uploadCertificateResp.Ret.CertName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
|
||||
return nil, core.ErrUnsupported
|
||||
}
|
||||
|
||||
func (c *Certmgr) tryGetResultIfCertExists(ctx context.Context, certPEM string) (*UploadResult, bool, error) {
|
||||
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
listUserCertificatesPage := 1
|
||||
listUserCertificatesPageSize := 100
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, false, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
listUserCertificatesReq := &ksyunkcmsdk.ListUserCertificatesRequest{
|
||||
Page: lo.ToPtr(int32(listUserCertificatesPage)),
|
||||
PageSize: lo.ToPtr(int32(listUserCertificatesPageSize)),
|
||||
}
|
||||
listUserCertificatesResp, err := c.sdkClient.ListUserCertificatesWithContext(ctx, listUserCertificatesReq)
|
||||
c.logger.Debug("sdk request 'kcm.ListUserCertificates'", slog.Any("request", listUserCertificatesReq), slog.Any("response", listUserCertificatesResp))
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("failed to execute sdk request 'kcm.ListUserCertificates': %w", err)
|
||||
}
|
||||
|
||||
if listUserCertificatesResp.Ret == nil || listUserCertificatesResp.Ret.Certs == nil {
|
||||
break
|
||||
}
|
||||
|
||||
fingerprintSha1 := sha1.Sum(certX509.Raw)
|
||||
fingerprintSha1Hex := hex.EncodeToString(fingerprintSha1[:])
|
||||
for _, certItem := range listUserCertificatesResp.Ret.Certs {
|
||||
// 对比证书备用名称
|
||||
if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), strings.Join(certItem.Domains, ",")) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 对比证书颁发者
|
||||
if certX509.Issuer.CommonName != certItem.CA {
|
||||
continue
|
||||
}
|
||||
|
||||
// 对比证书指纹
|
||||
if !strings.EqualFold(fingerprintSha1Hex, certItem.FingerPrint) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果以上信息都一致,则视为已存在相同证书,直接返回
|
||||
return &UploadResult{
|
||||
CertId: certItem.CertId,
|
||||
CertName: certItem.CertName,
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
if len(listUserCertificatesResp.Ret.Certs) < listUserCertificatesPageSize {
|
||||
break
|
||||
}
|
||||
|
||||
listUserCertificatesPage++
|
||||
}
|
||||
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, secretAccessKey string) (*ksyunkcmsdk.Client, error) {
|
||||
client, err := ksyunkcmsdk.NewClient(
|
||||
ksyunkcmsdk.WithAkSk(accessKeyId, secretAccessKey),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
package ksyunslb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/ksyun-kcm"
|
||||
ksyunkcmsdk "github.com/certimate-go/certimate/pkg/sdk3rd/ksyun/kcm"
|
||||
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Certmgr
|
||||
UploadResult = core.CertmgrUploadResult
|
||||
ReplaceResult = core.CertmgrReplaceResult
|
||||
)
|
||||
|
||||
type CertmgrConfig struct {
|
||||
// 金山云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 金山云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 金山云项目 ID。
|
||||
ProjectId int64 `json:"projectId,omitempty"`
|
||||
// 金山云地域。
|
||||
Region string `json:"region"`
|
||||
}
|
||||
|
||||
type Certmgr struct {
|
||||
config *CertmgrConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ksyunkcmsdk.Client
|
||||
sdkCertmgr core.Certmgr
|
||||
}
|
||||
|
||||
var _ Provider = (*Certmgr)(nil)
|
||||
|
||||
func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
ProjectId: config.ProjectId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Certmgr{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
c.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
c.logger = logger
|
||||
}
|
||||
|
||||
c.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
|
||||
// 描述证书,避免重复上传
|
||||
describeCertificatesPage := 1
|
||||
describeCertificatesPageSize := 100
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
describeCertificatesReq := &ksyunkcmsdk.DescribeCertificatesRequest{
|
||||
Region: lo.ToPtr(c.config.Region),
|
||||
Page: lo.ToPtr(int32(describeCertificatesPage)),
|
||||
PageSize: lo.ToPtr(int32(describeCertificatesPageSize)),
|
||||
}
|
||||
describeCertificatesResp, err := c.sdkClient.DescribeCertificatesWithContext(ctx, describeCertificatesReq)
|
||||
c.logger.Debug("sdk request 'kcm.DescribeCertificates'", slog.Any("request", describeCertificatesReq), slog.Any("response", describeCertificatesResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'kcm.DescribeCertificates': %w", err)
|
||||
}
|
||||
|
||||
if describeCertificatesResp.CertificateSet == nil {
|
||||
break
|
||||
}
|
||||
|
||||
for _, certItem := range describeCertificatesResp.CertificateSet {
|
||||
// 如果已存在相同证书,直接返回
|
||||
if xcert.EqualCertificatesFromPEM(certPEM, certItem.PublicKey) {
|
||||
c.logger.Info("ssl certificate already exists")
|
||||
return &UploadResult{
|
||||
CertId: certItem.CertificateId,
|
||||
CertName: certItem.CertificateName,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(describeCertificatesResp.CertificateSet) < describeCertificatesPageSize {
|
||||
break
|
||||
}
|
||||
|
||||
describeCertificatesPage++
|
||||
}
|
||||
|
||||
// 托管证书到 KCM
|
||||
upres, err := c.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
}
|
||||
|
||||
// 创建证书
|
||||
// REF: https://apiexplorer.ksyun.com/#/api/96/CreateCertificate/2016-03-04/1013
|
||||
createCertificateReq := &ksyunkcmsdk.CreateCertificateRequest{
|
||||
Region: lo.ToPtr(c.config.Region),
|
||||
CertificateName: lo.ToPtr(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
||||
Description: lo.ToPtr("upload from Certimate"),
|
||||
Source: lo.ToPtr("kcm"),
|
||||
SSLCertificateId: lo.ToPtr(upres.CertId),
|
||||
}
|
||||
createCertificateResp, err := c.sdkClient.CreateCertificateWithContext(ctx, createCertificateReq)
|
||||
c.logger.Debug("sdk request 'kcm.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'kcm.CreateCertificate': %w", err)
|
||||
}
|
||||
|
||||
return &UploadResult{
|
||||
CertId: createCertificateResp.Certificate.CertificateId,
|
||||
CertName: createCertificateResp.Certificate.CertificateName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
|
||||
// 托管证书到 KCM
|
||||
upres, err := c.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
}
|
||||
|
||||
// 更新证书
|
||||
// REF: https://apiexplorer.ksyun.com/#/api/96/ModifyCertificate/2016-03-04/1013
|
||||
modifyCertificateReq := &ksyunkcmsdk.ModifyCertificateRequest{
|
||||
Region: lo.ToPtr(c.config.Region),
|
||||
Description: lo.ToPtr("upload from Certimate"),
|
||||
SSLCertificateId: lo.ToPtr(upres.CertId),
|
||||
}
|
||||
modifyCertificateResp, err := c.sdkClient.ModifyCertificateWithContext(ctx, modifyCertificateReq)
|
||||
c.logger.Debug("sdk request 'kcm.ModifyCertificate'", slog.Any("request", modifyCertificateReq), slog.Any("response", modifyCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'kcm.ModifyCertificate': %w", err)
|
||||
}
|
||||
|
||||
return &ReplaceResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, secretAccessKey string) (*ksyunkcmsdk.Client, error) {
|
||||
client, err := ksyunkcmsdk.NewClient(
|
||||
ksyunkcmsdk.WithAkSk(accessKeyId, secretAccessKey),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
package wangsucertificate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
wangsucertificate "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/certificate"
|
||||
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Certmgr
|
||||
UploadResult = core.CertmgrUploadResult
|
||||
ReplaceResult = core.CertmgrReplaceResult
|
||||
)
|
||||
|
||||
type CertmgrConfig struct {
|
||||
// 网宿云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 网宿云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
}
|
||||
|
||||
type Certmgr struct {
|
||||
config *CertmgrConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *wangsucertificate.Client
|
||||
}
|
||||
|
||||
var _ Provider = (*Certmgr)(nil)
|
||||
|
||||
func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.AccessKeyId, config.AccessKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
return &Certmgr{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
c.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
|
||||
// 解析证书内容
|
||||
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 查询证书列表,避免重复上传
|
||||
// REF: https://www.wangsu.com/document/api-doc/22675?productCode=certificatemanagement
|
||||
listCertificatesResp, err := c.sdkClient.ListCertificatesWithContext(ctx)
|
||||
c.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 _, certItem := range listCertificatesResp.Certificates {
|
||||
// 对比证书序列号
|
||||
if !strings.EqualFold(certX509.SerialNumber.Text(16), certItem.Serial) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 对比证书有效期
|
||||
timezoneOfCST := time.FixedZone("CST", 8*60*60)
|
||||
newCertNotBefore := certX509.NotBefore
|
||||
newCertNotAfter := certX509.NotAfter
|
||||
oldCertNotBefore, _ := time.ParseInLocation(time.DateTime, certItem.ValidityFrom, timezoneOfCST)
|
||||
oldCertNotAfter, _ := time.ParseInLocation(time.DateTime, certItem.ValidityTo, timezoneOfCST)
|
||||
if !newCertNotBefore.Equal(oldCertNotBefore) || !newCertNotAfter.Equal(oldCertNotAfter) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果以上信息都一致,则视为已存在相同证书,直接返回
|
||||
c.logger.Info("ssl certificate already exists")
|
||||
return &UploadResult{
|
||||
CertId: certItem.Id,
|
||||
CertName: certItem.Name,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 生成新证书名(需符合网宿云命名规则)
|
||||
certName := fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
|
||||
|
||||
// 新增证书
|
||||
// REF: https://www.wangsu.com/document/api-doc/25199?productCode=certificatemanagement
|
||||
createCertificateReq := &wangsucertificate.CreateCertificateRequest{
|
||||
Name: lo.ToPtr(certName),
|
||||
Certificate: lo.ToPtr(certPEM),
|
||||
PrivateKey: lo.ToPtr(privkeyPEM),
|
||||
Comment: lo.ToPtr("upload from Certimate"),
|
||||
}
|
||||
createCertificateResp, err := c.sdkClient.CreateCertificateWithContext(ctx, createCertificateReq)
|
||||
c.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.CertificateLocation)
|
||||
if len(wangsuCertIdMatches) == 0 {
|
||||
return nil, fmt.Errorf("received empty certificate id")
|
||||
}
|
||||
|
||||
return &UploadResult{
|
||||
CertId: wangsuCertIdMatches[1],
|
||||
CertName: certName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
|
||||
certId := certIdOrName
|
||||
certName := fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
|
||||
|
||||
// 修改证书
|
||||
// REF: https://www.wangsu.com/document/api-doc/25568?productCode=certificatemanagement
|
||||
updateCertificateReq := &wangsucertificate.UpdateCertificateRequest{
|
||||
Name: lo.ToPtr(certName),
|
||||
Certificate: lo.ToPtr(certPEM),
|
||||
PrivateKey: lo.ToPtr(privkeyPEM),
|
||||
Comment: lo.ToPtr("upload from Certimate"),
|
||||
}
|
||||
updateCertificateResp, err := c.sdkClient.UpdateCertificateWithContext(ctx, certId, updateCertificateReq)
|
||||
c.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.UpdateCertificate': %w", err)
|
||||
}
|
||||
|
||||
return &ReplaceResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, accessKeySecret string) (*wangsucertificate.Client, error) {
|
||||
client, err := wangsucertificate.NewClient(
|
||||
wangsucertificate.WithAkSk(accessKeyId, accessKeySecret),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package baishancdn_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/deployer/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/baishan-cdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("BAISHANCDN_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fApiToken string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fApiToken, "APITOKEN")
|
||||
fp.DefineString(&fDomain, "DOMAIN")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./baishan_cdn_test.go -args \
|
||||
--BAISHANCDN_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--BAISHANCDN_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--BAISHANCDN_APITOKEN="your-api-token" \
|
||||
--BAISHANCDN_DOMAIN="example.com"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
ApiToken: fApiToken,
|
||||
DomainMatchPattern: impl.DOMAIN_MATCH_PATTERN_EXACT,
|
||||
Domain: fDomain,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Deploy(t, provider, tester.DeployInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package ksyuncdn_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/deployer/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/ksyun-cdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("KSYUNCDN_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fDomain string
|
||||
fCertificateId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fSecretAccessKey, "SECRETACCESSKEY")
|
||||
fp.DefineString(&fDomain, "DOMAIN")
|
||||
fp.DefineString(&fCertificateId, "CERTIFICATEID")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./ksyun_cdn_test.go -args \
|
||||
--KSYUNCDN_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--KSYUNCDN_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--KSYUNCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--KSYUNCDN_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--KSYUNCDN_DOMAIN="example.com" \
|
||||
--KSYUNCDN_CERTIFICATEID="your-certificate-id"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy_ToDomain", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
DeployTarget: impl.DEPLOY_TARGET_DOMAIN,
|
||||
DomainMatchPattern: impl.DOMAIN_MATCH_PATTERN_EXACT,
|
||||
Domain: fDomain,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Deploy(t, provider, tester.DeployInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
|
||||
t.Run("Deploy_ToCertificate", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
DeployTarget: impl.DEPLOY_TARGET_CERTIFICATE,
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Deploy(t, provider, tester.DeployInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package ksyunslb_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/deployer/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/ksyun-slb"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("KSYUNSLB_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fRegion string
|
||||
fCertificateId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fSecretAccessKey, "SECRETACCESSKEY")
|
||||
fp.DefineString(&fRegion, "REGION")
|
||||
fp.DefineString(&fCertificateId, "CERTIFICATEID")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./ksyun_slb_test.go -args \
|
||||
--KSYUNSLB_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--KSYUNSLB_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--KSYUNSLB_ACCESSKEYID="your-access-key-id" \
|
||||
--KSYUNSLB_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--KSYUNSLB_REGION="cn-beijing-6" \
|
||||
--KSYUNSLB_CERTIFICATEID="your-certificate-id"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy_ToCertificate", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
Region: fRegion,
|
||||
DeployTarget: impl.DEPLOY_TARGET_CERTIFICATE,
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Deploy(t, provider, tester.DeployInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package wangsucdn_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/deployer/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/wangsu-cdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("WANGSUCDN_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fAccessKeySecret, "ACCESSKEYSECRET")
|
||||
fp.DefineString(&fDomain, "DOMAIN")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./wangsu_cdn_test.go -args \
|
||||
--WANGSUCDN_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--WANGSUCDN_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--WANGSUCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--WANGSUCDN_ACCESSKEYSECRET="your-access-key-secret" \
|
||||
--WANGSUCDN_DOMAIN="example.com"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
Domains: []string{fDomain},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Deploy(t, provider, tester.DeployInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package wangsucdnpro_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/deployer/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/wangsu-cdnpro"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("WANGSUCDNPRO_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
fApiKey string
|
||||
fEnvironment string
|
||||
fDomain string
|
||||
fCertificateId string
|
||||
fWebhookId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fAccessKeySecret, "ACCESSKEYSECRET")
|
||||
fp.DefineString(&fApiKey, "APIKEY")
|
||||
fp.DefineString(&fEnvironment, "ENVIRONMENT", "production")
|
||||
fp.DefineString(&fDomain, "DOMAIN")
|
||||
fp.DefineString(&fCertificateId, "CERTIFICATEID")
|
||||
fp.DefineString(&fWebhookId, "WEBHOOKID")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./wangsu_cdnpro_test.go -args \
|
||||
--WANGSUCDNPRO_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--WANGSUCDNPRO_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--WANGSUCDNPRO_ACCESSKEYID="your-access-key-id" \
|
||||
--WANGSUCDNPRO_ACCESSKEYSECRET="your-access-key-secret" \
|
||||
--WANGSUCDNPRO_APIKEY="your-api-key" \
|
||||
--WANGSUCDNPRO_ENVIRONMENT="production" \
|
||||
--WANGSUCDNPRO_DOMAIN="example.com" \
|
||||
--WANGSUCDNPRO_CERTIFICATEID="your-certificate-id" \
|
||||
--WANGSUCDNPRO_WEBHOOKID="your-webhook-id"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
ApiKey: fApiKey,
|
||||
Environment: fEnvironment,
|
||||
Domain: fDomain,
|
||||
CertificateId: fCertificateId,
|
||||
WebhookId: fWebhookId,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Deploy(t, provider, tester.DeployInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//go:build tester
|
||||
|
||||
package wangsucertificate_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
tester "github.com/certimate-go/certimate/pkg/core/deployer/providers-tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/wangsu-certificate"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.InitArgs("WANGSUCERTIFICATE_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
fCertificateId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fAccessKeySecret, "ACCESSKEYSECRET")
|
||||
fp.DefineString(&fCertificateId, "CERTIFICATEID")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -tags=tester -v ./wangsu_certificate_test.go -args \
|
||||
--WANGSUCERTIFICATE_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--WANGSUCERTIFICATE_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--WANGSUCERTIFICATE_ACCESSKEYID="your-access-key-id" \
|
||||
--WANGSUCERTIFICATE_ACCESSKEYSECRET="your-access-key-secret" \
|
||||
--WANGSUCERTIFICATE_CERTIFICATEID="your-certificate-id"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tester.Deploy(t, provider, tester.DeployInput{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
package baishancdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/baishan-cdn"
|
||||
baishansdk "github.com/certimate-go/certimate/pkg/sdk3rd/baishan"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 白山云 API Token。
|
||||
ApiToken string `json:"apiToken"`
|
||||
// 部署目标。
|
||||
DeployTarget string `json:"deployTarget"`
|
||||
// 域名匹配模式。暂时只支持精确匹配。
|
||||
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
|
||||
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
// 证书 ID。
|
||||
// 部署目标为 [DEPLOY_TARGET_CERTIFICATE] 时必填。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *baishansdk.Client
|
||||
sdkCertmgr core.Certmgr
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.ApiToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
|
||||
ApiToken: config.ApiToken,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
d.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
// 根据部署目标决定业务流程
|
||||
switch d.config.DeployTarget {
|
||||
case DEPLOY_TARGET_DOMAIN:
|
||||
if err := d.deployToDomain(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case DEPLOY_TARGET_CERTIFICATE:
|
||||
if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported deploy target '%s'", d.config.DeployTarget)
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) deployToDomain(ctx context.Context, certPEM, privkeyPEM string) error {
|
||||
domain := normalizeDomain(d.config.Domain)
|
||||
if domain == "" {
|
||||
return fmt.Errorf("config `domain` is required")
|
||||
}
|
||||
|
||||
// 上传证书
|
||||
upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 查询域名配置
|
||||
// REF: https://portal.baishancloud.com/track/document/api/1/1065
|
||||
getDomainConfigReq := &baishansdk.GetDomainConfigRequest{
|
||||
Domains: lo.ToPtr(domain),
|
||||
Config: []*string{lo.ToPtr("https")},
|
||||
}
|
||||
getDomainConfigResp, err := d.sdkClient.GetDomainConfigWithContext(ctx, getDomainConfigReq)
|
||||
d.logger.Debug("sdk request 'cdn.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'cdn.GetDomainConfig': %w", err)
|
||||
} else if len(getDomainConfigResp.Data) == 0 {
|
||||
return fmt.Errorf("could not find domain '%s'", domain)
|
||||
}
|
||||
|
||||
// 设置域名配置
|
||||
// REF: https://portal.baishancloud.com/track/document/api/1/1045
|
||||
setDomainConfigReq := &baishansdk.SetDomainConfigRequest{
|
||||
Domains: lo.ToPtr(domain),
|
||||
Config: &baishansdk.DomainConfig{
|
||||
Https: &baishansdk.DomainConfigHttps{
|
||||
CertId: json.Number(upres.CertId),
|
||||
ForceHttps: getDomainConfigResp.Data[0].Config.Https.ForceHttps,
|
||||
EnableHttp2: getDomainConfigResp.Data[0].Config.Https.EnableHttp2,
|
||||
EnableOcsp: getDomainConfigResp.Data[0].Config.Https.EnableOcsp,
|
||||
},
|
||||
},
|
||||
}
|
||||
setDomainConfigResp, err := d.sdkClient.SetDomainConfigWithContext(ctx, setDomainConfigReq)
|
||||
d.logger.Debug("sdk request 'cdn.SetDomainConfig'", slog.Any("request", setDomainConfigReq), slog.Any("response", setDomainConfigResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'cdn.SetDomainConfig': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployer) deployToCertificate(ctx context.Context, certPEM, privkeyPEM string) error {
|
||||
if d.config.CertificateId == "" {
|
||||
return fmt.Errorf("config `certificateId` is required")
|
||||
}
|
||||
|
||||
// 替换证书
|
||||
rplres, err := d.sdkCertmgr.Replace(ctx, d.config.CertificateId, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to replace certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate replaced", slog.Any("result", rplres))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSDKClient(apiToken string) (*baishansdk.Client, error) {
|
||||
client, err := baishansdk.NewClient(
|
||||
baishansdk.WithApiToken(apiToken),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func normalizeDomain(domain string) string {
|
||||
// "*.example.com" → ".example.com",适配白山云 CDN 的泛域名参数要求
|
||||
if strings.HasPrefix(domain, "*.") {
|
||||
return strings.TrimPrefix(domain, "*")
|
||||
}
|
||||
return domain
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package baishancdn
|
||||
|
||||
const (
|
||||
// 部署目标:替换指定域名的证书。
|
||||
DEPLOY_TARGET_DOMAIN = "domain"
|
||||
// 部署目标:替换指定证书。
|
||||
DEPLOY_TARGET_CERTIFICATE = "certificate"
|
||||
)
|
||||
|
||||
const (
|
||||
// 匹配模式:精确匹配。
|
||||
DOMAIN_MATCH_PATTERN_EXACT = "exact"
|
||||
)
|
||||
@@ -1,17 +0,0 @@
|
||||
package ksyuncdn
|
||||
|
||||
const (
|
||||
// 部署目标:替换指定域名的证书。
|
||||
DEPLOY_TARGET_DOMAIN = "domain"
|
||||
// 部署目标:替换指定证书。
|
||||
DEPLOY_TARGET_CERTIFICATE = "certificate"
|
||||
)
|
||||
|
||||
const (
|
||||
// 匹配模式:精确匹配。
|
||||
DOMAIN_MATCH_PATTERN_EXACT = "exact"
|
||||
// 匹配模式:通配符匹配。
|
||||
DOMAIN_MATCH_PATTERN_WILDCARD = "wildcard"
|
||||
// 匹配模式:证书 SAN 匹配。
|
||||
DOMAIN_MATCH_PATTERN_CERTSAN = "certsan"
|
||||
)
|
||||
@@ -1,285 +0,0 @@
|
||||
package ksyuncdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
ksyuncdnsdk "github.com/certimate-go/certimate/pkg/sdk3rd/ksyun/cdn"
|
||||
xcerthostname "github.com/certimate-go/certimate/pkg/utils/cert/hostname"
|
||||
xloop "github.com/certimate-go/certimate/pkg/utils/loop"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 金山云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 金山云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 金山云项目 ID。
|
||||
ProjectId int64 `json:"projectId,omitempty"`
|
||||
// 部署目标。
|
||||
DeployTarget string `json:"deployTarget"`
|
||||
// 域名匹配模式。
|
||||
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
|
||||
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
// 证书 ID。
|
||||
// 部署目标为 [DEPLOY_TARGET_CERTIFICATE] 时必填。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ksyuncdnsdk.Client
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
// 根据部署目标决定业务流程
|
||||
switch d.config.DeployTarget {
|
||||
case DEPLOY_TARGET_DOMAIN:
|
||||
if err := d.deployToDomain(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case DEPLOY_TARGET_CERTIFICATE:
|
||||
if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported deploy target '%s'", d.config.DeployTarget)
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) deployToDomain(ctx context.Context, certPEM, privkeyPEM string) error {
|
||||
_, err := d.getAllDomains(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取待部署的域名列表
|
||||
var domainIds []string
|
||||
switch d.config.DomainMatchPattern {
|
||||
case "", DOMAIN_MATCH_PATTERN_EXACT:
|
||||
{
|
||||
if d.config.Domain == "" {
|
||||
return fmt.Errorf("config `domain` is required")
|
||||
}
|
||||
|
||||
domainCandidates, err := d.getAllDomains(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domains := lo.Filter(domainCandidates, func(domainItem *ksyuncdnsdk.CDNDomain, _ int) bool {
|
||||
return d.config.Domain == domainItem.DomainName
|
||||
})
|
||||
if len(domains) == 0 {
|
||||
return fmt.Errorf("could not find domain")
|
||||
}
|
||||
|
||||
domainIds = lo.Map(domains, func(domainItem *ksyuncdnsdk.CDNDomain, _ int) string {
|
||||
return domainItem.DomainId
|
||||
})
|
||||
}
|
||||
|
||||
case DOMAIN_MATCH_PATTERN_WILDCARD:
|
||||
{
|
||||
if d.config.Domain == "" {
|
||||
return fmt.Errorf("config `domain` is required")
|
||||
}
|
||||
|
||||
domainCandidates, err := d.getAllDomains(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
domains := lo.Filter(domainCandidates, func(domainItem *ksyuncdnsdk.CDNDomain, _ int) bool {
|
||||
return xcerthostname.IsMatch(d.config.Domain, domainItem.DomainName)
|
||||
})
|
||||
if len(domains) == 0 {
|
||||
return fmt.Errorf("could not find any domains matched by wildcard")
|
||||
}
|
||||
|
||||
domainIds = lo.Map(domains, func(domainItem *ksyuncdnsdk.CDNDomain, _ int) string {
|
||||
return domainItem.DomainId
|
||||
})
|
||||
}
|
||||
|
||||
case DOMAIN_MATCH_PATTERN_CERTSAN:
|
||||
{
|
||||
domainCandidates, err := d.getAllDomains(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
domains := lo.Filter(domainCandidates, func(domainItem *ksyuncdnsdk.CDNDomain, _ int) bool {
|
||||
return xcerthostname.IsMatchByCertificatePEM(certPEM, domainItem.DomainName)
|
||||
})
|
||||
if len(domains) == 0 {
|
||||
return fmt.Errorf("could not find any domains matched by certificate")
|
||||
}
|
||||
|
||||
domainIds = lo.Map(domains, func(domainItem *ksyuncdnsdk.CDNDomain, _ int) string {
|
||||
return domainItem.DomainId
|
||||
})
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported domain match pattern: '%s'", d.config.DomainMatchPattern)
|
||||
}
|
||||
|
||||
// 批量更新域名证书
|
||||
if len(domainIds) == 0 {
|
||||
d.logger.Info("no cdn domains to deploy")
|
||||
} else {
|
||||
d.logger.Info("found cdn domains to deploy", slog.Any("domainIds", domainIds))
|
||||
|
||||
if err := xloop.ForRangeAllWithContext(ctx, domainIds, func(ctx context.Context, domainId string, _ int) error {
|
||||
return d.updateDomainCertificate(ctx, domainId, certPEM, privkeyPEM)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployer) deployToCertificate(ctx context.Context, certPEM, privkeyPEM string) error {
|
||||
if d.config.CertificateId == "" {
|
||||
return fmt.Errorf("config `certificateId` is required")
|
||||
}
|
||||
|
||||
// 更新证书
|
||||
// REF: https://docs.ksyun.com/documents/259
|
||||
setCertificateReq := &ksyuncdnsdk.SetCertificateRequest{
|
||||
CertificateId: lo.ToPtr(d.config.CertificateId),
|
||||
CertificateName: lo.ToPtr(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
||||
ServerCertificate: lo.ToPtr(certPEM),
|
||||
PrivateKey: lo.ToPtr(privkeyPEM),
|
||||
}
|
||||
setCertificateResp, err := d.sdkClient.SetCertificateWithContext(ctx, setCertificateReq)
|
||||
d.logger.Debug("sdk request 'cdn.SetCertificate'", slog.Any("request", setCertificateReq), slog.Any("response", setCertificateResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'cdn.SetCertificate': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployer) getAllDomains(ctx context.Context) ([]*ksyuncdnsdk.CDNDomain, error) {
|
||||
domains := make([]*ksyuncdnsdk.CDNDomain, 0)
|
||||
|
||||
// 查询域名列表
|
||||
// REF: https://docs.ksyun.com/documents/198
|
||||
getCdnDomainsPageNumber := 1
|
||||
getCdnDomainsPageSize := 100
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
getCdnDomainsReq := &ksyuncdnsdk.GetCDNDomainsRequest{
|
||||
ProjectId: lo.IfF(d.config.ProjectId != 0, func() *int64 { return lo.ToPtr(d.config.ProjectId) }).Else(nil),
|
||||
PageNumber: lo.ToPtr(int32(getCdnDomainsPageNumber)),
|
||||
PageSize: lo.ToPtr(int32(getCdnDomainsPageSize)),
|
||||
}
|
||||
getCdnDomainsResp, err := d.sdkClient.GetCDNDomainsWithContext(ctx, getCdnDomainsReq)
|
||||
d.logger.Debug("sdk request 'cdn.GetCdnDomains'", slog.Any("request", getCdnDomainsReq), slog.Any("response", getCdnDomainsResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetCdnDomains': %w", err)
|
||||
}
|
||||
|
||||
if getCdnDomainsResp.Domains == nil {
|
||||
break
|
||||
}
|
||||
|
||||
ignoredStatuses := []string{"offline", "icp_checking", "icp_check_failed", "locking", "locked"}
|
||||
for _, domainItem := range getCdnDomainsResp.Domains {
|
||||
if lo.Contains(ignoredStatuses, domainItem.DomainStatus) {
|
||||
continue
|
||||
}
|
||||
|
||||
domains = append(domains, domainItem)
|
||||
}
|
||||
|
||||
if len(getCdnDomainsResp.Domains) < getCdnDomainsPageSize {
|
||||
break
|
||||
}
|
||||
|
||||
getCdnDomainsPageNumber++
|
||||
}
|
||||
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) updateDomainCertificate(ctx context.Context, cloudDomainId string, certPEM, privkeyPEM string) error {
|
||||
// 为加速域名配置证书接口
|
||||
// REF: https://docs.ksyun.com/documents/261
|
||||
configCertificateReq := &ksyuncdnsdk.ConfigCertificateRequest{
|
||||
Enable: lo.ToPtr("on"),
|
||||
DomainIds: lo.ToPtr(cloudDomainId),
|
||||
CertificateName: lo.ToPtr(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
||||
ServerCertificate: lo.ToPtr(certPEM),
|
||||
PrivateKey: lo.ToPtr(privkeyPEM),
|
||||
}
|
||||
configCertificateResp, err := d.sdkClient.ConfigCertificateWithContext(ctx, configCertificateReq)
|
||||
d.logger.Debug("sdk request 'cdn.ConfigCertificate'", slog.Any("request", configCertificateReq), slog.Any("response", configCertificateResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'cdn.ConfigCertificate': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, secretAccessKey string) (*ksyuncdnsdk.Client, error) {
|
||||
client, err := ksyuncdnsdk.NewClient(
|
||||
ksyuncdnsdk.WithAkSk(accessKeyId, secretAccessKey),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package ksyunkcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/ksyun-kcm"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 金山云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 金山云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkCertmgr core.Certmgr
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
d.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
// 上传证书
|
||||
upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package ksyunslb
|
||||
|
||||
const (
|
||||
// 部署目标:替换指定证书。
|
||||
DEPLOY_TARGET_CERTIFICATE = "certificate"
|
||||
)
|
||||
@@ -1,102 +0,0 @@
|
||||
package ksyunslb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/ksyun-slb"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 金山云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 金山云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 金山云项目 ID。
|
||||
ProjectId int64 `json:"projectId,omitempty"`
|
||||
// 金山云地域。
|
||||
Region string `json:"region"`
|
||||
// 部署目标。
|
||||
DeployTarget string `json:"deployTarget"`
|
||||
// 证书 ID。
|
||||
// 部署目标为 [DEPLOY_TARGET_CERTIFICATE] 时必填。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkCertmgr core.Certmgr
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
ProjectId: config.ProjectId,
|
||||
Region: config.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
d.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
// 根据部署目标决定业务流程
|
||||
switch d.config.DeployTarget {
|
||||
case DEPLOY_TARGET_CERTIFICATE:
|
||||
if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported deploy target '%s'", d.config.DeployTarget)
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) deployToCertificate(ctx context.Context, certPEM, privkeyPEM string) error {
|
||||
if d.config.CertificateId == "" {
|
||||
return fmt.Errorf("config `certificateId` is required")
|
||||
}
|
||||
|
||||
// 替换证书
|
||||
rplres, err := d.sdkCertmgr.Replace(ctx, d.config.CertificateId, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to replace certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate replaced", slog.Any("result", rplres))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package wangsucdn
|
||||
|
||||
const (
|
||||
// 匹配模式:精确匹配。
|
||||
DOMAIN_MATCH_PATTERN_EXACT = "exact"
|
||||
)
|
||||
@@ -1,139 +0,0 @@
|
||||
package wangsucdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/wangsu-certificate"
|
||||
wangsucdn "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/cdn"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 网宿云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 网宿云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 域名匹配模式。暂时只支持精确匹配。
|
||||
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
|
||||
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
|
||||
// 加速域名数组(支持泛域名)。
|
||||
Domains []string `json:"domains"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *wangsucdn.Client
|
||||
sdkCertmgr core.Certmgr
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.AccessKeyId, config.AccessKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
AccessKeySecret: config.AccessKeySecret,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
d.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
// 上传证书
|
||||
upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 获取待部署的域名列表
|
||||
domains := make([]string, 0)
|
||||
switch d.config.DomainMatchPattern {
|
||||
case "", DOMAIN_MATCH_PATTERN_EXACT:
|
||||
{
|
||||
if len(d.config.Domains) == 0 {
|
||||
return nil, fmt.Errorf("config `domains` is required")
|
||||
}
|
||||
|
||||
domains = lo.Map(d.config.Domains, func(domain string, _ int) string {
|
||||
return normalizeDomain(domain)
|
||||
})
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported domain match pattern: '%s'", d.config.DomainMatchPattern)
|
||||
}
|
||||
|
||||
// 批量修改域名证书配置
|
||||
// REF: https://www.wangsu.com/document/api-doc/37447
|
||||
certIdAsInt, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
||||
batchUpdateCertificateConfigReq := &wangsucdn.BatchUpdateCertificateConfigRequest{
|
||||
CertificateId: certIdAsInt,
|
||||
DomainNames: domains,
|
||||
}
|
||||
batchUpdateCertificateConfigResp, err := d.sdkClient.BatchUpdateCertificateConfigWithContext(ctx, 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 &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, accessKeySecret string) (*wangsucdn.Client, error) {
|
||||
client, err := wangsucdn.NewClient(
|
||||
wangsucdn.WithAkSk(accessKeyId, accessKeySecret),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func normalizeDomain(domain string) string {
|
||||
// "*.example.com" → ".example.com",适配网宿云 CDN 的泛域名参数要求
|
||||
if strings.HasPrefix(domain, "*.") {
|
||||
return strings.TrimPrefix(domain, "*")
|
||||
}
|
||||
return domain
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package wangsucdnpro
|
||||
|
||||
const (
|
||||
// 匹配模式:精确匹配。
|
||||
DOMAIN_MATCH_PATTERN_EXACT = "exact"
|
||||
)
|
||||
@@ -1,273 +0,0 @@
|
||||
package wangsucdnpro
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
wangsucdnpro "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/cdnpro"
|
||||
xwait "github.com/certimate-go/certimate/pkg/utils/wait"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 网宿云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 网宿云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 网宿云 API Key。
|
||||
ApiKey string `json:"apiKey"`
|
||||
// 网宿云环境。
|
||||
Environment string `json:"environment"`
|
||||
// 域名匹配模式。暂时只支持精确匹配。
|
||||
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
|
||||
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
// 证书 ID。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
// Webhook ID。
|
||||
// 选填。
|
||||
WebhookId string `json:"webhookId,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *wangsucdnpro.Client
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.AccessKeyId, config.AccessKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
if d.config.Domain == "" {
|
||||
return nil, fmt.Errorf("config `domain` is required")
|
||||
}
|
||||
|
||||
// 查询已部署加速域名的详情
|
||||
getHostnameDetailResp, err := d.sdkClient.GetHostnameDetailWithContext(ctx, d.config.Domain)
|
||||
d.logger.Debug("sdk request 'cdnpro.GetHostnameDetail'", slog.String("params.hostname", d.config.Domain), slog.Any("response", getHostnameDetailResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.GetHostnameDetail': %w", err)
|
||||
}
|
||||
|
||||
// 生成网宿云证书参数
|
||||
encryptedPrivateKey, err := encryptPrivateKey(privkeyPEM, d.config.ApiKey, time.Now().Unix())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt private key: %w", err)
|
||||
}
|
||||
certificateNewVersionInfo := &wangsucdnpro.CertificateVersion{
|
||||
PrivateKey: lo.ToPtr(encryptedPrivateKey),
|
||||
Certificate: lo.ToPtr(certPEM),
|
||||
}
|
||||
|
||||
// 网宿云证书 URL 中包含证书 ID 及版本号
|
||||
// 格式:
|
||||
// http://open.chinanetcenter.com/cdn/certificates/5dca2205f9e9cc0001df7b33
|
||||
// http://open.chinanetcenter.com/cdn/certificates/329f12c1fe6708c23c31e91f/versions/5
|
||||
var wangsuCertUrl string
|
||||
var wangsuCertId string
|
||||
var wangsuCertVer int32
|
||||
|
||||
// 如果原证书 ID 为空,则创建证书;否则更新证书。
|
||||
timestamp := time.Now().Unix()
|
||||
if d.config.CertificateId == "" {
|
||||
// 创建证书
|
||||
createCertificateReq := &wangsucdnpro.CreateCertificateRequest{
|
||||
Timestamp: timestamp,
|
||||
Name: lo.ToPtr(fmt.Sprintf("certimate_%d", time.Now().UnixMilli())),
|
||||
AutoRenew: lo.ToPtr("Off"),
|
||||
NewVersion: certificateNewVersionInfo,
|
||||
}
|
||||
createCertificateResp, err := d.sdkClient.CreateCertificateWithContext(ctx, createCertificateReq)
|
||||
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 'cdnpro.CreateCertificate': %w", err)
|
||||
}
|
||||
|
||||
wangsuCertUrl = createCertificateResp.CertificateLocation
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("certUrl", wangsuCertUrl))
|
||||
|
||||
wangsuCertIdMatches := regexp.MustCompile(`/certificates/([a-zA-Z0-9-]+)`).FindStringSubmatch(wangsuCertUrl)
|
||||
if len(wangsuCertIdMatches) > 1 {
|
||||
wangsuCertId = wangsuCertIdMatches[1]
|
||||
}
|
||||
|
||||
wangsuCertVer = 1
|
||||
} else {
|
||||
// 更新证书
|
||||
updateCertificateReq := &wangsucdnpro.UpdateCertificateRequest{
|
||||
Timestamp: timestamp,
|
||||
Name: lo.ToPtr(fmt.Sprintf("certimate_%d", time.Now().UnixMilli())),
|
||||
AutoRenew: lo.ToPtr("Off"),
|
||||
NewVersion: certificateNewVersionInfo,
|
||||
}
|
||||
updateCertificateResp, err := d.sdkClient.UpdateCertificateWithContext(ctx, d.config.CertificateId, updateCertificateReq)
|
||||
d.logger.Debug("sdk request 'cdnpro.UpdateCertificate'", slog.String("params.certificateId", d.config.CertificateId), slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.UpdateCertificate': %w", err)
|
||||
}
|
||||
|
||||
wangsuCertUrl = updateCertificateResp.CertificateLocation
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("certUrl", wangsuCertUrl))
|
||||
|
||||
wangsuCertIdMatches := regexp.MustCompile(`/certificates/([a-zA-Z0-9-]+)`).FindStringSubmatch(wangsuCertUrl)
|
||||
if len(wangsuCertIdMatches) > 1 {
|
||||
wangsuCertId = wangsuCertIdMatches[1]
|
||||
}
|
||||
|
||||
wangsuCertVerMatches := regexp.MustCompile(`/versions/(\d+)`).FindStringSubmatch(wangsuCertUrl)
|
||||
if len(wangsuCertVerMatches) > 1 {
|
||||
n, _ := strconv.ParseInt(wangsuCertVerMatches[1], 10, 32)
|
||||
wangsuCertVer = int32(n)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建部署任务
|
||||
// REF: https://www.wangsu.com/document/api-doc/27034
|
||||
var wangsuTaskId string
|
||||
createDeploymentTaskReq := &wangsucdnpro.CreateDeploymentTaskRequest{
|
||||
Name: lo.ToPtr(fmt.Sprintf("certimate_%d", time.Now().UnixMilli())),
|
||||
Target: lo.ToPtr(d.config.Environment),
|
||||
Actions: &[]wangsucdnpro.DeploymentTaskAction{
|
||||
{
|
||||
Action: lo.ToPtr("deploy_cert"),
|
||||
CertificateId: lo.ToPtr(wangsuCertId),
|
||||
Version: lo.ToPtr(wangsuCertVer),
|
||||
},
|
||||
},
|
||||
Webhook: lo.EmptyableToPtr(d.config.WebhookId),
|
||||
}
|
||||
createDeploymentTaskResp, err := d.sdkClient.CreateDeploymentTaskWithContext(ctx, createDeploymentTaskReq)
|
||||
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 'cdnpro.CreateDeploymentTask': %w", err)
|
||||
} else {
|
||||
wangsuTaskMatches := regexp.MustCompile(`/deploymentTasks/([a-zA-Z0-9-]+)`).FindStringSubmatch(createDeploymentTaskResp.DeploymentTaskLocation)
|
||||
if len(wangsuTaskMatches) > 1 {
|
||||
wangsuTaskId = wangsuTaskMatches[1]
|
||||
}
|
||||
}
|
||||
|
||||
// 获取部署任务详细信息,等待任务状态变更
|
||||
// REF: https://www.wangsu.com/document/api-doc/27038
|
||||
if _, err := xwait.UntilWithContext(ctx, func(_ context.Context, _ int) (bool, error) {
|
||||
getDeploymentTaskDetailResp, err := d.sdkClient.GetDeploymentTaskDetailWithContext(ctx, wangsuTaskId)
|
||||
d.logger.Info("sdk request 'cdnpro.GetDeploymentTaskDetail'", slog.String("params.taskId", wangsuTaskId), slog.Any("response", getDeploymentTaskDetailResp))
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to execute sdk request 'cdnpro.GetDeploymentTaskDetail': %w", err)
|
||||
}
|
||||
|
||||
if getDeploymentTaskDetailResp.Status == "failed" {
|
||||
return false, fmt.Errorf("unexpected deployment task status")
|
||||
} else if getDeploymentTaskDetailResp.Status == "succeeded" || getDeploymentTaskDetailResp.FinishTime != "" {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
d.logger.Info(fmt.Sprintf("waiting for deployment task completion (current status: %s) ...", getDeploymentTaskDetailResp.Status))
|
||||
return false, nil
|
||||
}, 10*time.Second); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, accessKeySecret string) (*wangsucdnpro.Client, error) {
|
||||
client, err := wangsucdnpro.NewClient(
|
||||
wangsucdnpro.WithAkSk(accessKeyId, accessKeySecret),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func encryptPrivateKey(privkeyPEM string, apiKey string, timestamp int64) (string, error) {
|
||||
date := time.Unix(timestamp, 0).UTC()
|
||||
dateStr := date.Format(http.TimeFormat)
|
||||
|
||||
h := hmac.New(sha256.New, []byte(apiKey))
|
||||
h.Write([]byte(dateStr))
|
||||
aesivkey := h.Sum(nil)
|
||||
aesivkeyHex := hex.EncodeToString(aesivkey)
|
||||
|
||||
if len(aesivkeyHex) != 64 {
|
||||
return "", fmt.Errorf("invalid hmac length: %d", len(aesivkeyHex))
|
||||
}
|
||||
ivHex := aesivkeyHex[:32]
|
||||
keyHex := aesivkeyHex[32:64]
|
||||
|
||||
iv, err := hex.DecodeString(ivHex)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to decode iv: %w", err)
|
||||
}
|
||||
|
||||
key, err := hex.DecodeString(keyHex)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to decode key: %w", err)
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
plainBytes := []byte(privkeyPEM)
|
||||
padlen := aes.BlockSize - len(plainBytes)%aes.BlockSize
|
||||
if padlen > 0 {
|
||||
paddata := bytes.Repeat([]byte{byte(padlen)}, padlen)
|
||||
plainBytes = append(plainBytes, paddata...)
|
||||
}
|
||||
|
||||
encBytes := make([]byte, len(plainBytes))
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encBytes, plainBytes)
|
||||
|
||||
return base64.StdEncoding.EncodeToString(encBytes), nil
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package wangsucertificate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/wangsu-certificate"
|
||||
wangsucertificate "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/certificate"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 网宿云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 网宿云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 证书 ID。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *wangsucertificate.Client
|
||||
sdkCertmgr core.Certmgr
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.AccessKeyId, config.AccessKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
AccessKeySecret: config.AccessKeySecret,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
d.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
if d.config.CertificateId == "" {
|
||||
// 上传证书
|
||||
upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
} else {
|
||||
// 替换证书
|
||||
rplres, err := d.sdkCertmgr.Replace(ctx, d.config.CertificateId, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to replace certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate replaced", slog.Any("result", rplres))
|
||||
}
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, accessKeySecret string) (*wangsucertificate.Client, error) {
|
||||
client, err := wangsucertificate.NewClient(
|
||||
wangsucertificate.WithAkSk(accessKeyId, accessKeySecret),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package baishan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type GetDomainConfigRequest struct {
|
||||
Domains *string `json:"domains,omitempty" url:"domains,omitempty"`
|
||||
Config []*string `json:"config,omitempty" url:"config,omitempty"`
|
||||
}
|
||||
|
||||
type GetDomainConfigResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Data []*struct {
|
||||
Domain string `json:"domain"`
|
||||
Config *DomainConfig `json:"config"`
|
||||
} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) GetDomainConfig(req *GetDomainConfigRequest) (*GetDomainConfigResponse, error) {
|
||||
return c.GetDomainConfigWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) GetDomainConfigWithContext(ctx context.Context, req *GetDomainConfigRequest) (*GetDomainConfigResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodGet, "/v2/domain/config")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if req.Domains != nil {
|
||||
httpreq.SetQueryParam("domains", *req.Domains)
|
||||
}
|
||||
if req.Config != nil {
|
||||
for _, config := range req.Config {
|
||||
if config != nil {
|
||||
httpreq.QueryParam.Add("config[]", *config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &GetDomainConfigResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package baishan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
qs "github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type GetDomainListRequest struct {
|
||||
PageNumber *int32 `json:"page_number,omitempty" url:"page_number,omitempty"`
|
||||
PageSize *int32 `json:"page_size,omitempty" url:"page_size,omitempty"`
|
||||
DomainStatus *string `json:"domain_status,omitempty" url:"domain_status,omitempty"`
|
||||
}
|
||||
|
||||
type GetDomainListResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Data []*struct {
|
||||
List []*Domain `json:"list"`
|
||||
PageNumber json.Number `json:"page_number"`
|
||||
PageSize json.Number `json:"page_size"`
|
||||
TotalNumber json.Number `json:"total_number"`
|
||||
} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) GetDomainList(req *GetDomainListRequest) (*GetDomainListResponse, error) {
|
||||
return c.GetDomainListWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) GetDomainListWithContext(ctx context.Context, req *GetDomainListRequest) (*GetDomainListResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodGet, "/v2/domain/list")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
values, err := qs.Values(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpreq.SetQueryParamsFromValues(values)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &GetDomainListResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package baishan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type SetDomainConfigRequest struct {
|
||||
Domains *string `json:"domains,omitempty"`
|
||||
Config *DomainConfig `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
type SetDomainConfigResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Data *struct {
|
||||
Config *DomainConfig `json:"config"`
|
||||
} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) SetDomainConfig(req *SetDomainConfigRequest) (*SetDomainConfigResponse, error) {
|
||||
return c.SetDomainConfigWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) SetDomainConfigWithContext(ctx context.Context, req *SetDomainConfigRequest) (*SetDomainConfigResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/v2/domain/config")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &SetDomainConfigResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package baishan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type UploadDomainCertificateRequest struct {
|
||||
CertificateId *string `json:"cert_id,omitempty"`
|
||||
Certificate *string `json:"certificate,omitempty"`
|
||||
Key *string `json:"key,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type UploadDomainCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Data *DomainCertificate `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) UploadDomainCertificate(req *UploadDomainCertificateRequest) (*UploadDomainCertificateResponse, error) {
|
||||
return c.UploadDomainCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) UploadDomainCertificateWithContext(ctx context.Context, req *UploadDomainCertificateRequest) (*UploadDomainCertificateResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/v2/domain/certificate")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &UploadDomainCertificateResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// A simple SDK client for BaishanCloud.
|
||||
// API documentation: https://portal.baishancloud.com/track/document/api/1/1249
|
||||
package baishan
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/app"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
rc *resty.Client
|
||||
}
|
||||
|
||||
func NewClient(optFns ...OptionsFunc) (*Client, error) {
|
||||
opts := &Options{}
|
||||
for _, fn := range optFns {
|
||||
fn(opts)
|
||||
}
|
||||
|
||||
if opts.ApiToken == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset apiToken")
|
||||
}
|
||||
|
||||
httper := resty.New().
|
||||
SetBaseURL("https://cdn.api.baishan.com").
|
||||
SetHeader("Accept", "application/json").
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("User-Agent", app.AppUserAgent).
|
||||
SetQueryParam("token", opts.ApiToken)
|
||||
|
||||
return &Client{rc: httper}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.rc.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method string, path string) (*resty.Request, error) {
|
||||
if method == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset method")
|
||||
}
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset path")
|
||||
}
|
||||
|
||||
req := c.rc.R()
|
||||
req.Method = method
|
||||
req.URL = path
|
||||
|
||||
// WARN:
|
||||
// DO NOT CALL `req.SetResult` or `req.SetError` AGAIN! USE `doRequestWithResult` INSTEAD.
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := req.Send()
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to send request: %w", err)
|
||||
} else if resp.IsError() {
|
||||
return resp, fmt.Errorf("sdkerr: unexpected status code: %d (resp: %s)", resp.StatusCode(), resp.String())
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := c.doRequest(req)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
json.Unmarshal(resp.Body(), &res)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if len(resp.Body()) != 0 {
|
||||
if err := json.Unmarshal(resp.Body(), &res); err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to unmarshal response: %w (resp: %s)", err, resp.String())
|
||||
} else {
|
||||
if rCode := res.GetCode(); rCode != 0 {
|
||||
return resp, fmt.Errorf("sdkerr: api error: code='%d', message='%s'", rCode, res.GetMessage())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package baishan
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Domain struct {
|
||||
Id string `json:"id"`
|
||||
Domain string `json:"domain"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Cname string `json:"cname"`
|
||||
Area string `json:"area"`
|
||||
CreateTime string `json:"create_time"`
|
||||
UpdateTime string `json:"update_time"`
|
||||
}
|
||||
|
||||
type DomainCertificate struct {
|
||||
CertId json.Number `json:"cert_id"`
|
||||
Name string `json:"name"`
|
||||
CertStartTime string `json:"cert_start_time"`
|
||||
CertExpireTime string `json:"cert_expire_time"`
|
||||
}
|
||||
|
||||
type DomainConfig struct {
|
||||
Https *DomainConfigHttps `json:"https"`
|
||||
}
|
||||
|
||||
type DomainConfigHttps struct {
|
||||
CertId json.Number `json:"cert_id"`
|
||||
ForceHttps *string `json:"force_https,omitempty"`
|
||||
EnableHttp2 *string `json:"http2,omitempty"`
|
||||
EnableOcsp *string `json:"ocsp,omitempty"`
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package baishan
|
||||
|
||||
type Options struct {
|
||||
ApiToken string
|
||||
}
|
||||
|
||||
type OptionsFunc func(*Options)
|
||||
|
||||
func WithApiToken(apiToken string) OptionsFunc {
|
||||
return func(o *Options) {
|
||||
o.ApiToken = apiToken
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package baishan
|
||||
|
||||
type sdkResponse interface {
|
||||
GetCode() int
|
||||
GetMessage() string
|
||||
}
|
||||
|
||||
type sdkResponseBase struct {
|
||||
Code *int `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetCode() int {
|
||||
if r.Code == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return *r.Code
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetMessage() string {
|
||||
if r.Message == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *r.Message
|
||||
}
|
||||
|
||||
var _ sdkResponse = (*sdkResponseBase)(nil)
|
||||
@@ -1,5 +0,0 @@
|
||||
本模块存在相应的官方 SDK:`github.com/KscSDK/ksc-sdk-go/service/cdnv1`。
|
||||
|
||||
但会使得依赖体积显著膨胀,故没有使用。
|
||||
|
||||
具体细节见 [PR #1341](https://github.com/certimate-go/certimate/pull/1341)。
|
||||
@@ -1,51 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ConfigCertificateRequest struct {
|
||||
Enable *string `json:"Enable,omitempty"`
|
||||
DomainIds *string `json:"DomainIds,omitempty"`
|
||||
CertificateId *string `json:"CertificateId,omitempty"`
|
||||
CertificateName *string `json:"CertificateName,omitempty"`
|
||||
ServerCertificate *string `json:"ServerCertificate,omitempty"`
|
||||
PrivateKey *string `json:"PrivateKey,omitempty"`
|
||||
}
|
||||
|
||||
type ConfigCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
CertificateId string `json:"CertificateId,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) ConfigCertificate(req *ConfigCertificateRequest) (*ConfigCertificateResponse, error) {
|
||||
return c.ConfigCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) ConfigCertificateWithContext(ctx context.Context, req *ConfigCertificateRequest) (*ConfigCertificateResponse, error) {
|
||||
params := &struct {
|
||||
ConfigCertificateRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
ConfigCertificateRequest: *req,
|
||||
Action: "ConfigCertificate",
|
||||
Version: "2016-09-01",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/2016-09-01/cert/ConfigCertificate", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &ConfigCertificateResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type GetCDNDomainsRequest struct {
|
||||
ProjectId *int64 `json:"ProjectId,omitempty"`
|
||||
DomainName *string `json:"DomainName,omitempty"`
|
||||
DomainStatus *string `json:"DomainStatus,omitempty"`
|
||||
FuzzyMatch *bool `json:"FuzzyMatch,omitempty"`
|
||||
CdnType *bool `json:"CdnType,omitempty"`
|
||||
PageNumber *int32 `json:"PageNumber,omitempty"`
|
||||
PageSize *int32 `json:"PageSize,omitempty"`
|
||||
}
|
||||
|
||||
type GetCdnDomainsResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Domains []*CDNDomain `json:"Domains"`
|
||||
PageNumber int32 `json:"PageNumber,omitempty"`
|
||||
PageSize int32 `json:"PageSize,omitempty"`
|
||||
TotalCount int32 `json:"TotalCount,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) GetCDNDomains(req *GetCDNDomainsRequest) (*GetCdnDomainsResponse, error) {
|
||||
return c.GetCDNDomainsWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) GetCDNDomainsWithContext(ctx context.Context, req *GetCDNDomainsRequest) (*GetCdnDomainsResponse, error) {
|
||||
params := &struct {
|
||||
GetCDNDomainsRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
GetCDNDomainsRequest: *req,
|
||||
Action: "GetCdnDomains",
|
||||
Version: "2019-06-01",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodGet, "/2019-06-01/GetCdnDomains", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &GetCdnDomainsResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type SetCertificateRequest struct {
|
||||
CertificateId *string `json:"CertificateId,omitempty"`
|
||||
CertificateName *string `json:"CertificateName,omitempty"`
|
||||
ServerCertificate *string `json:"ServerCertificate,omitempty"`
|
||||
PrivateKey *string `json:"PrivateKey,omitempty"`
|
||||
}
|
||||
|
||||
type SetCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
CertificateId string `json:"CertificateId,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) SetCertificate(req *SetCertificateRequest) (*SetCertificateResponse, error) {
|
||||
return c.SetCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) SetCertificateWithContext(ctx context.Context, req *SetCertificateRequest) (*SetCertificateResponse, error) {
|
||||
params := &struct {
|
||||
SetCertificateRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
SetCertificateRequest: *req,
|
||||
Action: "SetCertificate",
|
||||
Version: "2016-09-01",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/2016-09-01/cert/SetCertificate", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &SetCertificateResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// A simple SDK client for KingsoftCloud CDN.
|
||||
// API documentation: https://apiexplorer.ksyun.com/#/api/home
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/ksyun/zz-shared-common"
|
||||
)
|
||||
|
||||
const (
|
||||
service = "cdn"
|
||||
endpoint = "https://" + service + ".api.ksyun.com"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *common.Client
|
||||
}
|
||||
|
||||
func NewClient(optFns ...common.OptionsFunc) (*Client, error) {
|
||||
client, err := common.NewClient(endpoint, service, optFns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{client: client}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.client.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method string, path string, params any) (*resty.Request, error) {
|
||||
return c.client.NewRequest(method, path, params)
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
|
||||
return c.client.DoRequest(req)
|
||||
}
|
||||
|
||||
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
|
||||
resp, err := c.client.DoRequestWithResult(req, res)
|
||||
if err == nil {
|
||||
if err := res.GetAPIError(); err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: api error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package cdn
|
||||
|
||||
type CDNDomain struct {
|
||||
Region string `json:"Region"`
|
||||
DomainId string `json:"DomainId"`
|
||||
DomainName string `json:"DomainName"`
|
||||
Description string `json:"Description"`
|
||||
Cname string `json:"Cname"`
|
||||
CdnType string `json:"CdnType"`
|
||||
CdnSubType string `json:"CdnSubType"`
|
||||
DomainStatus string `json:"DomainStatus"`
|
||||
CreatedTime string `json:"CreatedTime"`
|
||||
ModifiedTime string `json:"ModifiedTime"`
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/ksyun/zz-shared-common"
|
||||
)
|
||||
|
||||
func WithAkSk(ak, sk string) common.OptionsFunc {
|
||||
return common.WithAkSk(ak, sk)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type sdkResponse interface {
|
||||
GetAPIError() error
|
||||
}
|
||||
|
||||
type sdkResponseBase struct {
|
||||
RequestId *string `json:"RequestId,omitempty"`
|
||||
Error *sdkAPIError `json:"Error,omitempty"`
|
||||
}
|
||||
|
||||
type sdkAPIError struct {
|
||||
Type string `json:"Type,omitempty"`
|
||||
Code string `json:"Code"`
|
||||
Message string `json:"Message"`
|
||||
}
|
||||
|
||||
func (e sdkAPIError) Error() string {
|
||||
if e.Type == "" {
|
||||
return fmt.Sprintf("[%s] %s ", e.Code, e.Message)
|
||||
}
|
||||
return fmt.Sprintf("[%s_%s] %s ", e.Type, e.Code, e.Message)
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetAPIError() error {
|
||||
if r.Error != nil {
|
||||
return r.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ sdkResponse = (*sdkResponseBase)(nil)
|
||||
@@ -1,5 +0,0 @@
|
||||
本模块存在相应的官方 SDK:`github.com/KscSDK/ksc-sdk-go/service/kcm`。
|
||||
|
||||
但会使得依赖体积显著膨胀,故没有使用。
|
||||
|
||||
具体细节见 [PR #1341](https://github.com/certimate-go/certimate/pull/1341)。
|
||||
@@ -1,61 +0,0 @@
|
||||
package kcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
qs "github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type CreateCertificateRequest struct {
|
||||
Region *string `json:"Region,omitempty" url:"Region,omitempty"`
|
||||
CertificateName *string `json:"CertificateName,omitempty" url:"CertificateName,omitempty"`
|
||||
Description *string `json:"Description,omitempty" url:"Description,omitempty"`
|
||||
PublicKey *string `json:"PublicKey,omitempty" url:"-"`
|
||||
PrivateKey *string `json:"PrivateKey,omitempty" url:"-"`
|
||||
CertificateType *string `json:"CertificateType,omitempty" url:"CertificateType,omitempty"`
|
||||
Source *string `json:"Source,omitempty" url:"Source,omitempty"`
|
||||
SSLCertificateId *string `json:"SslCertificateId,omitempty" url:"SslCertificateId,omitempty"`
|
||||
}
|
||||
|
||||
type CreateCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Certificate *LBCertificate `json:"Certificate,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||
return c.CreateCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) CreateCertificateWithContext(ctx context.Context, req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||
params := &struct {
|
||||
CreateCertificateRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
CreateCertificateRequest: *req,
|
||||
Action: "CreateCertificate",
|
||||
Version: "2016-03-04",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
values, err := qs.Values(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpreq.SetQueryParamsFromValues(values)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &CreateCertificateResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package kcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type DescribeCertificatesRequest struct {
|
||||
Region *string `json:"Region,omitempty"`
|
||||
Page *int32 `json:"Page,omitempty"`
|
||||
PageSize *int32 `json:"PageSize,omitempty"`
|
||||
}
|
||||
|
||||
type DescribeCertificatesResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
CertificateSet []*LBCertificate `json:"CertificateSet"`
|
||||
}
|
||||
|
||||
func (c *Client) DescribeCertificates(req *DescribeCertificatesRequest) (*DescribeCertificatesResponse, error) {
|
||||
return c.DescribeCertificatesWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) DescribeCertificatesWithContext(ctx context.Context, req *DescribeCertificatesRequest) (*DescribeCertificatesResponse, error) {
|
||||
params := &struct {
|
||||
DescribeCertificatesRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
DescribeCertificatesRequest: *req,
|
||||
Action: "DescribeCertificates",
|
||||
Version: "2016-03-04",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodGet, "/", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &DescribeCertificatesResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package kcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ListUserCertificatesRequest struct {
|
||||
Page *int32 `json:"Page,omitempty"`
|
||||
PageSize *int32 `json:"PageSize,omitempty"`
|
||||
}
|
||||
|
||||
type ListUserCertificatesResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Success bool `json:"Success"`
|
||||
Ret *struct {
|
||||
Certs []*UserCertificate `json:"Certs"`
|
||||
} `json:"Ret,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) ListUserCertificates(req *ListUserCertificatesRequest) (*ListUserCertificatesResponse, error) {
|
||||
return c.ListUserCertificatesWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) ListUserCertificatesWithContext(ctx context.Context, req *ListUserCertificatesRequest) (*ListUserCertificatesResponse, error) {
|
||||
params := &struct {
|
||||
ListUserCertificatesRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
ListUserCertificatesRequest: *req,
|
||||
Action: "ListUserCertificates",
|
||||
Version: "2016-03-04",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodGet, "/", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &ListUserCertificatesResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package kcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
qs "github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type ModifyCertificateRequest struct {
|
||||
Region *string `json:"Region,omitempty" url:"Region,omitempty"`
|
||||
CertificateId *string `json:"CertificateId,omitempty" url:"CertificateId,omitempty"`
|
||||
CertificateName *string `json:"CertificateName,omitempty" url:"CertificateName,omitempty"`
|
||||
Description *string `json:"Description,omitempty" url:"Description,omitempty"`
|
||||
PublicKey *string `json:"PublicKey,omitempty" url:"-"`
|
||||
PrivateKey *string `json:"PrivateKey,omitempty" url:"-"`
|
||||
SSLCertificateId *string `json:"SslCertificateId,omitempty" url:"SslCertificateId,omitempty"`
|
||||
}
|
||||
|
||||
type ModifyCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Certificate *LBCertificate `json:"Certificate,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) ModifyCertificate(req *ModifyCertificateRequest) (*ModifyCertificateResponse, error) {
|
||||
return c.ModifyCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) ModifyCertificateWithContext(ctx context.Context, req *ModifyCertificateRequest) (*ModifyCertificateResponse, error) {
|
||||
params := &struct {
|
||||
ModifyCertificateRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
ModifyCertificateRequest: *req,
|
||||
Action: "ModifyCertificate",
|
||||
Version: "2016-03-04",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
values, err := qs.Values(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpreq.SetQueryParamsFromValues(values)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &ModifyCertificateResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package kcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type UploadCertificateRequest struct {
|
||||
ProjectId *int64 `json:"ProjectId,omitempty"`
|
||||
CertName *string `json:"CertName,omitempty"`
|
||||
CertFile *string `json:"CertFile,omitempty"`
|
||||
CertKey *string `json:"CertKey,omitempty"`
|
||||
}
|
||||
|
||||
type UploadCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Success bool `json:"Success"`
|
||||
Ret *UserCertificate `json:"Ret,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) UploadCertificate(req *UploadCertificateRequest) (*UploadCertificateResponse, error) {
|
||||
return c.UploadCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) UploadCertificateWithContext(ctx context.Context, req *UploadCertificateRequest) (*UploadCertificateResponse, error) {
|
||||
params := &struct {
|
||||
UploadCertificateRequest `json:",inline"`
|
||||
Action string
|
||||
Version string
|
||||
}{
|
||||
UploadCertificateRequest: *req,
|
||||
Action: "UploadCertificate",
|
||||
Version: "2016-03-04",
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &UploadCertificateResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// A simple SDK client for KingsoftCloud KCM.
|
||||
// API documentation: https://apiexplorer.ksyun.com/#/api/home
|
||||
package kcm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/ksyun/zz-shared-common"
|
||||
)
|
||||
|
||||
const (
|
||||
service = "kcm"
|
||||
endpoint = "https://" + service + ".api.ksyun.com"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *common.Client
|
||||
}
|
||||
|
||||
func NewClient(optFns ...common.OptionsFunc) (*Client, error) {
|
||||
client, err := common.NewClient(endpoint, service, optFns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{client: client}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.client.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method string, path string, params any) (*resty.Request, error) {
|
||||
return c.client.NewRequest(method, path, params)
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
|
||||
return c.client.DoRequest(req)
|
||||
}
|
||||
|
||||
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
|
||||
resp, err := c.client.DoRequestWithResult(req, res)
|
||||
if err == nil {
|
||||
if err := res.GetAPIError(); err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: api error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package kcm
|
||||
|
||||
type UserCertificate struct {
|
||||
CertId string `json:"CertID"`
|
||||
CertName string `json:"CertName"`
|
||||
MainDomain string `json:"MainDomain"`
|
||||
Domains []string `json:"Domains"`
|
||||
AdditionalDomains []string `json:"AdditionalDomains"`
|
||||
Brand string `json:"Brand"`
|
||||
CA string `json:"CA"`
|
||||
Level string `json:"Level"`
|
||||
FingerPrint string `json:"FingerPrint"`
|
||||
DomainCount int32 `json:"DomainCount"`
|
||||
WildcardCount int32 `json:"WildcardCount"`
|
||||
IssueTime string `json:"IssueTime"`
|
||||
ExpireTime string `json:"ExpireTime"`
|
||||
Source string `json:"Source"`
|
||||
}
|
||||
|
||||
type LBCertificate struct {
|
||||
CertificateId string `json:"CertificateId"`
|
||||
CertificateName string `json:"CertificateName"`
|
||||
CommonName string `json:"CommonName"`
|
||||
CertAuthority string `json:"CertAuthority"`
|
||||
CertType string `json:"CertType"`
|
||||
CertificateType string `json:"CertificateType"`
|
||||
PublicKey string `json:"PublicKey"`
|
||||
ExpireTime string `json:"ExpireTime"`
|
||||
CreateTime string `json:"CreateTime"`
|
||||
Source string `json:"Source"`
|
||||
SSLCertificateId string `json:"SslCertificateId,omitempty"`
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package kcm
|
||||
|
||||
import (
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/ksyun/zz-shared-common"
|
||||
)
|
||||
|
||||
func WithAkSk(ak, sk string) common.OptionsFunc {
|
||||
return common.WithAkSk(ak, sk)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package kcm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type sdkResponse interface {
|
||||
GetAPIError() error
|
||||
}
|
||||
|
||||
type sdkResponseBase struct {
|
||||
RequestId *string `json:"RequestId,omitempty"`
|
||||
Error *sdkAPIError `json:"Error,omitempty"`
|
||||
}
|
||||
|
||||
type sdkAPIError struct {
|
||||
Code string `json:"Code"`
|
||||
Message string `json:"Message"`
|
||||
}
|
||||
|
||||
func (e sdkAPIError) Error() string {
|
||||
return fmt.Sprintf("[%s] %s ", e.Code, e.Message)
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetAPIError() error {
|
||||
if r.Error != nil {
|
||||
return r.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ sdkResponse = (*sdkResponseBase)(nil)
|
||||
@@ -1,147 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/app"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
rc *resty.Client
|
||||
}
|
||||
|
||||
func NewClient(baseUrl string, service string, optFns ...OptionsFunc) (*Client, error) {
|
||||
options := &Options{}
|
||||
for _, fn := range optFns {
|
||||
fn(options)
|
||||
}
|
||||
|
||||
if baseUrl == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset baseUrl")
|
||||
}
|
||||
if _, err := url.Parse(baseUrl); err != nil {
|
||||
return nil, fmt.Errorf("sdkerr: invalid baseUrl: %w", err)
|
||||
}
|
||||
if service == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset service")
|
||||
}
|
||||
if options.AccessKeyId == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset accessKeyId")
|
||||
}
|
||||
if options.SecretAccessKey == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset secretAccessKey")
|
||||
}
|
||||
|
||||
signer := NewSigner(options.AccessKeyId, options.SecretAccessKey, service)
|
||||
httper := resty.New().
|
||||
SetBaseURL(baseUrl).
|
||||
SetHeader("Accept", "application/json").
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("User-Agent", app.AppUserAgent).
|
||||
SetPreRequestHook(func(_ *resty.Client, req *http.Request) error {
|
||||
if err := signer.Sign(req); err != nil {
|
||||
return fmt.Errorf("sdkerr: sign error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return &Client{rc: httper}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.rc.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) NewRequest(method string, path string, params any) (*resty.Request, error) {
|
||||
if method == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset method")
|
||||
}
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset path")
|
||||
}
|
||||
|
||||
paramsMap := 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 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch reflect.Indirect(reflect.ValueOf(v)).Kind() {
|
||||
case reflect.String:
|
||||
paramsMap[k] = v.(string)
|
||||
|
||||
case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
|
||||
paramsMap[k] = fmt.Sprintf("%v", v)
|
||||
|
||||
default:
|
||||
jsonb, _ := json.Marshal(v)
|
||||
paramsMap[k] = string(jsonb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req := c.rc.R()
|
||||
req.Method = method
|
||||
req.URL = path
|
||||
if strings.ToUpper(method) == http.MethodGet {
|
||||
req.SetQueryParams(paramsMap)
|
||||
} else {
|
||||
req.SetBody(paramsMap)
|
||||
}
|
||||
|
||||
// WARN:
|
||||
// DO NOT CALL `req.SetBody` or `req.SetFormData` AGAIN! USE `newRequest` INSTEAD.
|
||||
// DO NOT CALL `req.SetResult` or `req.SetError` AGAIN! USE `doRequestWithResult` INSTEAD.
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) DoRequest(req *resty.Request) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := req.Send()
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to send request: %w", err)
|
||||
} else if resp.IsError() {
|
||||
return resp, fmt.Errorf("sdkerr: unexpected status code: %d (resp: %s)", resp.StatusCode(), resp.String())
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) DoRequestWithResult(req *resty.Request, res any) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := c.DoRequest(req)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
json.Unmarshal(resp.Body(), &res)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if len(resp.Body()) != 0 {
|
||||
if err := json.Unmarshal(resp.Body(), &res); err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to unmarshal response: %w (resp: %s)", err, resp.String())
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package common
|
||||
|
||||
type Options struct {
|
||||
AccessKeyId string
|
||||
SecretAccessKey string
|
||||
}
|
||||
|
||||
type OptionsFunc func(*Options)
|
||||
|
||||
func WithAkSk(ak, sk string) OptionsFunc {
|
||||
return func(o *Options) {
|
||||
o.AccessKeyId = ak
|
||||
o.SecretAccessKey = sk
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
type signer struct {
|
||||
accessKeyId string
|
||||
secretAccessKey string
|
||||
service string
|
||||
}
|
||||
|
||||
func NewSigner(ak, sk, service string) *signer {
|
||||
return &signer{
|
||||
accessKeyId: ak,
|
||||
secretAccessKey: sk,
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *signer) Sign(req *http.Request) error {
|
||||
// API 签名机制:
|
||||
// https://docs.ksyun.com/documents/40298
|
||||
|
||||
method := strings.ToUpper(req.Method)
|
||||
|
||||
query := url.Values{}
|
||||
if req.URL != nil {
|
||||
query = req.URL.Query()
|
||||
}
|
||||
|
||||
payload := make(map[string]string)
|
||||
if method != http.MethodGet && req.Body != nil {
|
||||
payloadb, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(payloadb, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Body = io.NopCloser(bytes.NewReader(payloadb))
|
||||
}
|
||||
|
||||
params := make(map[string]string)
|
||||
for k := range query {
|
||||
params[k] = query.Get(k)
|
||||
}
|
||||
for k, v := range payload {
|
||||
params[k] = v
|
||||
}
|
||||
|
||||
nowUtc := time.Now().UTC()
|
||||
timestamp := nowUtc.Format("2006-01-02T15:04:05Z")
|
||||
|
||||
params["Accesskey"] = s.accessKeyId
|
||||
params["Service"] = s.service
|
||||
params["Timestamp"] = timestamp
|
||||
params["SignatureVersion"] = "1.0"
|
||||
params["SignatureMethod"] = "HMAC-SHA256"
|
||||
paramsKeys := xmaps.Keys(params)
|
||||
sort.Strings(paramsKeys)
|
||||
|
||||
stringToSign := ""
|
||||
for i, k := range paramsKeys {
|
||||
if i > 0 {
|
||||
stringToSign += "&"
|
||||
}
|
||||
|
||||
stringToSign += escapeQuery(k) + "=" + escapeQuery(params[k])
|
||||
}
|
||||
|
||||
h := hmac.New(sha256.New, []byte(s.secretAccessKey))
|
||||
h.Write([]byte(stringToSign))
|
||||
signature := strings.ToLower(hex.EncodeToString(h.Sum(nil)))
|
||||
|
||||
if method == http.MethodGet {
|
||||
query.Set("Accesskey", params["Accesskey"])
|
||||
query.Set("Service", params["Service"])
|
||||
query.Set("Timestamp", params["Timestamp"])
|
||||
query.Set("SignatureVersion", params["SignatureVersion"])
|
||||
query.Set("SignatureMethod", params["SignatureMethod"])
|
||||
|
||||
req.URL.RawQuery = query.Encode() + "&Signature=" + signature
|
||||
} else {
|
||||
if _, ok := payload["Action"]; ok {
|
||||
query.Set("Action", payload["Action"])
|
||||
delete(payload, "Action")
|
||||
}
|
||||
|
||||
if _, ok := payload["Version"]; ok {
|
||||
query.Set("Version", payload["Version"])
|
||||
delete(payload, "Version")
|
||||
}
|
||||
|
||||
payload["Accesskey"] = params["Accesskey"]
|
||||
payload["Service"] = params["Service"]
|
||||
payload["Timestamp"] = params["Timestamp"]
|
||||
payload["SignatureVersion"] = params["SignatureVersion"]
|
||||
payload["SignatureMethod"] = params["SignatureMethod"]
|
||||
payload["Signature"] = signature
|
||||
|
||||
jsonb, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.URL.RawQuery = query.Encode()
|
||||
req.Body = io.NopCloser(bytes.NewReader(jsonb))
|
||||
req.ContentLength = int64(len(jsonb))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func escapeQuery(str string) string {
|
||||
res := url.QueryEscape(str)
|
||||
res = strings.ReplaceAll(res, "+", "%20")
|
||||
return res
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type BatchUpdateCertificateConfigRequest struct {
|
||||
CertificateId int64 `json:"certificateId"`
|
||||
DomainNames []string `json:"domainNames"`
|
||||
}
|
||||
|
||||
type BatchUpdateCertificateConfigResponse struct {
|
||||
sdkResponseBase
|
||||
}
|
||||
|
||||
func (c *Client) BatchUpdateCertificateConfig(req *BatchUpdateCertificateConfigRequest) (*BatchUpdateCertificateConfigResponse, error) {
|
||||
return c.BatchUpdateCertificateConfigWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) BatchUpdateCertificateConfigWithContext(ctx context.Context, req *BatchUpdateCertificateConfigRequest) (*BatchUpdateCertificateConfigResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodPut, "/api/config/certificate/batch")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &BatchUpdateCertificateConfigResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// A simple SDK client for WangsuCloud CDN.
|
||||
// API documentation: https://www.wangsu.com/document/api-doc/product
|
||||
package cdn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/zz-shared-common"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *common.Client
|
||||
}
|
||||
|
||||
func NewClient(optFns ...common.OptionsFunc) (*Client, error) {
|
||||
client, err := common.NewClient(optFns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{client: client}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.client.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method string, path string) (*resty.Request, error) {
|
||||
return c.client.NewRequest(method, path)
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
|
||||
return c.client.DoRequest(req)
|
||||
}
|
||||
|
||||
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
|
||||
resp, err := c.client.DoRequestWithResult(req, res)
|
||||
if err == nil {
|
||||
if rCode := res.GetCode(); rCode != "" && rCode != "0" {
|
||||
return resp, fmt.Errorf("sdkerr: api error: code='%s', message='%s'", rCode, res.GetMessage())
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package cdn
|
||||
|
||||
import (
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/zz-shared-common"
|
||||
)
|
||||
|
||||
func WithAkSk(ak, sk string) common.OptionsFunc {
|
||||
return common.WithAkSk(ak, sk)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package cdn
|
||||
|
||||
type sdkResponse interface {
|
||||
GetCode() string
|
||||
GetMessage() string
|
||||
}
|
||||
|
||||
type sdkResponseBase struct {
|
||||
Code *string `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
var _ sdkResponse = (*sdkResponseBase)(nil)
|
||||
|
||||
func (r *sdkResponseBase) GetCode() string {
|
||||
if r.Code == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *r.Code
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetMessage() string {
|
||||
if r.Message == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *r.Message
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type CreateCertificateRequest 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"`
|
||||
}
|
||||
|
||||
type CreateCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
CertificateLocation string `json:"location,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||
return c.CreateCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) CreateCertificateWithContext(ctx context.Context, req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/cdn/certificates")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetHeader("X-CNC-Timestamp", fmt.Sprintf("%d", req.Timestamp))
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &CreateCertificateResponse{}
|
||||
if httpresp, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
result.CertificateLocation = httpresp.Header().Get("Location")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type CreateDeploymentTaskRequest struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Target *string `json:"target,omitempty"`
|
||||
Actions *[]DeploymentTaskAction `json:"actions,omitempty"`
|
||||
Webhook *string `json:"webhook,omitempty"`
|
||||
}
|
||||
|
||||
type CreateDeploymentTaskResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
DeploymentTaskLocation string `json:"location,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) CreateDeploymentTask(req *CreateDeploymentTaskRequest) (*CreateDeploymentTaskResponse, error) {
|
||||
return c.CreateDeploymentTaskWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) CreateDeploymentTaskWithContext(ctx context.Context, req *CreateDeploymentTaskRequest) (*CreateDeploymentTaskResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/cdn/deploymentTasks")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &CreateDeploymentTaskResponse{}
|
||||
if httpresp, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
result.DeploymentTaskLocation = httpresp.Header().Get("Location")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type GetDeploymentTaskDetailResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
func (c *Client) GetDeploymentTaskDetail(deploymentTaskId string) (*GetDeploymentTaskDetailResponse, error) {
|
||||
return c.GetDeploymentTaskDetailWithContext(context.Background(), deploymentTaskId)
|
||||
}
|
||||
|
||||
func (c *Client) GetDeploymentTaskDetailWithContext(ctx context.Context, deploymentTaskId string) (*GetDeploymentTaskDetailResponse, error) {
|
||||
if deploymentTaskId == "" {
|
||||
return nil, fmt.Errorf("sdkerr: bad request: unset deploymentTaskId")
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodGet, fmt.Sprintf("/cdn/deploymentTasks/%s", url.PathEscape(deploymentTaskId)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &GetDeploymentTaskDetailResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type GetHostnameDetailResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Hostname string `json:"hostname"`
|
||||
PropertyInProduction *HostnameProperty `json:"propertyInProduction,omitempty"`
|
||||
PropertyInStaging *HostnameProperty `json:"propertyInStaging,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) GetHostnameDetail(hostname string) (*GetHostnameDetailResponse, error) {
|
||||
return c.GetHostnameDetailWithContext(context.Background(), hostname)
|
||||
}
|
||||
|
||||
func (c *Client) GetHostnameDetailWithContext(ctx context.Context, hostname string) (*GetHostnameDetailResponse, error) {
|
||||
if hostname == "" {
|
||||
return nil, fmt.Errorf("sdkerr: bad request: unset hostname")
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodGet, fmt.Sprintf("/cdn/hostnames/%s", url.PathEscape(hostname)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &GetHostnameDetailResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
type UpdateCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
CertificateLocation string `json:"location,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) UpdateCertificate(certificateId string, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
|
||||
return c.UpdateCertificateWithContext(context.Background(), certificateId, req)
|
||||
}
|
||||
|
||||
func (c *Client) UpdateCertificateWithContext(ctx context.Context, certificateId string, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
|
||||
if certificateId == "" {
|
||||
return nil, fmt.Errorf("sdkerr: bad request: unset certificateId")
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPatch, fmt.Sprintf("/cdn/certificates/%s", url.PathEscape(certificateId)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetHeader("X-CNC-Timestamp", fmt.Sprintf("%d", req.Timestamp))
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &UpdateCertificateResponse{}
|
||||
if httpresp, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
result.CertificateLocation = httpresp.Header().Get("Location")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// A simple SDK client for WangsuCloud CDN.
|
||||
// API documentation: https://www.wangsu.com/document/api-doc/product
|
||||
package cdnpro
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/zz-shared-common"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *common.Client
|
||||
}
|
||||
|
||||
func NewClient(optFns ...common.OptionsFunc) (*Client, error) {
|
||||
client, err := common.NewClient(optFns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{client: client}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.client.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method string, path string) (*resty.Request, error) {
|
||||
return c.client.NewRequest(method, path)
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
|
||||
return c.client.DoRequest(req)
|
||||
}
|
||||
|
||||
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
|
||||
return c.client.DoRequestWithResult(req, res)
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
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"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
SubjectAlternativeNames []*string `json:"subjectAlternativeNames,omitempty"`
|
||||
}
|
||||
|
||||
type HostnameProperty struct {
|
||||
PropertyId string `json:"propertyId"`
|
||||
Version int32 `json:"version"`
|
||||
CertificateId *string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type DeploymentTaskAction struct {
|
||||
Action *string `json:"action,omitempty"`
|
||||
PropertyId *string `json:"propertyId,omitempty"`
|
||||
CertificateId *string `json:"certificateId,omitempty"`
|
||||
Version *int32 `json:"version,omitempty"`
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
import (
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/zz-shared-common"
|
||||
)
|
||||
|
||||
func WithAkSk(ak, sk string) common.OptionsFunc {
|
||||
return common.WithAkSk(ak, sk)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package cdnpro
|
||||
|
||||
type sdkResponse interface {
|
||||
GetCode() string
|
||||
GetMessage() string
|
||||
}
|
||||
|
||||
type sdkResponseBase struct {
|
||||
Code *string `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
var _ sdkResponse = (*sdkResponseBase)(nil)
|
||||
|
||||
func (r *sdkResponseBase) GetCode() string {
|
||||
if r.Code == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *r.Code
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetMessage() string {
|
||||
if r.Message == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *r.Message
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type CreateCertificateRequest struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Certificate *string `json:"certificate,omitempty"`
|
||||
PrivateKey *string `json:"privateKey,omitempty"`
|
||||
Comment *string `json:"comment,omitempty" `
|
||||
}
|
||||
|
||||
type CreateCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
CertificateLocation string `json:"location,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||
return c.CreateCertificateWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) CreateCertificateWithContext(ctx context.Context, req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/api/certificate")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &CreateCertificateResponse{}
|
||||
if httpresp, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
result.CertificateLocation = httpresp.Header().Get("Location")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ListCertificatesResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Certificates []*Certificate `json:"ssl-certificates,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Client) ListCertificates() (*ListCertificatesResponse, error) {
|
||||
return c.ListCertificatesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func (c *Client) ListCertificatesWithContext(ctx context.Context) (*ListCertificatesResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodGet, "/api/ssl/certificate")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &ListCertificatesResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type UpdateCertificateRequest struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Certificate *string `json:"certificate,omitempty"`
|
||||
PrivateKey *string `json:"privateKey,omitempty"`
|
||||
Comment *string `json:"comment,omitempty" `
|
||||
}
|
||||
|
||||
type UpdateCertificateResponse struct {
|
||||
sdkResponseBase
|
||||
}
|
||||
|
||||
func (c *Client) UpdateCertificate(certificateId string, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
|
||||
return c.UpdateCertificateWithContext(context.Background(), certificateId, req)
|
||||
}
|
||||
|
||||
func (c *Client) UpdateCertificateWithContext(ctx context.Context, certificateId string, req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) {
|
||||
if certificateId == "" {
|
||||
return nil, fmt.Errorf("sdkerr: bad request: unset certificateId")
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPut, fmt.Sprintf("/api/certificate/%s", url.PathEscape(certificateId)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &UpdateCertificateResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// A simple SDK client for WangsuCloud CDN.
|
||||
// API documentation: https://www.wangsu.com/document/api-doc/product
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/zz-shared-common"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
client *common.Client
|
||||
}
|
||||
|
||||
func NewClient(optFns ...common.OptionsFunc) (*Client, error) {
|
||||
client, err := common.NewClient(optFns...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{client: client}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.client.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method string, path string) (*resty.Request, error) {
|
||||
return c.client.NewRequest(method, path)
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
|
||||
return c.client.DoRequest(req)
|
||||
}
|
||||
|
||||
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
|
||||
return c.client.DoRequestWithResult(req, res)
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package certificate
|
||||
|
||||
type Certificate struct {
|
||||
Id 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"`
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
common "github.com/certimate-go/certimate/pkg/sdk3rd/wangsu/zz-shared-common"
|
||||
)
|
||||
|
||||
func WithAkSk(ak, sk string) common.OptionsFunc {
|
||||
return common.WithAkSk(ak, sk)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package certificate
|
||||
|
||||
type sdkResponse interface {
|
||||
GetCode() string
|
||||
GetMessage() string
|
||||
}
|
||||
|
||||
type sdkResponseBase struct {
|
||||
Code *string `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
var _ sdkResponse = (*sdkResponseBase)(nil)
|
||||
|
||||
func (r *sdkResponseBase) GetCode() string {
|
||||
if r.Code == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *r.Code
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetMessage() string {
|
||||
if r.Message == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *r.Message
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/app"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
rc *resty.Client
|
||||
}
|
||||
|
||||
func NewClient(optFns ...OptionsFunc) (*Client, error) {
|
||||
options := &Options{}
|
||||
for _, fn := range optFns {
|
||||
fn(options)
|
||||
}
|
||||
|
||||
if options.AccessKey == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset accessKey")
|
||||
}
|
||||
if options.SecretKey == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset secretKey")
|
||||
}
|
||||
|
||||
signer := NewSigner(options.AccessKey, options.SecretKey)
|
||||
httper := resty.New().
|
||||
SetBaseURL("https://open.chinanetcenter.com").
|
||||
SetHeader("Accept", "application/json").
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("User-Agent", app.AppUserAgent).
|
||||
SetPreRequestHook(func(_ *resty.Client, req *http.Request) error {
|
||||
if err := signer.Sign(req); err != nil {
|
||||
return fmt.Errorf("sdkerr: sign error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return &Client{rc: httper}, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.rc.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) NewRequest(method string, path string) (*resty.Request, error) {
|
||||
if method == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset method")
|
||||
}
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset path")
|
||||
}
|
||||
|
||||
req := c.rc.R()
|
||||
req.Method = method
|
||||
req.URL = path
|
||||
|
||||
// WARN:
|
||||
// DO NOT CALL `req.SetResult` or `req.SetError` AGAIN! USE `doRequestWithResult` INSTEAD.
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) DoRequest(req *resty.Request) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := req.Send()
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to send request: %w", err)
|
||||
} else if resp.IsError() {
|
||||
return resp, fmt.Errorf("sdkerr: unexpected status code: %d (resp: %s)", resp.StatusCode(), resp.String())
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) DoRequestWithResult(req *resty.Request, res any) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := c.DoRequest(req)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
json.Unmarshal(resp.Body(), &res)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if len(resp.Body()) != 0 {
|
||||
if err := json.Unmarshal(resp.Body(), &res); err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to unmarshal response: %w (resp: %s)", err, resp.String())
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package common
|
||||
|
||||
type Options struct {
|
||||
AccessKey string
|
||||
SecretKey string
|
||||
}
|
||||
|
||||
type OptionsFunc func(*Options)
|
||||
|
||||
func WithAkSk(ak, sk string) OptionsFunc {
|
||||
return func(o *Options) {
|
||||
o.AccessKey = ak
|
||||
o.SecretKey = sk
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type signer struct {
|
||||
accessKey string
|
||||
secretKey string
|
||||
}
|
||||
|
||||
func NewSigner(ak, sk string) *signer {
|
||||
return &signer{
|
||||
accessKey: ak,
|
||||
secretKey: sk,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *signer) Sign(req *http.Request) error {
|
||||
// API 签名机制:
|
||||
// https://www.wangsu.com/document/openapi/api-authentication
|
||||
|
||||
method := strings.ToUpper(req.Method)
|
||||
|
||||
path := "/"
|
||||
if req.URL != nil {
|
||||
path = req.URL.Path
|
||||
}
|
||||
|
||||
queryStr := ""
|
||||
if method != http.MethodPost && req.URL != nil {
|
||||
queryStr = req.URL.RawQuery
|
||||
|
||||
s, err := url.QueryUnescape(queryStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queryStr = s
|
||||
}
|
||||
|
||||
canonicalHeaders := "" +
|
||||
"content-type:" + strings.TrimSpace(strings.ToLower(req.Header.Get("Content-Type"))) + "\n" +
|
||||
"host:" + strings.TrimSpace(strings.ToLower(req.Host)) + "\n"
|
||||
signedHeaders := "content-type;host"
|
||||
|
||||
payloadStr := ""
|
||||
if method != http.MethodGet && req.Body != nil {
|
||||
payloadb, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
payloadStr = string(payloadb)
|
||||
req.Body = io.NopCloser(bytes.NewReader(payloadb))
|
||||
}
|
||||
payloadHash := sha256.Sum256([]byte(payloadStr))
|
||||
payloadHashHex := strings.ToLower(hex.EncodeToString(payloadHash[:]))
|
||||
|
||||
nowUtc := time.Now().UTC()
|
||||
timestampStr := req.Header.Get("X-CNC-Timestamp")
|
||||
if timestampStr == "" {
|
||||
timestampStr = fmt.Sprintf("%d", nowUtc.Unix())
|
||||
} else {
|
||||
timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nowUtc = time.Unix(timestamp, 0).UTC()
|
||||
}
|
||||
|
||||
canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", method, path, queryStr, canonicalHeaders, signedHeaders, payloadHashHex)
|
||||
canonicalRequestHash := sha256.Sum256([]byte(canonicalRequest))
|
||||
canonicalRequestHashHex := strings.ToLower(hex.EncodeToString(canonicalRequestHash[:]))
|
||||
|
||||
const signAlgorithmHeader = "CNC-HMAC-SHA256"
|
||||
stringToSign := fmt.Sprintf("%s\n%s\n%s", signAlgorithmHeader, timestampStr, canonicalRequestHashHex)
|
||||
|
||||
h := hmac.New(sha256.New, []byte(s.secretKey))
|
||||
h.Write([]byte(stringToSign))
|
||||
signature := strings.ToLower(hex.EncodeToString(h.Sum(nil)))
|
||||
|
||||
authorization := fmt.Sprintf("%s Credential=%s, SignedHeaders=%s, Signature=%s", signAlgorithmHeader, s.accessKey, signedHeaders, signature)
|
||||
|
||||
req.Header.Set("Authorization", authorization)
|
||||
req.Header.Set("Date", nowUtc.Format(http.TimeFormat))
|
||||
req.Header.Set("X-CNC-Auth-Method", "AKSK")
|
||||
req.Header.Set("X-CNC-AccessKey", s.accessKey)
|
||||
req.Header.Set("X-CNC-Timestamp", timestampStr)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import AccessConfigFieldsProviderAWS from "./AccessConfigFieldsProviderAWS";
|
||||
import AccessConfigFieldsProviderAxisNow from "./AccessConfigFieldsProviderAxisNow";
|
||||
import AccessConfigFieldsProviderAzure from "./AccessConfigFieldsProviderAzure";
|
||||
import AccessConfigFieldsProviderBaiduCloud from "./AccessConfigFieldsProviderBaiduCloud";
|
||||
import AccessConfigFieldsProviderBaishan from "./AccessConfigFieldsProviderBaishan";
|
||||
import AccessConfigFieldsProviderBaotaPanel from "./AccessConfigFieldsProviderBaotaPanel";
|
||||
import AccessConfigFieldsProviderBaotaPanelGo from "./AccessConfigFieldsProviderBaotaPanelGo";
|
||||
import AccessConfigFieldsProviderBaotaWAF from "./AccessConfigFieldsProviderBaotaWAF";
|
||||
@@ -69,7 +68,6 @@ import AccessConfigFieldsProviderInfomaniak from "./AccessConfigFieldsProviderIn
|
||||
import AccessConfigFieldsProviderIONOS from "./AccessConfigFieldsProviderIONOS";
|
||||
import AccessConfigFieldsProviderJDCloud from "./AccessConfigFieldsProviderJDCloud";
|
||||
import AccessConfigFieldsProviderKong from "./AccessConfigFieldsProviderKong";
|
||||
import AccessConfigFieldsProviderKsyun from "./AccessConfigFieldsProviderKsyun";
|
||||
import AccessConfigFieldsProviderLarkBot from "./AccessConfigFieldsProviderLarkBot";
|
||||
import AccessConfigFieldsProviderLeCDN from "./AccessConfigFieldsProviderLeCDN";
|
||||
import AccessConfigFieldsProviderLinode from "./AccessConfigFieldsProviderLinode";
|
||||
@@ -115,7 +113,6 @@ import AccessConfigFieldsProviderUniCloud from "./AccessConfigFieldsProviderUniC
|
||||
import AccessConfigFieldsProviderVercel from "./AccessConfigFieldsProviderVercel";
|
||||
import AccessConfigFieldsProviderVolcEngine from "./AccessConfigFieldsProviderVolcEngine";
|
||||
import AccessConfigFieldsProviderVultr from "./AccessConfigFieldsProviderVultr";
|
||||
import AccessConfigFieldsProviderWangsu from "./AccessConfigFieldsProviderWangsu";
|
||||
import AccessConfigFieldsProviderWebhook from "./AccessConfigFieldsProviderWebhook";
|
||||
import AccessConfigFieldsProviderWeComBot from "./AccessConfigFieldsProviderWeComBot";
|
||||
import AccessConfigFieldsProviderWestcn from "./AccessConfigFieldsProviderWestcn";
|
||||
@@ -142,7 +139,6 @@ const providerComponentMap: Partial<Record<AccessProviderType, React.ComponentTy
|
||||
[ACCESS_PROVIDERS.AXISNOW]: AccessConfigFieldsProviderAxisNow,
|
||||
[ACCESS_PROVIDERS.AZURE]: AccessConfigFieldsProviderAzure,
|
||||
[ACCESS_PROVIDERS.BAIDUCLOUD]: AccessConfigFieldsProviderBaiduCloud,
|
||||
[ACCESS_PROVIDERS.BAISHAN]: AccessConfigFieldsProviderBaishan,
|
||||
[ACCESS_PROVIDERS.BAOTAPANEL]: AccessConfigFieldsProviderBaotaPanel,
|
||||
[ACCESS_PROVIDERS.BAOTAPANELGO]: AccessConfigFieldsProviderBaotaPanelGo,
|
||||
[ACCESS_PROVIDERS.BAOTAWAF]: AccessConfigFieldsProviderBaotaWAF,
|
||||
@@ -192,7 +188,6 @@ const providerComponentMap: Partial<Record<AccessProviderType, React.ComponentTy
|
||||
[ACCESS_PROVIDERS.IONOS]: AccessConfigFieldsProviderIONOS,
|
||||
[ACCESS_PROVIDERS.JDCLOUD]: AccessConfigFieldsProviderJDCloud,
|
||||
[ACCESS_PROVIDERS.KONG]: AccessConfigFieldsProviderKong,
|
||||
[ACCESS_PROVIDERS.KSYUN]: AccessConfigFieldsProviderKsyun,
|
||||
[ACCESS_PROVIDERS.LARKBOT]: AccessConfigFieldsProviderLarkBot,
|
||||
[ACCESS_PROVIDERS.LECDN]: AccessConfigFieldsProviderLeCDN,
|
||||
[ACCESS_PROVIDERS.INFOMANIAK]: AccessConfigFieldsProviderInfomaniak,
|
||||
@@ -239,7 +234,6 @@ const providerComponentMap: Partial<Record<AccessProviderType, React.ComponentTy
|
||||
[ACCESS_PROVIDERS.VERCEL]: AccessConfigFieldsProviderVercel,
|
||||
[ACCESS_PROVIDERS.VOLCENGINE]: AccessConfigFieldsProviderVolcEngine,
|
||||
[ACCESS_PROVIDERS.VULTR]: AccessConfigFieldsProviderVultr,
|
||||
[ACCESS_PROVIDERS.WANGSU]: AccessConfigFieldsProviderWangsu,
|
||||
[ACCESS_PROVIDERS.WEBHOOK]: AccessConfigFieldsProviderWebhook,
|
||||
[ACCESS_PROVIDERS.WECOMBOT]: AccessConfigFieldsProviderWeComBot,
|
||||
[ACCESS_PROVIDERS.WESTCN]: AccessConfigFieldsProviderWestcn,
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const AccessConfigFormFieldsProviderBaishan = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item name={[parentNamePath, "apiToken"]} initialValue={initialValues.apiToken} label={t("access.form.baishan_api_token.label")} rules={[formRule]}>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.baishan_api_token.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
apiToken: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
apiToken: z.string().nonempty(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(AccessConfigFormFieldsProviderBaishan, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -1,64 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const AccessConfigFormFieldsProviderKsyun = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "accessKeyId"]}
|
||||
initialValue={initialValues.accessKeyId}
|
||||
label={t("access.form.ksyun_access_key_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ksyun_access_key_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input autoComplete="new-password" placeholder={t("access.form.ksyun_access_key_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "secretAccessKey"]}
|
||||
initialValue={initialValues.secretAccessKey}
|
||||
label={t("access.form.ksyun_secret_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ksyun_secret_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.ksyun_secret_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
accessKeyId: "",
|
||||
secretAccessKey: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
accessKeyId: z.string().nonempty(),
|
||||
secretAccessKey: z.string().nonempty(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(AccessConfigFormFieldsProviderKsyun, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -1,76 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const AccessConfigFormFieldsProviderWangsu = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "accessKeyId"]}
|
||||
initialValue={initialValues.accessKeyId}
|
||||
label={t("access.form.wangsu_access_key_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.wangsu_access_key_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input autoComplete="new-password" placeholder={t("access.form.wangsu_access_key_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "accessKeySecret"]}
|
||||
initialValue={initialValues.accessKeySecret}
|
||||
label={t("access.form.wangsu_access_key_secret.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.wangsu_access_key_secret.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.wangsu_access_key_secret.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "apiKey"]}
|
||||
initialValue={initialValues.apiKey}
|
||||
label={t("access.form.wangsu_api_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.wangsu_api_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.wangsu_api_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
accessKeyId: "",
|
||||
accessKeySecret: "",
|
||||
apiKey: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
accessKeyId: z.string().nonempty(),
|
||||
accessKeySecret: z.string().nonempty(),
|
||||
apiKey: z.string().nonempty(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(AccessConfigFormFieldsProviderWangsu, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -34,7 +34,6 @@ import BizDeployNodeConfigFieldsProviderAzureKeyVault from "./BizDeployNodeConfi
|
||||
import BizDeployNodeConfigFieldsProviderBaiduCloudAppBLB from "./BizDeployNodeConfigFieldsProviderBaiduCloudAppBLB";
|
||||
import BizDeployNodeConfigFieldsProviderBaiduCloudBLB from "./BizDeployNodeConfigFieldsProviderBaiduCloudBLB";
|
||||
import BizDeployNodeConfigFieldsProviderBaiduCloudCDN from "./BizDeployNodeConfigFieldsProviderBaiduCloudCDN";
|
||||
import BizDeployNodeConfigFieldsProviderBaishanCDN from "./BizDeployNodeConfigFieldsProviderBaishanCDN";
|
||||
import BizDeployNodeConfigFieldsProviderBaotaPanel from "./BizDeployNodeConfigFieldsProviderBaotaPanel";
|
||||
import BizDeployNodeConfigFieldsProviderBaotaPanelConsole from "./BizDeployNodeConfigFieldsProviderBaotaPanelConsole";
|
||||
import BizDeployNodeConfigFieldsProviderBaotaPanelGo from "./BizDeployNodeConfigFieldsProviderBaotaPanelGo";
|
||||
@@ -80,8 +79,6 @@ import BizDeployNodeConfigFieldsProviderJDCloudLive from "./BizDeployNodeConfigF
|
||||
import BizDeployNodeConfigFieldsProviderJDCloudVOD from "./BizDeployNodeConfigFieldsProviderJDCloudVOD";
|
||||
import BizDeployNodeConfigFieldsProviderJDCloudWAF from "./BizDeployNodeConfigFieldsProviderJDCloudWAF";
|
||||
import BizDeployNodeConfigFieldsProviderKong from "./BizDeployNodeConfigFieldsProviderKong";
|
||||
import BizDeployNodeConfigFieldsProviderKsyunCDN from "./BizDeployNodeConfigFieldsProviderKsyunCDN";
|
||||
import BizDeployNodeConfigFieldsProviderKsyunSLB from "./BizDeployNodeConfigFieldsProviderKsyunSLB";
|
||||
import BizDeployNodeConfigFieldsProviderLeCDN from "./BizDeployNodeConfigFieldsProviderLeCDN";
|
||||
import BizDeployNodeConfigFieldsProviderLinodeLOS from "./BizDeployNodeConfigFieldsProviderLinodeLOS";
|
||||
import BizDeployNodeConfigFieldsProviderLocal from "./BizDeployNodeConfigFieldsProviderLocal";
|
||||
@@ -135,9 +132,6 @@ import BizDeployNodeConfigFieldsProviderVolcEngineLive from "./BizDeployNodeConf
|
||||
import BizDeployNodeConfigFieldsProviderVolcEngineTOS from "./BizDeployNodeConfigFieldsProviderVolcEngineTOS";
|
||||
import BizDeployNodeConfigFieldsProviderVolcEngineVOD from "./BizDeployNodeConfigFieldsProviderVolcEngineVOD";
|
||||
import BizDeployNodeConfigFieldsProviderVolcEngineWAF from "./BizDeployNodeConfigFieldsProviderVolcEngineWAF";
|
||||
import BizDeployNodeConfigFieldsProviderWangsuCDN from "./BizDeployNodeConfigFieldsProviderWangsuCDN";
|
||||
import BizDeployNodeConfigFieldsProviderWangsuCDNPro from "./BizDeployNodeConfigFieldsProviderWangsuCDNPro";
|
||||
import BizDeployNodeConfigFieldsProviderWangsuCertificate from "./BizDeployNodeConfigFieldsProviderWangsuCertificate";
|
||||
import BizDeployNodeConfigFieldsProviderWebhook from "./BizDeployNodeConfigFieldsProviderWebhook";
|
||||
import BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager from "./BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager";
|
||||
import SchemaConfigFields from "./SchemaConfigFields";
|
||||
@@ -178,7 +172,6 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
|
||||
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_APPBLB]: BizDeployNodeConfigFieldsProviderBaiduCloudAppBLB,
|
||||
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_BLB]: BizDeployNodeConfigFieldsProviderBaiduCloudBLB,
|
||||
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_CDN]: BizDeployNodeConfigFieldsProviderBaiduCloudCDN,
|
||||
[DEPLOYMENT_PROVIDERS.BAISHAN_CDN]: BizDeployNodeConfigFieldsProviderBaishanCDN,
|
||||
[DEPLOYMENT_PROVIDERS.BAOTAPANEL_CONSOLE]: BizDeployNodeConfigFieldsProviderBaotaPanelConsole,
|
||||
[DEPLOYMENT_PROVIDERS.BAOTAPANEL]: BizDeployNodeConfigFieldsProviderBaotaPanel,
|
||||
[DEPLOYMENT_PROVIDERS.BAOTAPANELGO_CONSOLE]: BizDeployNodeConfigFieldsProviderBaotaPanelGoConsole,
|
||||
@@ -224,8 +217,6 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_VOD]: BizDeployNodeConfigFieldsProviderJDCloudVOD,
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_WAF]: BizDeployNodeConfigFieldsProviderJDCloudWAF,
|
||||
[DEPLOYMENT_PROVIDERS.KONG]: BizDeployNodeConfigFieldsProviderKong,
|
||||
[DEPLOYMENT_PROVIDERS.KSYUN_CDN]: BizDeployNodeConfigFieldsProviderKsyunCDN,
|
||||
[DEPLOYMENT_PROVIDERS.KSYUN_SLB]: BizDeployNodeConfigFieldsProviderKsyunSLB,
|
||||
[DEPLOYMENT_PROVIDERS.LECDN]: BizDeployNodeConfigFieldsProviderLeCDN,
|
||||
[DEPLOYMENT_PROVIDERS.LINODE_LOS]: BizDeployNodeConfigFieldsProviderLinodeLOS,
|
||||
[DEPLOYMENT_PROVIDERS.LOCAL]: BizDeployNodeConfigFieldsProviderLocal,
|
||||
@@ -279,9 +270,6 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
|
||||
[DEPLOYMENT_PROVIDERS.VOLCENGINE_TOS]: BizDeployNodeConfigFieldsProviderVolcEngineTOS,
|
||||
[DEPLOYMENT_PROVIDERS.VOLCENGINE_VOD]: BizDeployNodeConfigFieldsProviderVolcEngineVOD,
|
||||
[DEPLOYMENT_PROVIDERS.VOLCENGINE_WAF]: BizDeployNodeConfigFieldsProviderVolcEngineWAF,
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CDN]: BizDeployNodeConfigFieldsProviderWangsuCDN,
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CDNPRO]: BizDeployNodeConfigFieldsProviderWangsuCDNPro,
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CERTIFICATE]: BizDeployNodeConfigFieldsProviderWangsuCertificate,
|
||||
[DEPLOYMENT_PROVIDERS.WEBHOOK]: BizDeployNodeConfigFieldsProviderWebhook,
|
||||
[DEPLOYMENT_PROVIDERS.YANDEXCLOUD_CERTIFICATEMANAGER]: BizDeployNodeConfigFieldsProviderYandexCloudCertificateManager,
|
||||
};
|
||||
|
||||
-166
@@ -1,166 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Radio, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { isDomain } from "@/utils/validator";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const DEPLOY_TARGET_DOMAIN = "domain" as const;
|
||||
const DEPLOY_TARGET_CERTIFICATE = "certificate" as const;
|
||||
|
||||
const DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderBaishanCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "deployTarget"], formInst);
|
||||
const fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "deployTarget"]}
|
||||
initialValue={initialValues.deployTarget}
|
||||
label={t("workflow_node.deploy.form.shared_deploy_target.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select
|
||||
options={[DEPLOY_TARGET_DOMAIN, DEPLOY_TARGET_CERTIFICATE].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.baishan_cdn_deploy_target.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
placeholder={t("workflow_node.deploy.form.shared_deploy_target.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === DEPLOY_TARGET_DOMAIN}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domainMatchPattern"]}
|
||||
initialValue={initialValues.domainMatchPattern}
|
||||
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
|
||||
extra={
|
||||
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
|
||||
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.option.exact.help.wildcard") }}></span>
|
||||
) : (
|
||||
void 0
|
||||
)
|
||||
}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Radio.Group
|
||||
options={[DOMAIN_MATCH_PATTERN_EXACT].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.baishan_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.baishan_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === DEPLOY_TARGET_CERTIFICATE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.baishan_cdn_certificate_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baishan_cdn_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear type="number" placeholder={t("workflow_node.deploy.form.baishan_cdn_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
deployTarget: DEPLOY_TARGET_DOMAIN,
|
||||
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
deployTarget: z.enum([DEPLOY_TARGET_DOMAIN, DEPLOY_TARGET_CERTIFICATE]),
|
||||
domainMatchPattern: z.string().nonempty().default(DOMAIN_MATCH_PATTERN_EXACT),
|
||||
domain: z.string().nullish(),
|
||||
certificateId: z.union([z.string(), z.int().positive()]).nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.deployTarget) {
|
||||
case DEPLOY_TARGET_DOMAIN:
|
||||
{
|
||||
const scDomainMatchPattern = z.string().nonempty();
|
||||
const spDomainMatchPattern = scDomainMatchPattern.safeParse(values.domainMatchPattern);
|
||||
if (!spDomainMatchPattern.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomainMatchPattern.error).errors.join(),
|
||||
path: ["domainMatchPattern"],
|
||||
});
|
||||
}
|
||||
|
||||
switch (values.domainMatchPattern) {
|
||||
case DOMAIN_MATCH_PATTERN_EXACT:
|
||||
{
|
||||
const scDomain = z.string().refine((v) => isDomain(v, { allowWildcard: true }), t("common.errmsg.domain_invalid"));
|
||||
const spDomain = scDomain.safeParse(values.domain);
|
||||
if (!spDomain.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomain.error).errors.join(),
|
||||
path: ["domain"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DEPLOY_TARGET_CERTIFICATE:
|
||||
{
|
||||
const scCertificateId = z.string().nonempty();
|
||||
const spCertificateId = scCertificateId.safeParse(values.certificateId);
|
||||
if (!spCertificateId.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spCertificateId.error).errors.join(),
|
||||
path: ["certificateId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderBaishanCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
-169
@@ -1,169 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Radio, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { isDomain } from "@/utils/validator";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const DEPLOY_TARGET_DOMAIN = "domain" as const;
|
||||
const DEPLOY_TARGET_CERTIFICATE = "certificate" as const;
|
||||
|
||||
const DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
|
||||
const DOMAIN_MATCH_PATTERN_WILDCARD = "wildcard" as const;
|
||||
const DOMAIN_MATCH_PATTERN_CERTSAN = "certsan" as const;
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderKsyunCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "deployTarget"], formInst);
|
||||
const fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "deployTarget"]}
|
||||
initialValue={initialValues.deployTarget}
|
||||
label={t("workflow_node.deploy.form.shared_deploy_target.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select
|
||||
options={[DEPLOY_TARGET_DOMAIN, DEPLOY_TARGET_CERTIFICATE].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.ksyun_cdn_deploy_target.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
placeholder={t("workflow_node.deploy.form.shared_deploy_target.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === DEPLOY_TARGET_DOMAIN}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domainMatchPattern"]}
|
||||
initialValue={initialValues.domainMatchPattern}
|
||||
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
|
||||
extra={
|
||||
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
|
||||
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.option.exact.help.wildcard") }}></span>
|
||||
) : (
|
||||
void 0
|
||||
)
|
||||
}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Radio.Group
|
||||
options={[DOMAIN_MATCH_PATTERN_EXACT, DOMAIN_MATCH_PATTERN_WILDCARD, DOMAIN_MATCH_PATTERN_CERTSAN].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.ksyun_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ksyun_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === DEPLOY_TARGET_CERTIFICATE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.ksyun_cdn_certificate_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ksyun_cdn_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.ksyun_cdn_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
deployTarget: DEPLOY_TARGET_DOMAIN,
|
||||
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
deployTarget: z.enum([DEPLOY_TARGET_DOMAIN, DEPLOY_TARGET_CERTIFICATE]),
|
||||
domainMatchPattern: z.string().nonempty().default(DOMAIN_MATCH_PATTERN_EXACT),
|
||||
domain: z.string().nullish(),
|
||||
certificateId: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.deployTarget) {
|
||||
case DEPLOY_TARGET_DOMAIN:
|
||||
{
|
||||
const scDomainMatchPattern = z.string().nonempty();
|
||||
const spDomainMatchPattern = scDomainMatchPattern.safeParse(values.domainMatchPattern);
|
||||
if (!spDomainMatchPattern.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomainMatchPattern.error).errors.join(),
|
||||
path: ["domainMatchPattern"],
|
||||
});
|
||||
}
|
||||
|
||||
switch (values.domainMatchPattern) {
|
||||
case DOMAIN_MATCH_PATTERN_EXACT:
|
||||
case DOMAIN_MATCH_PATTERN_WILDCARD:
|
||||
{
|
||||
const scDomain = z.string().refine((v) => isDomain(v, { allowWildcard: true }), t("common.errmsg.domain_invalid"));
|
||||
const spDomain = scDomain.safeParse(values.domain);
|
||||
if (!spDomain.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomain.error).errors.join(),
|
||||
path: ["domain"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DEPLOY_TARGET_CERTIFICATE:
|
||||
{
|
||||
const scCertificateId = z.string().nonempty();
|
||||
const spCertificateId = scCertificateId.safeParse(values.certificateId);
|
||||
if (!spCertificateId.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spCertificateId.error).errors.join(),
|
||||
path: ["certificateId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderKsyunCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const DEPLOY_TARGET_CERTIFICATE = "certificate" as const;
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderKsyunSLB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "deployTarget"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.ksyun_slb_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ksyun_slb_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ksyun_slb_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "deployTarget"]}
|
||||
initialValue={initialValues.deployTarget}
|
||||
label={t("workflow_node.deploy.form.shared_deploy_target.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select
|
||||
options={[DEPLOY_TARGET_CERTIFICATE].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.ksyun_slb_deploy_target.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
placeholder={t("workflow_node.deploy.form.shared_deploy_target.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === DEPLOY_TARGET_CERTIFICATE}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.ksyun_slb_certificate_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ksyun_slb_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.ksyun_slb_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
deployTarget: DEPLOY_TARGET_CERTIFICATE,
|
||||
certificateId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
region: z.string().nonempty(),
|
||||
deployTarget: z.enum([DEPLOY_TARGET_CERTIFICATE]),
|
||||
certificateId: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.deployTarget) {
|
||||
case DEPLOY_TARGET_CERTIFICATE:
|
||||
{
|
||||
const scCertificateId = z.string().nonempty();
|
||||
const spCertificateId = scCertificateId.safeParse(values.certificateId);
|
||||
if (!spCertificateId.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spCertificateId.error).errors.join(),
|
||||
path: ["certificateId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderKsyunSLB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Radio } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
|
||||
import { isDomain } from "@/utils/validator";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const MULTIPLE_INPUT_SEPARATOR = ";";
|
||||
|
||||
const DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderWangsuCDN = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domainMatchPattern"]}
|
||||
initialValue={initialValues.domainMatchPattern}
|
||||
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
|
||||
extra={
|
||||
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
|
||||
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.option.exact.help.wildcard") }}></span>
|
||||
) : (
|
||||
void 0
|
||||
)
|
||||
}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Radio.Group
|
||||
options={[DOMAIN_MATCH_PATTERN_EXACT].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domains"]}
|
||||
initialValue={initialValues.domains}
|
||||
label={t("workflow_node.deploy.form.wangsu_cdn_domains.label")}
|
||||
extra={t("workflow_node.deploy.form.wangsu_cdn_domains.help")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<MultipleSplitValueInput
|
||||
modalTitle={t("workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.title")}
|
||||
placeholder={t("workflow_node.deploy.form.wangsu_cdn_domains.placeholder")}
|
||||
placeholderInModal={t("workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.placeholder")}
|
||||
separator={MULTIPLE_INPUT_SEPARATOR}
|
||||
splitOptions={{ removeEmpty: true, trimSpace: true }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
|
||||
domains: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
domainMatchPattern: z.string().nonempty().default(DOMAIN_MATCH_PATTERN_EXACT),
|
||||
domains: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
if (values.domainMatchPattern) {
|
||||
switch (values.domainMatchPattern) {
|
||||
case DOMAIN_MATCH_PATTERN_EXACT:
|
||||
{
|
||||
const scDomains = z
|
||||
.string()
|
||||
.nonempty()
|
||||
.refine((v) => v.split(MULTIPLE_INPUT_SEPARATOR).every((e) => isDomain(e, { allowWildcard: true })), t("common.errmsg.domain_invalid"));
|
||||
const spDomains = scDomains.safeParse(values.domains);
|
||||
if (!spDomains.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomains.error).errors.join(),
|
||||
path: ["domains"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderWangsuCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Radio, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { isDomain } from "@/utils/validator";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderWangsuCDNPro = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "environment"]}
|
||||
initialValue={initialValues.environment}
|
||||
label={t("workflow_node.deploy.form.wangsu_cdnpro_environment.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select
|
||||
options={["production", "staging"].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.wangsu_cdnpro_environment.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
placeholder={t("workflow_node.deploy.form.wangsu_cdnpro_environment.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domainMatchPattern"]}
|
||||
initialValue={initialValues.domainMatchPattern}
|
||||
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
|
||||
extra={
|
||||
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
|
||||
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.option.exact.help.wildcard") }}></span>
|
||||
) : (
|
||||
void 0
|
||||
)
|
||||
}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Radio.Group
|
||||
options={[DOMAIN_MATCH_PATTERN_EXACT].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.wangsu_cdnpro_domain.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.wangsu_cdnpro_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.wangsu_cdnpro_certificate_id.label")}
|
||||
extra={t("workflow_node.deploy.form.wangsu_cdnpro_certificate_id.help")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.wangsu_cdnpro_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.wangsu_cdnpro_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "webhookId"]}
|
||||
initialValue={initialValues.webhookId}
|
||||
label={t("workflow_node.deploy.form.wangsu_cdnpro_webhook_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.wangsu_cdnpro_webhook_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.wangsu_cdnpro_webhook_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
environment: "production",
|
||||
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
environment: z.enum(["production", "staging"]).default("production"),
|
||||
domainMatchPattern: z.string().nonempty().default(DOMAIN_MATCH_PATTERN_EXACT),
|
||||
domain: z.string().nullish(),
|
||||
certificateId: z.string().nullish(),
|
||||
webhookId: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
if (values.domainMatchPattern) {
|
||||
switch (values.domainMatchPattern) {
|
||||
case DOMAIN_MATCH_PATTERN_EXACT:
|
||||
{
|
||||
const scDomain = z.string().refine((v) => isDomain(v, { allowWildcard: true }), t("common.errmsg.domain_invalid"));
|
||||
const spDomain = scDomain.safeParse(values.domain);
|
||||
if (!spDomain.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomain.error).errors.join(),
|
||||
path: ["domain"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderWangsuCDNPro, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderWangsuCertificate = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "certificateId"]}
|
||||
initialValue={initialValues.certificateId}
|
||||
label={t("workflow_node.deploy.form.wangsu_certificate_id.label")}
|
||||
extra={t("workflow_node.deploy.form.wangsu_certificate_id.help")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.wangsu_certificate_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.wangsu_certificate_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
certificateId: z.string().nullish(),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderWangsuCertificate, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -50,7 +50,7 @@ export const NodeConfigDrawer = ({ children, afterClose, anchor, footer = true,
|
||||
setFormPending(true);
|
||||
try {
|
||||
applyTrimmedFormValues(formInst);
|
||||
formValues = await formInst.validateFields();
|
||||
formValues = { ...formInst.getFieldsValue(true), ...(await formInst.validateFields()) };
|
||||
} catch (err) {
|
||||
message.warning(t("common.errmsg.form_invalid"));
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
||||
AXISNOW: "axisnow",
|
||||
AZURE: "azure",
|
||||
BAIDUCLOUD: "baiducloud",
|
||||
BAISHAN: "baishan",
|
||||
BAOTAPANEL: "baotapanel",
|
||||
BAOTAPANELGO: "baotapanelgo",
|
||||
BAOTAWAF: "baotawaf",
|
||||
@@ -86,7 +85,6 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
||||
IONOS: "ionos",
|
||||
JDCLOUD: "jdcloud",
|
||||
KONG: "kong",
|
||||
KSYUN: "ksyun",
|
||||
LARKBOT: "larkbot",
|
||||
LECDN: "lecdn",
|
||||
LETSENCRYPT: "letsencrypt",
|
||||
@@ -135,7 +133,6 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
||||
VERCEL: "vercel",
|
||||
VOLCENGINE: "volcengine",
|
||||
VULTR: "vultr",
|
||||
WANGSU: "wangsu",
|
||||
WEBHOOK: "webhook",
|
||||
WECOMBOT: "wecombot",
|
||||
WESTCN: "westcn",
|
||||
@@ -199,9 +196,6 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.VERCEL, "provider.vercel", "/imgs/providers/vercel.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.CPANEL, "provider.cpanel", "/imgs/providers/cpanel.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
|
||||
[ACCESS_PROVIDERS.BAISHAN, "provider.baishan", "/imgs/providers/baishan.png", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.KSYUN, "provider.ksyun", "/imgs/providers/ksyun.svg", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.WANGSU, "provider.wangsu", "/imgs/providers/wangsu.svg", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.MOHUA, "provider.mohua", "/imgs/providers/mohua.png", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.UNICLOUD, "provider.unicloud", "/imgs/providers/unicloud.png", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.CACHEFLY, "provider.cachefly", "/imgs/providers/cachefly.png", [ACCESS_USAGES.HOSTING]],
|
||||
@@ -642,7 +636,6 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
BAIDUCLOUD_BLB: `${ACCESS_PROVIDERS.BAIDUCLOUD}-blb`,
|
||||
BAIDUCLOUD_CDN: `${ACCESS_PROVIDERS.BAIDUCLOUD}-cdn`,
|
||||
BAIDUCLOUD_CERT: `${ACCESS_PROVIDERS.BAIDUCLOUD}-cert`,
|
||||
BAISHAN_CDN: `${ACCESS_PROVIDERS.BAISHAN}-cdn`,
|
||||
BAOTAPANEL: `${ACCESS_PROVIDERS.BAOTAPANEL}`,
|
||||
BAOTAPANEL_CONSOLE: `${ACCESS_PROVIDERS.BAOTAPANEL}-console`,
|
||||
BAOTAPANELGO: `${ACCESS_PROVIDERS.BAOTAPANELGO}`,
|
||||
@@ -695,9 +688,6 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
JDCLOUD_SSL: `${ACCESS_PROVIDERS.JDCLOUD}-ssl`,
|
||||
JDCLOUD_WAF: `${ACCESS_PROVIDERS.JDCLOUD}-waf`,
|
||||
KONG: `${ACCESS_PROVIDERS.KONG}`,
|
||||
KSYUN_CDN: `${ACCESS_PROVIDERS.KSYUN}-cdn`,
|
||||
KSYUN_KCM: `${ACCESS_PROVIDERS.KSYUN}-kcm`,
|
||||
KSYUN_SLB: `${ACCESS_PROVIDERS.KSYUN}-slb`,
|
||||
LECDN: `${ACCESS_PROVIDERS.LECDN}`,
|
||||
LINODE_LOS: `${ACCESS_PROVIDERS.LINODE}-los`,
|
||||
LOCAL: `${ACCESS_PROVIDERS.LOCAL}`,
|
||||
@@ -753,9 +743,6 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
VOLCENGINE_TOS: `${ACCESS_PROVIDERS.VOLCENGINE}-tos`,
|
||||
VOLCENGINE_VOD: `${ACCESS_PROVIDERS.VOLCENGINE}-vod`,
|
||||
VOLCENGINE_WAF: `${ACCESS_PROVIDERS.VOLCENGINE}-waf`,
|
||||
WANGSU_CDN: `${ACCESS_PROVIDERS.WANGSU}-cdn`,
|
||||
WANGSU_CDNPRO: `${ACCESS_PROVIDERS.WANGSU}-cdnpro`,
|
||||
WANGSU_CERTIFICATE: `${ACCESS_PROVIDERS.WANGSU}-certificate`,
|
||||
WEBHOOK: `${ACCESS_PROVIDERS.WEBHOOK}`,
|
||||
YANDEXCLOUD_CERTIFICATEMANAGER: `${ACCESS_PROVIDERS.YANDEXCLOUD}-certificatemanager`,
|
||||
} as const);
|
||||
@@ -895,9 +882,6 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_LIVE, "provider.jdcloud_live", DEPLOYMENT_CATEGORIES.AV],
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_VOD, "provider.jdcloud_vod", DEPLOYMENT_CATEGORIES.AV],
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_SSL, "provider.jdcloud_ssl_upload", DEPLOYMENT_CATEGORIES.SSL],
|
||||
[DEPLOYMENT_PROVIDERS.KSYUN_CDN, "provider.ksyun_cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.KSYUN_SLB, "provider.ksyun_slb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[DEPLOYMENT_PROVIDERS.KSYUN_KCM, "provider.ksyun_kcm_upload", DEPLOYMENT_CATEGORIES.SSL],
|
||||
[DEPLOYMENT_PROVIDERS.QINGCLOUD_LB, "provider.qingcloud_lb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_US3, "provider.ucloud_us3", DEPLOYMENT_CATEGORIES.STORAGE],
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UCDN, "provider.ucloud_ucdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
@@ -905,10 +889,6 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UALB, "provider.ucloud_ualb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UEWAF, "provider.ucloud_uewaf", DEPLOYMENT_CATEGORIES.FIREWALL],
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UPATHX, "provider.ucloud_upathx", DEPLOYMENT_CATEGORIES.ACCELERATOR],
|
||||
[DEPLOYMENT_PROVIDERS.BAISHAN_CDN, "provider.baishan_cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CDN, "provider.wangsu_cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CDNPRO, "provider.wangsu_cdnpro", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.WANGSU_CERTIFICATE, "provider.wangsu_certificate_upload", DEPLOYMENT_CATEGORIES.SSL],
|
||||
[DEPLOYMENT_PROVIDERS.RAINYUN_RCDN, "provider.rainyun_rcdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.RAINYUN_SSLCENTER, "provider.rainyun_sslcenter_upload", DEPLOYMENT_CATEGORIES.SSL],
|
||||
[DEPLOYMENT_PROVIDERS.UNICLOUD_WEBHOST, "provider.unicloud_webhost", DEPLOYMENT_CATEGORIES.WEBSITE],
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user