mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-19 01:41:55 +08:00
Merge pull request #416 from fudiwei/feat/new-workflow
feat: more providers
This commit is contained in:
commit
23f83b9377
@ -125,6 +125,7 @@ make local.run
|
||||
| [七牛云](https://www.qiniu.com/) | 可部署到七牛云 CDN |
|
||||
| [多吉云](https://www.dogecloud.com/) | 可部署到多吉云 CDN |
|
||||
| [BytePlus](https://www.byteplus.com/) | 可部署到 BytePlus CDN 等服务 |
|
||||
| [优刻得](https://www.ucloud.cn/) | 可部署到优刻得 US3、UCDN 等服务 |
|
||||
|
||||
</details>
|
||||
|
||||
|
@ -124,6 +124,7 @@ The following hosting providers are supported:
|
||||
| [Qiniu Cloud](https://www.qiniu.com/) | Supports deployment to Qiniu Cloud CDN |
|
||||
| [Doge Cloud](https://www.dogecloud.com/) | Supports deployment to Doge Cloud CDN |
|
||||
| [BytePlus](https://www.byteplus.com/) | Supports deployment to BytePlus CDN |
|
||||
| [UCloud](https://www.ucloud-global.com/) | Supports deployment to UCloud US3, UCDN |
|
||||
|
||||
</details>
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -34,6 +34,7 @@ require (
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1080
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1065
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1065
|
||||
github.com/ucloud/ucloud-sdk-go v0.22.31
|
||||
github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.8
|
||||
github.com/volcengine/volc-sdk-golang v1.0.189
|
||||
github.com/volcengine/volcengine-go-sdk v1.0.177
|
||||
@ -80,6 +81,7 @@ require (
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.mongodb.org/mongo-driver v1.12.0 // indirect
|
||||
|
5
go.sum
5
go.sum
@ -783,10 +783,13 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
@ -847,6 +850,8 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaO
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ucloud/ucloud-sdk-go v0.22.31 h1:izZK+Re9ZkJAd1fHSVpFzgh8uKda4f5G6++iUw4n/mE=
|
||||
github.com/ucloud/ucloud-sdk-go v0.22.31/go.mod h1:dyLmFHmUfgb4RZKYQP9IArlvQ2pxzFthfhwxRzOEPIw=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
|
@ -27,6 +27,8 @@ import (
|
||||
providerTencentCloudCSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-css"
|
||||
providerTencentCloudECDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ecdn"
|
||||
providerTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-eo"
|
||||
providerUCloudUCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-ucdn"
|
||||
providerUCloudUS3 "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-us3"
|
||||
providerVolcEngineCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-cdn"
|
||||
providerVolcEngineCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-clb"
|
||||
providerVolcEngineDCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-dcdn"
|
||||
@ -352,6 +354,39 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
case domain.DeployProviderTypeUCloudUCDN, domain.DeployProviderTypeUCloudUS3:
|
||||
{
|
||||
access := domain.AccessConfigForUCloud{}
|
||||
if err := maps.Decode(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to decode provider access config: %w", err)
|
||||
}
|
||||
|
||||
switch options.Provider {
|
||||
case domain.DeployProviderTypeUCloudUCDN:
|
||||
deployer, err := providerUCloudUCDN.NewWithLogger(&providerUCloudUCDN.UCloudUCDNDeployerConfig{
|
||||
PrivateKey: access.PrivateKey,
|
||||
PublicKey: access.PublicKey,
|
||||
ProjectId: access.ProjectId,
|
||||
DomainId: maps.GetValueAsString(options.ProviderDeployConfig, "domainId"),
|
||||
}, logger)
|
||||
return deployer, logger, err
|
||||
|
||||
case domain.DeployProviderTypeUCloudUS3:
|
||||
deployer, err := providerUCloudUS3.NewWithLogger(&providerUCloudUS3.UCloudUS3DeployerConfig{
|
||||
PrivateKey: access.PrivateKey,
|
||||
PublicKey: access.PublicKey,
|
||||
ProjectId: access.ProjectId,
|
||||
Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"),
|
||||
Bucket: maps.GetValueAsString(options.ProviderDeployConfig, "bucket"),
|
||||
Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"),
|
||||
}, logger)
|
||||
return deployer, logger, err
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
case domain.DeployProviderTypeVolcEngineCDN, domain.DeployProviderTypeVolcEngineCLB, domain.DeployProviderTypeVolcEngineDCDN, domain.DeployProviderTypeVolcEngineLive, domain.DeployProviderTypeVolcEngineTOS:
|
||||
{
|
||||
access := domain.AccessConfigForVolcEngine{}
|
||||
|
@ -25,9 +25,9 @@ func (a *Access) UnmarshalConfigToMap() (map[string]any, error) {
|
||||
|
||||
type AccessConfigForACMEHttpReq struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
Mode string `json:"mode"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForAliyun struct {
|
||||
@ -79,7 +79,7 @@ type AccessConfigForHuaweiCloud struct {
|
||||
type AccessConfigForLocal struct{}
|
||||
|
||||
type AccessConfigForKubernetes struct {
|
||||
KubeConfig string `json:"kubeConfig"`
|
||||
KubeConfig string `json:"kubeConfig,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForNameDotCom struct {
|
||||
@ -105,9 +105,9 @@ type AccessConfigForSSH struct {
|
||||
Host string `json:"host"`
|
||||
Port int32 `json:"port"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Key string `json:"key"`
|
||||
KeyPassphrase string `json:"keyPassphrase"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
KeyPassphrase string `json:"keyPassphrase,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForTencentCloud struct {
|
||||
@ -115,6 +115,12 @@ type AccessConfigForTencentCloud struct {
|
||||
SecretKey string `json:"secretKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForUCloud struct {
|
||||
PrivateKey string `json:"privateKey"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
ProjectId string `json:"projectId,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForVolcEngine struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
|
@ -27,6 +27,7 @@ const (
|
||||
AccessProviderTypeQiniu = AccessProviderType("qiniu")
|
||||
AccessProviderTypeSSH = AccessProviderType("ssh")
|
||||
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
|
||||
AccessProviderTypeUCloud = AccessProviderType("ucloud")
|
||||
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
|
||||
AccessProviderTypeWebhook = AccessProviderType("webhook")
|
||||
)
|
||||
@ -92,6 +93,8 @@ const (
|
||||
DeployProviderTypeTencentCloudCSS = DeployProviderType("tencentcloud-css")
|
||||
DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn")
|
||||
DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo")
|
||||
DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn")
|
||||
DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3")
|
||||
DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn")
|
||||
DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb")
|
||||
DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn")
|
||||
|
132
internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go
Normal file
132
internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go
Normal file
@ -0,0 +1,132 @@
|
||||
package uclouducdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
xerrors "github.com/pkg/errors"
|
||||
uCdn "github.com/ucloud/ucloud-sdk-go/services/ucdn"
|
||||
usdk "github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||
uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploaderSsl "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl"
|
||||
)
|
||||
|
||||
type UCloudUCDNDeployerConfig struct {
|
||||
// 优刻得 API 私钥。
|
||||
PrivateKey string `json:"privateKey"`
|
||||
// 优刻得 API 公钥。
|
||||
PublicKey string `json:"publicKey"`
|
||||
// 优刻得项目 ID。
|
||||
ProjectId string `json:"projectId,omitempty"`
|
||||
// 加速域名 ID。
|
||||
DomainId string `json:"domainId"`
|
||||
}
|
||||
|
||||
type UCloudUCDNDeployer struct {
|
||||
config *UCloudUCDNDeployerConfig
|
||||
logger logger.Logger
|
||||
sdkClient *uCdn.UCDNClient
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*UCloudUCDNDeployer)(nil)
|
||||
|
||||
func New(config *UCloudUCDNDeployerConfig) (*UCloudUCDNDeployer, error) {
|
||||
return NewWithLogger(config, logger.NewNilLogger())
|
||||
}
|
||||
|
||||
func NewWithLogger(config *UCloudUCDNDeployerConfig, logger logger.Logger) (*UCloudUCDNDeployer, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is nil")
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.PrivateKey, config.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
||||
}
|
||||
|
||||
uploader, err := uploaderSsl.New(&uploaderSsl.UCloudUSSLUploaderConfig{
|
||||
PrivateKey: config.PrivateKey,
|
||||
PublicKey: config.PublicKey,
|
||||
ProjectId: config.ProjectId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
||||
}
|
||||
|
||||
return &UCloudUCDNDeployer{
|
||||
logger: logger,
|
||||
config: config,
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *UCloudUCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
||||
// 上传证书到 USSL
|
||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
||||
}
|
||||
|
||||
d.logger.Logt("certificate file uploaded", upres)
|
||||
|
||||
// 获取加速域名配置
|
||||
// REF: https://docs.ucloud.cn/api/ucdn-api/get_ucdn_domain_config
|
||||
getUcdnDomainConfigReq := d.sdkClient.NewGetUcdnDomainConfigRequest()
|
||||
getUcdnDomainConfigReq.DomainId = []string{d.config.DomainId}
|
||||
if d.config.ProjectId != "" {
|
||||
getUcdnDomainConfigReq.ProjectId = usdk.String(d.config.ProjectId)
|
||||
}
|
||||
getUcdnDomainConfigResp, err := d.sdkClient.GetUcdnDomainConfig(getUcdnDomainConfigReq)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.GetUcdnDomainConfig'")
|
||||
} else if len(getUcdnDomainConfigResp.DomainList) == 0 {
|
||||
return nil, errors.New("no domain found")
|
||||
}
|
||||
|
||||
d.logger.Logt("已查询到加速域名配置", getUcdnDomainConfigResp)
|
||||
|
||||
// 更新 HTTPS 加速配置
|
||||
// REF: https://docs.ucloud.cn/api/ucdn-api/update_ucdn_domain_https_config_v2
|
||||
certId, _ := strconv.Atoi(upres.CertId)
|
||||
updateUcdnDomainHttpsConfigV2Req := d.sdkClient.NewUpdateUcdnDomainHttpsConfigV2Request()
|
||||
updateUcdnDomainHttpsConfigV2Req.DomainId = usdk.String(d.config.DomainId)
|
||||
updateUcdnDomainHttpsConfigV2Req.HttpsStatusCn = usdk.String(getUcdnDomainConfigResp.DomainList[0].HttpsStatusCn)
|
||||
updateUcdnDomainHttpsConfigV2Req.HttpsStatusAbroad = usdk.String(getUcdnDomainConfigResp.DomainList[0].HttpsStatusAbroad)
|
||||
updateUcdnDomainHttpsConfigV2Req.HttpsStatusAbroad = usdk.String(getUcdnDomainConfigResp.DomainList[0].HttpsStatusAbroad)
|
||||
updateUcdnDomainHttpsConfigV2Req.CertId = usdk.Int(certId)
|
||||
updateUcdnDomainHttpsConfigV2Req.CertName = usdk.String(upres.CertName)
|
||||
updateUcdnDomainHttpsConfigV2Req.CertType = usdk.String("ussl")
|
||||
if d.config.ProjectId != "" {
|
||||
updateUcdnDomainHttpsConfigV2Req.ProjectId = usdk.String(d.config.ProjectId)
|
||||
}
|
||||
updateUcdnDomainHttpsConfigV2Resp, err := d.sdkClient.UpdateUcdnDomainHttpsConfigV2(updateUcdnDomainHttpsConfigV2Req)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.UpdateUcdnDomainHttpsConfigV2'")
|
||||
}
|
||||
|
||||
d.logger.Logt("已更新 HTTPS 加速配置", updateUcdnDomainHttpsConfigV2Resp)
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(privateKey, publicKey string) (*uCdn.UCDNClient, error) {
|
||||
cfg := usdk.NewConfig()
|
||||
|
||||
credential := uAuth.NewCredential()
|
||||
credential.PrivateKey = privateKey
|
||||
credential.PublicKey = publicKey
|
||||
|
||||
client := uCdn.NewClient(&cfg, &credential)
|
||||
return client, nil
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package uclouducdn_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-ucdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fPrivateKey string
|
||||
fPublicKey string
|
||||
fDomainId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_UCLOUDUCDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fPrivateKey, argsPrefix+"PRIVATEKEY", "", "")
|
||||
flag.StringVar(&fPublicKey, argsPrefix+"PUBLICKEY", "", "")
|
||||
flag.StringVar(&fDomainId, argsPrefix+"DOMAINID", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ucloud_ucdn_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUCDN_PRIVATEKEY="your-private-key" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUCDN_PUBLICKEY="your-public-key" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUCDN_DOMAINID="your-domain-id"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("PRIVATEKEY: %v", fPrivateKey),
|
||||
fmt.Sprintf("PUBLICKEY: %v", fPublicKey),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomainId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.New(&provider.UCloudUCDNDeployerConfig{
|
||||
PrivateKey: fPrivateKey,
|
||||
PublicKey: fPublicKey,
|
||||
DomainId: fDomainId,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
116
internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go
Normal file
116
internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go
Normal file
@ -0,0 +1,116 @@
|
||||
package ucloudus3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
xerrors "github.com/pkg/errors"
|
||||
usdk "github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||
uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/logger"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploaderSsl "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl"
|
||||
usdkFile "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ufile"
|
||||
)
|
||||
|
||||
type UCloudUS3DeployerConfig struct {
|
||||
// 优刻得 API 私钥。
|
||||
PrivateKey string `json:"privateKey"`
|
||||
// 优刻得 API 公钥。
|
||||
PublicKey string `json:"publicKey"`
|
||||
// 优刻得项目 ID。
|
||||
ProjectId string `json:"projectId,omitempty"`
|
||||
// 优刻得地域。
|
||||
Region string `json:"region"`
|
||||
// 存储桶名。
|
||||
Bucket string `json:"bucket"`
|
||||
// 自定义域名(不支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type UCloudUS3Deployer struct {
|
||||
config *UCloudUS3DeployerConfig
|
||||
logger logger.Logger
|
||||
sdkClient *usdkFile.UFileClient
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*UCloudUS3Deployer)(nil)
|
||||
|
||||
func New(config *UCloudUS3DeployerConfig) (*UCloudUS3Deployer, error) {
|
||||
return NewWithLogger(config, logger.NewNilLogger())
|
||||
}
|
||||
|
||||
func NewWithLogger(config *UCloudUS3DeployerConfig, logger logger.Logger) (*UCloudUS3Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is nil")
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.PrivateKey, config.PublicKey, config.Region)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
||||
}
|
||||
|
||||
uploader, err := uploaderSsl.New(&uploaderSsl.UCloudUSSLUploaderConfig{
|
||||
PrivateKey: config.PrivateKey,
|
||||
PublicKey: config.PublicKey,
|
||||
ProjectId: config.ProjectId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to create ssl uploader")
|
||||
}
|
||||
|
||||
return &UCloudUS3Deployer{
|
||||
logger: logger,
|
||||
config: config,
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *UCloudUS3Deployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
|
||||
// 上传证书到 USSL
|
||||
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to upload certificate file")
|
||||
}
|
||||
|
||||
d.logger.Logt("certificate file uploaded", upres)
|
||||
|
||||
// 添加 SSL 证书
|
||||
// REF: https://docs.ucloud.cn/api/ufile-api/add_ufile_ssl_cert
|
||||
addUFileSSLCertReq := d.sdkClient.NewAddUFileSSLCertRequest()
|
||||
addUFileSSLCertReq.BucketName = usdk.String(d.config.Bucket)
|
||||
addUFileSSLCertReq.Domain = usdk.String(d.config.Domain)
|
||||
addUFileSSLCertReq.USSLId = usdk.String(upres.CertId)
|
||||
addUFileSSLCertReq.CertificateName = usdk.String(upres.CertName)
|
||||
if d.config.ProjectId != "" {
|
||||
addUFileSSLCertReq.ProjectId = usdk.String(d.config.ProjectId)
|
||||
}
|
||||
addUFileSSLCertResp, err := d.sdkClient.AddUFileSSLCert(addUFileSSLCertReq)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.AddUFileSSLCert'")
|
||||
}
|
||||
|
||||
d.logger.Logt("添加 SSL 证书", addUFileSSLCertResp)
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(privateKey, publicKey, region string) (*usdkFile.UFileClient, error) {
|
||||
cfg := usdk.NewConfig()
|
||||
cfg.Region = region
|
||||
|
||||
credential := uAuth.NewCredential()
|
||||
credential.PrivateKey = privateKey
|
||||
credential.PublicKey = publicKey
|
||||
|
||||
client := usdkFile.NewClient(&cfg, &credential)
|
||||
return client, nil
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package ucloudus3_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-us3"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fPrivateKey string
|
||||
fPublicKey string
|
||||
fRegion string
|
||||
fBucket string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_UCLOUDUS3_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fPrivateKey, argsPrefix+"PRIVATEKEY", "", "")
|
||||
flag.StringVar(&fPublicKey, argsPrefix+"PUBLICKEY", "", "")
|
||||
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
|
||||
flag.StringVar(&fBucket, argsPrefix+"BUCKET", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ucloud_us3_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUS3_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUS3_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUS3_PRIVATEKEY="your-private-key" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUS3_PUBLICKEY="your-public-key" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUS3_REGION="cn-bj2" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUS3_BUCKET="your-us3-bucket" \
|
||||
--CERTIMATE_DEPLOYER_UCLOUDUS3_DOMAIN="example.com"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("PRIVATEKEY: %v", fPrivateKey),
|
||||
fmt.Sprintf("PUBLICKEY: %v", fPublicKey),
|
||||
fmt.Sprintf("REGION: %v", fRegion),
|
||||
fmt.Sprintf("BUCKET: %v", fBucket),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.New(&provider.UCloudUS3DeployerConfig{
|
||||
PrivateKey: fPrivateKey,
|
||||
PublicKey: fPublicKey,
|
||||
Region: fRegion,
|
||||
Bucket: fBucket,
|
||||
Domain: fDomain,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
220
internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go
Normal file
220
internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go
Normal file
@ -0,0 +1,220 @@
|
||||
package ucloudussl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
xerrors "github.com/pkg/errors"
|
||||
usdk "github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||
uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
x509util "github.com/usual2970/certimate/internal/pkg/utils/x509"
|
||||
usdkSsl "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ussl"
|
||||
)
|
||||
|
||||
type UCloudUSSLUploaderConfig struct {
|
||||
// 优刻得 API 私钥。
|
||||
PrivateKey string `json:"privateKey"`
|
||||
// 优刻得 API 公钥。
|
||||
PublicKey string `json:"publicKey"`
|
||||
// 优刻得项目 ID。
|
||||
ProjectId string `json:"projectId,omitempty"`
|
||||
}
|
||||
|
||||
type UCloudUSSLUploader struct {
|
||||
config *UCloudUSSLUploaderConfig
|
||||
sdkClient *usdkSsl.USSLClient
|
||||
}
|
||||
|
||||
var _ uploader.Uploader = (*UCloudUSSLUploader)(nil)
|
||||
|
||||
func New(config *UCloudUSSLUploaderConfig) (*UCloudUSSLUploader, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.PrivateKey, config.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to create sdk client")
|
||||
}
|
||||
|
||||
return &UCloudUSSLUploader{
|
||||
config: config,
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *UCloudUSSLUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 生成新证书名(需符合优刻得命名规则)
|
||||
var certId, certName string
|
||||
certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
|
||||
|
||||
// 生成优刻得所需的证书参数
|
||||
certPemBase64 := base64.StdEncoding.EncodeToString([]byte(certPem))
|
||||
privkeyPemBase64 := base64.StdEncoding.EncodeToString([]byte(privkeyPem))
|
||||
certMd5 := md5.Sum([]byte(certPemBase64 + privkeyPemBase64))
|
||||
certMd5Hex := hex.EncodeToString(certMd5[:])
|
||||
|
||||
// 上传托管证书
|
||||
// REF: https://docs.ucloud.cn/api/usslcertificate-api/upload_normal_certificate
|
||||
uploadNormalCertificateReq := u.sdkClient.NewUploadNormalCertificateRequest()
|
||||
uploadNormalCertificateReq.CertificateName = usdk.String(certName)
|
||||
uploadNormalCertificateReq.SslPublicKey = usdk.String(certPemBase64)
|
||||
uploadNormalCertificateReq.SslPrivateKey = usdk.String(privkeyPemBase64)
|
||||
uploadNormalCertificateReq.SslMD5 = usdk.String(certMd5Hex)
|
||||
if u.config.ProjectId != "" {
|
||||
uploadNormalCertificateReq.ProjectId = usdk.String(u.config.ProjectId)
|
||||
}
|
||||
uploadNormalCertificateResp, err := u.sdkClient.UploadNormalCertificate(uploadNormalCertificateReq)
|
||||
if err != nil {
|
||||
if uploadNormalCertificateResp != nil && uploadNormalCertificateResp.GetRetCode() == 80035 {
|
||||
return u.getExistCert(ctx, certPem, privkeyPem)
|
||||
}
|
||||
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ussl.UploadNormalCertificate'")
|
||||
}
|
||||
|
||||
certId = fmt.Sprintf("%d", uploadNormalCertificateResp.CertificateID)
|
||||
return &uploader.UploadResult{
|
||||
CertId: certId,
|
||||
CertName: certName,
|
||||
ExtendedData: map[string]interface{}{
|
||||
"resourceId": uploadNormalCertificateResp.LongResourceID,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *UCloudUSSLUploader) getExistCert(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 解析证书内容
|
||||
certX509, err := x509util.ParseCertificateFromPEM(certPem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 遍历获取用户证书列表,避免重复上传
|
||||
// REF: https://docs.ucloud.cn/api/usslcertificate-api/get_certificate_list
|
||||
// REF: https://docs.ucloud.cn/api/usslcertificate-api/download_certificate
|
||||
getCertificateListPage := int(1)
|
||||
getCertificateListLimit := int(1000)
|
||||
for {
|
||||
getCertificateListReq := u.sdkClient.NewGetCertificateListRequest()
|
||||
getCertificateListReq.Mode = usdk.String("trust")
|
||||
getCertificateListReq.Domain = usdk.String(certX509.Subject.CommonName)
|
||||
getCertificateListReq.Sort = usdk.String("2")
|
||||
getCertificateListReq.Page = usdk.Int(getCertificateListPage)
|
||||
getCertificateListReq.PageSize = usdk.Int(getCertificateListLimit)
|
||||
if u.config.ProjectId != "" {
|
||||
getCertificateListReq.ProjectId = usdk.String(u.config.ProjectId)
|
||||
}
|
||||
getCertificateListResp, err := u.sdkClient.GetCertificateList(getCertificateListReq)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ussl.GetCertificateList'")
|
||||
}
|
||||
|
||||
if getCertificateListResp.CertificateList != nil {
|
||||
for _, certInfo := range getCertificateListResp.CertificateList {
|
||||
// 优刻得未提供可唯一标识证书的字段,只能通过多个字段尝试匹配来判断是否为同一证书
|
||||
// 先分别匹配证书的域名、品牌、有效期,再匹配签名算法
|
||||
|
||||
if len(certX509.DNSNames) == 0 || certInfo.Domains != strings.Join(certX509.DNSNames, ",") {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(certX509.Issuer.Organization) == 0 || certInfo.Brand != certX509.Issuer.Organization[0] {
|
||||
continue
|
||||
}
|
||||
|
||||
if int64(certInfo.NotBefore) != certX509.NotBefore.UnixMilli() || int64(certInfo.NotAfter) != certX509.NotAfter.UnixMilli() {
|
||||
continue
|
||||
}
|
||||
|
||||
getCertificateDetailInfoReq := u.sdkClient.NewGetCertificateDetailInfoRequest()
|
||||
getCertificateDetailInfoReq.CertificateID = usdk.Int(certInfo.CertificateID)
|
||||
if u.config.ProjectId != "" {
|
||||
getCertificateDetailInfoReq.ProjectId = usdk.String(u.config.ProjectId)
|
||||
}
|
||||
getCertificateDetailInfoResp, err := u.sdkClient.GetCertificateDetailInfo(getCertificateDetailInfoReq)
|
||||
if err != nil {
|
||||
return nil, xerrors.Wrap(err, "failed to execute sdk request 'ussl.GetCertificateDetailInfo'")
|
||||
}
|
||||
|
||||
switch certX509.SignatureAlgorithm {
|
||||
case x509.SHA256WithRSA:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA256-RSA") {
|
||||
continue
|
||||
}
|
||||
case x509.SHA384WithRSA:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA384-RSA") {
|
||||
continue
|
||||
}
|
||||
case x509.SHA512WithRSA:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA512-RSA") {
|
||||
continue
|
||||
}
|
||||
case x509.SHA256WithRSAPSS:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA256-RSAPSS") {
|
||||
continue
|
||||
}
|
||||
case x509.SHA384WithRSAPSS:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA384-RSAPSS") {
|
||||
continue
|
||||
}
|
||||
case x509.SHA512WithRSAPSS:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA512-RSAPSS") {
|
||||
continue
|
||||
}
|
||||
case x509.ECDSAWithSHA256:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA256") {
|
||||
continue
|
||||
}
|
||||
case x509.ECDSAWithSHA384:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA384") {
|
||||
continue
|
||||
}
|
||||
case x509.ECDSAWithSHA512:
|
||||
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA512") {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
// 未知签名算法,跳过
|
||||
continue
|
||||
}
|
||||
|
||||
return &uploader.UploadResult{
|
||||
CertId: fmt.Sprintf("%d", certInfo.CertificateID),
|
||||
CertName: certInfo.Name,
|
||||
ExtendedData: map[string]interface{}{
|
||||
"resourceId": certInfo.CertificateSN,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if getCertificateListResp.CertificateList == nil || len(getCertificateListResp.CertificateList) < int(getCertificateListLimit) {
|
||||
break
|
||||
} else {
|
||||
getCertificateListPage++
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("no certificate found")
|
||||
}
|
||||
|
||||
func createSdkClient(privateKey, publicKey string) (*usdkSsl.USSLClient, error) {
|
||||
cfg := usdk.NewConfig()
|
||||
|
||||
credential := uAuth.NewCredential()
|
||||
credential.PrivateKey = privateKey
|
||||
credential.PublicKey = publicKey
|
||||
|
||||
client := usdkSsl.NewClient(&cfg, &credential)
|
||||
return client, nil
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package ucloudussl_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fPrivateKey string
|
||||
fPublicKey string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_UPLOADER_UCLOUDUSSL_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fPrivateKey, argsPrefix+"PRIVATEKEY", "", "")
|
||||
flag.StringVar(&fPublicKey, argsPrefix+"PUBLICKEY", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ucloud_ussl_test.go -args \
|
||||
--CERTIMATE_UPLOADER_UCLOUDUSSL_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_UPLOADER_UCLOUDUSSL_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_UPLOADER_UCLOUDUSSL_PRIVATEKEY="your-private-key" \
|
||||
--CERTIMATE_UPLOADER_UCLOUDUSSL_PUBLICKEY="your-public-key"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("PRIVATEKEY: %v", fPrivateKey),
|
||||
fmt.Sprintf("PUBLICKEY: %v", fPublicKey),
|
||||
}, "\n"))
|
||||
|
||||
uploader, err := provider.New(&provider.UCloudUSSLUploaderConfig{
|
||||
PrivateKey: fPrivateKey,
|
||||
PublicKey: fPublicKey,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := uploader.Upload(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
sres, _ := json.Marshal(res)
|
||||
t.Logf("ok: %s", string(sres))
|
||||
})
|
||||
}
|
@ -9,7 +9,7 @@ import (
|
||||
veSession "github.com/volcengine/volcengine-go-sdk/volcengine/session"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
veCertCenter "github.com/usual2970/certimate/internal/pkg/vendors/volcengine-sdk/certcenter"
|
||||
vesdkCc "github.com/usual2970/certimate/internal/pkg/vendors/volcengine-sdk/certcenter"
|
||||
)
|
||||
|
||||
type VolcEngineCertCenterUploaderConfig struct {
|
||||
@ -23,7 +23,7 @@ type VolcEngineCertCenterUploaderConfig struct {
|
||||
|
||||
type VolcEngineCertCenterUploader struct {
|
||||
config *VolcEngineCertCenterUploaderConfig
|
||||
sdkClient *veCertCenter.CertCenter
|
||||
sdkClient *vesdkCc.CertCenter
|
||||
}
|
||||
|
||||
var _ uploader.Uploader = (*VolcEngineCertCenterUploader)(nil)
|
||||
@ -47,8 +47,8 @@ func New(config *VolcEngineCertCenterUploaderConfig) (*VolcEngineCertCenterUploa
|
||||
func (u *VolcEngineCertCenterUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) {
|
||||
// 上传证书
|
||||
// REF: https://www.volcengine.com/docs/6638/1365580
|
||||
importCertificateReq := &veCertCenter.ImportCertificateInput{
|
||||
CertificateInfo: &veCertCenter.ImportCertificateInputCertificateInfo{
|
||||
importCertificateReq := &vesdkCc.ImportCertificateInput{
|
||||
CertificateInfo: &vesdkCc.ImportCertificateInputCertificateInfo{
|
||||
CertificateChain: ve.String(certPem),
|
||||
PrivateKey: ve.String(privkeyPem),
|
||||
},
|
||||
@ -71,7 +71,7 @@ func (u *VolcEngineCertCenterUploader) Upload(ctx context.Context, certPem strin
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*veCertCenter.CertCenter, error) {
|
||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*vesdkCc.CertCenter, error) {
|
||||
if region == "" {
|
||||
region = "cn-beijing" // 证书中心默认区域:北京
|
||||
}
|
||||
@ -83,6 +83,6 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*veCertCenter
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := veCertCenter.New(session)
|
||||
client := vesdkCc.New(session)
|
||||
return client, nil
|
||||
}
|
||||
|
42
internal/pkg/vendors/ucloud-sdk/ufile/apis.go
vendored
Normal file
42
internal/pkg/vendors/ucloud-sdk/ufile/apis.go
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package ufile
|
||||
|
||||
import (
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/request"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/response"
|
||||
)
|
||||
|
||||
type AddUFileSSLCertRequest struct {
|
||||
request.CommonBase
|
||||
|
||||
BucketName *string `required:"true"`
|
||||
Domain *string `required:"true"`
|
||||
CertificateName *string `required:"true"`
|
||||
USSLId *string `required:"false"`
|
||||
}
|
||||
|
||||
type AddUFileSSLCertResponse struct {
|
||||
response.CommonBase
|
||||
}
|
||||
|
||||
func (c *UFileClient) NewAddUFileSSLCertRequest() *AddUFileSSLCertRequest {
|
||||
req := &AddUFileSSLCertRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(false)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *UFileClient) AddUFileSSLCert(req *AddUFileSSLCertRequest) (*AddUFileSSLCertResponse, error) {
|
||||
var err error
|
||||
var res AddUFileSSLCertResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("AddUFileSSLCert", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
18
internal/pkg/vendors/ucloud-sdk/ufile/client.go
vendored
Normal file
18
internal/pkg/vendors/ucloud-sdk/ufile/client.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package ufile
|
||||
|
||||
import (
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
)
|
||||
|
||||
type UFileClient struct {
|
||||
*ucloud.Client
|
||||
}
|
||||
|
||||
func NewClient(config *ucloud.Config, credential *auth.Credential) *UFileClient {
|
||||
meta := ucloud.ClientMeta{Product: "UFile"}
|
||||
client := ucloud.NewClientWithMeta(config, credential, meta)
|
||||
return &UFileClient{
|
||||
client,
|
||||
}
|
||||
}
|
161
internal/pkg/vendors/ucloud-sdk/ussl/apis.go
vendored
Normal file
161
internal/pkg/vendors/ucloud-sdk/ussl/apis.go
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
package ussl
|
||||
|
||||
import (
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/request"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/response"
|
||||
)
|
||||
|
||||
type UploadNormalCertificateRequest struct {
|
||||
request.CommonBase
|
||||
|
||||
CertificateName *string `required:"true"`
|
||||
SslPublicKey *string `required:"true"`
|
||||
SslPrivateKey *string `required:"true"`
|
||||
SslMD5 *string `required:"true"`
|
||||
SslCaKey *string `required:"false"`
|
||||
}
|
||||
|
||||
type UploadNormalCertificateResponse struct {
|
||||
response.CommonBase
|
||||
|
||||
CertificateID int
|
||||
LongResourceID string
|
||||
}
|
||||
|
||||
func (c *USSLClient) NewUploadNormalCertificateRequest() *UploadNormalCertificateRequest {
|
||||
req := &UploadNormalCertificateRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(false)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *USSLClient) UploadNormalCertificate(req *UploadNormalCertificateRequest) (*UploadNormalCertificateResponse, error) {
|
||||
var err error
|
||||
var res UploadNormalCertificateResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("UploadNormalCertificate", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
type GetCertificateListRequest struct {
|
||||
request.CommonBase
|
||||
|
||||
Mode *string `required:"true"`
|
||||
StateCode *string `required:"false"`
|
||||
Brand *string `required:"false"`
|
||||
CaOrganization *string `required:"false"`
|
||||
Domain *string `required:"false"`
|
||||
Sort *string `required:"false"`
|
||||
Page *int `required:"false"`
|
||||
PageSize *int `required:"false"`
|
||||
}
|
||||
|
||||
type GetCertificateListResponse struct {
|
||||
response.CommonBase
|
||||
|
||||
CertificateList []*CertificateListItem
|
||||
TotalCount int
|
||||
}
|
||||
|
||||
func (c *USSLClient) NewGetCertificateListRequest() *GetCertificateListRequest {
|
||||
req := &GetCertificateListRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(false)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *USSLClient) GetCertificateList(req *GetCertificateListRequest) (*GetCertificateListResponse, error) {
|
||||
var err error
|
||||
var res GetCertificateListResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("GetCertificateList", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
type GetCertificateDetailInfoRequest struct {
|
||||
request.CommonBase
|
||||
|
||||
CertificateID *int `required:"true"`
|
||||
}
|
||||
|
||||
type GetCertificateDetailInfoResponse struct {
|
||||
response.CommonBase
|
||||
|
||||
CertificateInfo *CertificateInfo
|
||||
}
|
||||
|
||||
func (c *USSLClient) NewGetCertificateDetailInfoRequest() *GetCertificateDetailInfoRequest {
|
||||
req := &GetCertificateDetailInfoRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(false)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *USSLClient) GetCertificateDetailInfo(req *GetCertificateDetailInfoRequest) (*GetCertificateDetailInfoResponse, error) {
|
||||
var err error
|
||||
var res GetCertificateDetailInfoResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("GetCertificateDetailInfo", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
type DownloadCertificateRequest struct {
|
||||
request.CommonBase
|
||||
|
||||
CertificateID *int `required:"true"`
|
||||
}
|
||||
|
||||
type DownloadCertificateResponse struct {
|
||||
response.CommonBase
|
||||
|
||||
CertificateUrl string
|
||||
CertCA *CertificateDownloadInfo
|
||||
Certificate *CertificateDownloadInfo
|
||||
}
|
||||
|
||||
func (c *USSLClient) NewDownloadCertificateRequest() *DownloadCertificateRequest {
|
||||
req := &DownloadCertificateRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(false)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *USSLClient) DownloadCertificate(req *DownloadCertificateRequest) (*DownloadCertificateResponse, error) {
|
||||
var err error
|
||||
var res DownloadCertificateResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("DownloadCertificate", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
18
internal/pkg/vendors/ucloud-sdk/ussl/client.go
vendored
Normal file
18
internal/pkg/vendors/ucloud-sdk/ussl/client.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package ussl
|
||||
|
||||
import (
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
)
|
||||
|
||||
type USSLClient struct {
|
||||
*ucloud.Client
|
||||
}
|
||||
|
||||
func NewClient(config *ucloud.Config, credential *auth.Credential) *USSLClient {
|
||||
meta := ucloud.ClientMeta{Product: "USSL"}
|
||||
client := ucloud.NewClientWithMeta(config, credential, meta)
|
||||
return &USSLClient{
|
||||
client,
|
||||
}
|
||||
}
|
61
internal/pkg/vendors/ucloud-sdk/ussl/models.go
vendored
Normal file
61
internal/pkg/vendors/ucloud-sdk/ussl/models.go
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
package ussl
|
||||
|
||||
type CertificateListItem struct {
|
||||
CertificateID int
|
||||
CertificateSN string
|
||||
CertificateCat string
|
||||
Mode string
|
||||
Domains string
|
||||
Brand string
|
||||
ValidityPeriod int
|
||||
Type string
|
||||
NotBefore int
|
||||
NotAfter int
|
||||
AlarmState int
|
||||
State string
|
||||
StateCode string
|
||||
Name string
|
||||
MaxDomainsCount int
|
||||
DomainsCount int
|
||||
CaChannel string
|
||||
CSRAlgorithms []CSRAlgorithmInfo
|
||||
TopOrganizationID int
|
||||
OrganizationID int
|
||||
IsFree int
|
||||
YearOfValidity int
|
||||
Channel int
|
||||
CreateTime int
|
||||
CertificateUrl string
|
||||
}
|
||||
|
||||
type CSRAlgorithmInfo struct {
|
||||
Algorithm string
|
||||
AlgorithmOption []string
|
||||
}
|
||||
|
||||
type CertificateInfo struct {
|
||||
Type string
|
||||
CertificateID int
|
||||
CertificateType string
|
||||
CaOrganization string
|
||||
Algorithm string
|
||||
ValidityPeriod int
|
||||
State string
|
||||
StateCode string
|
||||
Name string
|
||||
Brand string
|
||||
Domains string
|
||||
DomainsCount int
|
||||
Mode string
|
||||
CSROnline int
|
||||
CSR string
|
||||
CSRKeyParameter string
|
||||
CSREncryptAlgo string
|
||||
IssuedDate int
|
||||
ExpiredDate int
|
||||
}
|
||||
|
||||
type CertificateDownloadInfo struct {
|
||||
FileData string
|
||||
FileName string
|
||||
}
|
113
migrations/1736861196_updated_access.go
Normal file
113
migrations/1736861196_updated_access.go
Normal file
@ -0,0 +1,113 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/daos"
|
||||
m "github.com/pocketbase/pocketbase/migrations"
|
||||
"github.com/pocketbase/pocketbase/models/schema"
|
||||
)
|
||||
|
||||
func init() {
|
||||
m.Register(func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update
|
||||
edit_provider := &schema.SchemaField{}
|
||||
if err := json.Unmarshal([]byte(`{
|
||||
"system": false,
|
||||
"id": "hwy7m03o",
|
||||
"name": "provider",
|
||||
"type": "select",
|
||||
"required": false,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"maxSelect": 1,
|
||||
"values": [
|
||||
"acmehttpreq",
|
||||
"aliyun",
|
||||
"aws",
|
||||
"azure",
|
||||
"baiducloud",
|
||||
"byteplus",
|
||||
"cloudflare",
|
||||
"dogecloud",
|
||||
"godaddy",
|
||||
"huaweicloud",
|
||||
"k8s",
|
||||
"local",
|
||||
"namedotcom",
|
||||
"namesilo",
|
||||
"powerdns",
|
||||
"qiniu",
|
||||
"ssh",
|
||||
"tencentcloud",
|
||||
"ucloud",
|
||||
"volcengine",
|
||||
"webhook"
|
||||
]
|
||||
}
|
||||
}`), edit_provider); err != nil {
|
||||
return err
|
||||
}
|
||||
collection.Schema.AddField(edit_provider)
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
}, func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update
|
||||
edit_provider := &schema.SchemaField{}
|
||||
if err := json.Unmarshal([]byte(`{
|
||||
"system": false,
|
||||
"id": "hwy7m03o",
|
||||
"name": "provider",
|
||||
"type": "select",
|
||||
"required": false,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"maxSelect": 1,
|
||||
"values": [
|
||||
"acmehttpreq",
|
||||
"aliyun",
|
||||
"aws",
|
||||
"azure",
|
||||
"baiducloud",
|
||||
"byteplus",
|
||||
"cloudflare",
|
||||
"dogecloud",
|
||||
"godaddy",
|
||||
"huaweicloud",
|
||||
"k8s",
|
||||
"local",
|
||||
"namedotcom",
|
||||
"namesilo",
|
||||
"powerdns",
|
||||
"qiniu",
|
||||
"ssh",
|
||||
"tencentcloud",
|
||||
"volcengine",
|
||||
"webhook"
|
||||
]
|
||||
}
|
||||
}`), edit_provider); err != nil {
|
||||
return err
|
||||
}
|
||||
collection.Schema.AddField(edit_provider)
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
})
|
||||
}
|
1
ui/public/imgs/providers/ucloud.svg
Normal file
1
ui/public/imgs/providers/ucloud.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M912.192 1024H111.808A111.808 111.808 0 0 1 0 912.192V111.808C0 50.048 50.048 0 111.808 0h800.384C973.952 0 1024 50.048 1024 111.808v800.384c0 61.76-50.048 111.808-111.808 111.808" fill="#3860F4"></path><path d="M822.208 435.2c0 64.128 0.128 128.32 0 192.448-0.256 134.592-81.216 229.376-214.336 252.416a462.08 462.08 0 0 1-187.136-5.632c-110.528-26.048-187.392-117.76-189.632-230.912-1.536-79.04 0.64-158.144-1.024-237.184-0.512-24.576 9.728-30.272 30.144-26.88 30.336 5.056 42.56-6.848 37.248-37.248-4.288-24.704 7.68-33.408 30.912-29.952 25.984 3.968 38.848-5.056 34.24-33.152-3.008-18.432 3.712-26.304 24.128-26.368 20.416-0.064 24.576 7.68 24.448 26.24-0.64 120.32-0.384 240.64-0.192 360.96 0 30.016 2.304 59.84 19.968 85.568 24 35.008 78.464 50.688 131.072 36.736 42.368-11.2 69.312-37.696 76.16-82.88 5.824-37.76 3.328-75.52 3.456-113.216 0.448-116.864 0.896-233.728-0.384-350.592-0.256-24.32 6.72-31.488 30.72-30.4 41.088 1.92 82.368 1.6 123.52 0.064 20.736-0.704 27.648 4.736 27.2 26.56-1.344 74.432-0.512 148.928-0.512 223.36" fill="#FFFFFF"></path><path d="M249.152 318.976c16.768-2.304 24 2.88 24.064 19.84 0 16.768-4.032 24.448-22.528 24.128-16.768-0.256-21.12-7.168-20.672-22.4 0.384-14.528 2.304-25.472 19.2-21.568M384.64 227.904c-15.808 2.304-22.784-3.392-22.656-20.352 0.128-15.488 3.84-22.656 20.928-22.4 15.168 0.32 22.912 3.52 22.4 20.8-0.448 14.976-3.072 24.832-20.736 21.952M317.76 253.44c16-2.368 22.72 3.648 22.72 20.672s-7.04 21.504-22.656 21.248c-14.272-0.192-20.8-4.48-20.864-19.648-0.128-15.168 3.008-25.088 20.8-22.272M319.36 192.64c13.312-1.536 21.056 1.984 20.928 18.112-0.128 16.896-9.856 17.28-22.208 17.6-13.504 0.32-21.12-2.88-21.056-18.752 0-17.024 9.856-17.92 22.4-16.96M272.192 272.896c2.176 15.36-7.424 15.744-18.944 16.192-14.976 0.64-16.128-7.552-16.448-19.328-0.384-14.848 7.68-16.192 19.52-16.512 14.912-0.448 17.216 7.68 15.872 19.648M190.848 288.896c-12.288 1.664-15.616-4.992-15.168-16 0.32-8.64 1.728-15.616 12.608-16 10.816-0.32 17.152 3.392 17.472 15.232 0.256 10.624-2.24 17.92-14.912 16.768M333.888 150.016c0.128 10.368-6.144 13.44-15.296 13.312-10.432-0.128-17.728-4.032-17.024-15.744 0.64-11.52 9.664-10.304 17.472-10.56 8.96-0.32 15.744 1.92 14.848 12.992M252.8 220.928c-8.64 0.448-15.616-1.152-15.616-12.096 0-8.192 0.128-15.808 11.52-16.128 9.728-0.256 17.6 0.64 17.28 13.696-0.256 9.28-2.816 15.04-13.184 14.528M266.112 150.272c-0.32 7.68-3.712 12.544-12.032 12.032-8.32-0.512-10.88-5.952-11.008-13.44-0.064-8.32 4.352-11.52 12.288-11.392 8.576 0.192 11.328 4.992 10.752 12.8M186.496 198.336c6.976 0 13.376 1.024 14.208 9.856 0.768 8.064-3.2 12.352-11.008 12.992-7.168 0.512-13.248-0.64-13.632-9.792-0.384-7.424 1.28-13.184 10.432-13.056M191.36 143.552c2.752 2.432 6.784 4.288 6.784 6.208 0 5.504-4.48 7.68-9.216 6.336-2.24-0.64-3.584-4.48-5.312-6.912l7.68-5.632" fill="#FFFFFF"></path></svg>
|
@ -27,6 +27,7 @@ import AccessFormPowerDNSConfig from "./AccessFormPowerDNSConfig";
|
||||
import AccessFormQiniuConfig from "./AccessFormQiniuConfig";
|
||||
import AccessFormSSHConfig from "./AccessFormSSHConfig";
|
||||
import AccessFormTencentCloudConfig from "./AccessFormTencentCloudConfig";
|
||||
import AccessFormUCloudConfig from "./AccessFormUCloudConfig";
|
||||
import AccessFormVolcEngineConfig from "./AccessFormVolcEngineConfig";
|
||||
import AccessFormWebhookConfig from "./AccessFormWebhookConfig";
|
||||
|
||||
@ -118,6 +119,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
||||
return <AccessFormSSHConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.TENCENTCLOUD:
|
||||
return <AccessFormTencentCloudConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.UCLOUD:
|
||||
return <AccessFormUCloudConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.VOLCENGINE:
|
||||
return <AccessFormVolcEngineConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.WEBHOOK:
|
||||
|
90
ui/src/components/access/AccessFormUCloudConfig.tsx
Normal file
90
ui/src/components/access/AccessFormUCloudConfig.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type AccessConfigForUCloud } from "@/domain/access";
|
||||
|
||||
type AccessFormUCloudConfigFieldValues = Nullish<AccessConfigForUCloud>;
|
||||
|
||||
export type AccessFormUCloudConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: AccessFormUCloudConfigFieldValues;
|
||||
onValuesChange?: (values: AccessFormUCloudConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): AccessFormUCloudConfigFieldValues => {
|
||||
return {
|
||||
privateKey: "",
|
||||
publicKey: "",
|
||||
};
|
||||
};
|
||||
|
||||
const AccessFormUCloudConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormUCloudConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
privateKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.ucloud_private_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
publicKey: z
|
||||
.string()
|
||||
.min(1, t("access.form.ucloud_public_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim(),
|
||||
projectId: z
|
||||
.string()
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.trim()
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="privateKey"
|
||||
label={t("access.form.ucloud_private_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ucloud_private_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input autoComplete="new-password" placeholder={t("access.form.ucloud_private_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="publicKey"
|
||||
label={t("access.form.ucloud_public_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ucloud_public_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.ucloud_public_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="projectId"
|
||||
label={t("access.form.ucloud_project_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ucloud_project_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input autoComplete="new-password" placeholder={t("access.form.ucloud_project_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessFormUCloudConfig;
|
@ -40,7 +40,7 @@ const ApplyDNSProviderPicker = ({ className, style, placeholder, onSelect }: App
|
||||
<Row gutter={[16, 16]}>
|
||||
{filteredProviders.map((provider, index) => {
|
||||
return (
|
||||
<Col key={index} span={12}>
|
||||
<Col key={index} xs={24} md={12} span={12}>
|
||||
<Card
|
||||
className="h-16 w-full overflow-hidden shadow-sm"
|
||||
styles={{ body: { height: "100%", padding: "0.5rem 1rem" } }}
|
||||
@ -51,7 +51,7 @@ const ApplyDNSProviderPicker = ({ className, style, placeholder, onSelect }: App
|
||||
>
|
||||
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
||||
<Avatar src={provider.icon} size="small" />
|
||||
<Typography.Text className="line-clamp-2">{t(provider.name)}</Typography.Text>
|
||||
<Typography.Text className="line-clamp-2 flex-1">{t(provider.name)}</Typography.Text>
|
||||
</Flex>
|
||||
</Card>
|
||||
</Col>
|
||||
|
@ -40,7 +40,7 @@ const DeployProviderPicker = ({ className, style, placeholder, onSelect }: Deplo
|
||||
<Row gutter={[16, 16]}>
|
||||
{filteredProviders.map((provider, index) => {
|
||||
return (
|
||||
<Col key={index} span={12}>
|
||||
<Col key={index} xs={24} md={12} span={12}>
|
||||
<Card
|
||||
className="h-16 w-full overflow-hidden shadow-sm"
|
||||
styles={{ body: { height: "100%", padding: "0.5rem 1rem" } }}
|
||||
@ -51,7 +51,7 @@ const DeployProviderPicker = ({ className, style, placeholder, onSelect }: Deplo
|
||||
>
|
||||
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
||||
<Avatar src={provider.icon} size="small" />
|
||||
<Typography.Text className="line-clamp-2">{t(provider.name)}</Typography.Text>
|
||||
<Typography.Text className="line-clamp-2 flex-1">{t(provider.name)}</Typography.Text>
|
||||
</Flex>
|
||||
</Card>
|
||||
</Col>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar, Space, Typography } from "antd";
|
||||
import { Avatar, Flex, Typography } from "antd";
|
||||
import { produce } from "immer";
|
||||
|
||||
import { deployProvidersMap } from "@/domain/provider";
|
||||
@ -45,10 +45,10 @@ const DeployNode = ({ node, disabled }: DeployNodeProps) => {
|
||||
const config = (node.config as WorkflowNodeConfigForDeploy) ?? {};
|
||||
const provider = deployProvidersMap.get(config.provider);
|
||||
return (
|
||||
<Space className="max-w-full">
|
||||
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
||||
<Avatar src={provider?.icon} size="small" />
|
||||
<Typography.Text className="truncate">{t(provider?.name ?? "")}</Typography.Text>
|
||||
</Space>
|
||||
<Typography.Text className="flex-1 truncate">{t(provider?.name ?? "")}</Typography.Text>
|
||||
</Flex>
|
||||
);
|
||||
}, [node]);
|
||||
|
||||
|
@ -37,6 +37,8 @@ import DeployNodeConfigFormTencentCloudCOSConfig from "./DeployNodeConfigFormTen
|
||||
import DeployNodeConfigFormTencentCloudCSSConfig from "./DeployNodeConfigFormTencentCloudCSSConfig.tsx";
|
||||
import DeployNodeConfigFormTencentCloudECDNConfig from "./DeployNodeConfigFormTencentCloudECDNConfig.tsx";
|
||||
import DeployNodeConfigFormTencentCloudEOConfig from "./DeployNodeConfigFormTencentCloudEOConfig.tsx";
|
||||
import DeployNodeConfigFormUCloudUCDNConfig from "./DeployNodeConfigFormUCloudUCDNConfig.tsx";
|
||||
import DeployNodeConfigFormUCloudUS3Config from "./DeployNodeConfigFormUCloudUS3Config.tsx";
|
||||
import DeployNodeConfigFormVolcEngineCDNConfig from "./DeployNodeConfigFormVolcEngineCDNConfig.tsx";
|
||||
import DeployNodeConfigFormVolcEngineCLBConfig from "./DeployNodeConfigFormVolcEngineCLBConfig.tsx";
|
||||
import DeployNodeConfigFormVolcEngineDCDNConfig from "./DeployNodeConfigFormVolcEngineDCDNConfig.tsx";
|
||||
@ -156,6 +158,10 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
||||
return <DeployNodeConfigFormTencentCloudECDNConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.TENCENTCLOUD_EO:
|
||||
return <DeployNodeConfigFormTencentCloudEOConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.UCLOUD_UCDN:
|
||||
return <DeployNodeConfigFormUCloudUCDNConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.UCLOUD_US3:
|
||||
return <DeployNodeConfigFormUCloudUS3Config {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.VOLCENGINE_CDN:
|
||||
return <DeployNodeConfigFormVolcEngineCDNConfig {...nestedFormProps} />;
|
||||
case DEPLOY_PROVIDERS.VOLCENGINE_CLB:
|
||||
|
@ -0,0 +1,63 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
type DeployNodeConfigFormUCloudUCDNConfigFieldValues = Nullish<{
|
||||
domainId: string;
|
||||
}>;
|
||||
|
||||
export type DeployNodeConfigFormUCloudUCDNConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: DeployNodeConfigFormUCloudUCDNConfigFieldValues;
|
||||
onValuesChange?: (values: DeployNodeConfigFormUCloudUCDNConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): DeployNodeConfigFormUCloudUCDNConfigFieldValues => {
|
||||
return {};
|
||||
};
|
||||
|
||||
const DeployNodeConfigFormUCloudUCDNConfig = ({
|
||||
form: formInst,
|
||||
formName,
|
||||
disabled,
|
||||
initialValues,
|
||||
onValuesChange,
|
||||
}: DeployNodeConfigFormUCloudUCDNConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
domainId: z
|
||||
.string({ message: t("workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder") })
|
||||
.nonempty(t("workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="domainId"
|
||||
label={t("workflow_node.deploy.form.ucloud_ucdn_domain_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ucloud_ucdn_domain_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployNodeConfigFormUCloudUCDNConfig;
|
@ -0,0 +1,93 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
type DeployNodeConfigFormUCloudUS3ConfigFieldValues = Nullish<{
|
||||
region: string;
|
||||
bucket: string;
|
||||
domain: string;
|
||||
}>;
|
||||
|
||||
export type DeployNodeConfigFormUCloudUS3ConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: DeployNodeConfigFormUCloudUS3ConfigFieldValues;
|
||||
onValuesChange?: (values: DeployNodeConfigFormUCloudUS3ConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): DeployNodeConfigFormUCloudUS3ConfigFieldValues => {
|
||||
return {};
|
||||
};
|
||||
|
||||
const DeployNodeConfigFormUCloudUS3Config = ({
|
||||
form: formInst,
|
||||
formName,
|
||||
disabled,
|
||||
initialValues,
|
||||
onValuesChange,
|
||||
}: DeployNodeConfigFormUCloudUS3ConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
region: z
|
||||
.string({ message: t("workflow_node.deploy.form.ucloud_us3_region.placeholder") })
|
||||
.nonempty(t("workflow_node.deploy.form.ucloud_us3_region.placeholder"))
|
||||
.trim(),
|
||||
bucket: z
|
||||
.string({ message: t("workflow_node.deploy.form.ucloud_us3_bucket.placeholder") })
|
||||
.nonempty(t("workflow_node.deploy.form.ucloud_us3_bucket.placeholder"))
|
||||
.trim(),
|
||||
domain: z
|
||||
.string({ message: t("workflow_node.deploy.form.ucloud_us3_domain.placeholder") })
|
||||
.refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="region"
|
||||
label={t("workflow_node.deploy.form.ucloud_us3_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ucloud_us3_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ucloud_us3_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="bucket"
|
||||
label={t("workflow_node.deploy.form.ucloud_us3_bucket.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ucloud_us3_bucket.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ucloud_us3_bucket.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="domain"
|
||||
label={t("workflow_node.deploy.form.ucloud_us3_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ucloud_us3_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ucloud_us3_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployNodeConfigFormUCloudUS3Config;
|
@ -1,6 +1,6 @@
|
||||
import { memo, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Typography } from "antd";
|
||||
import { Flex, Typography } from "antd";
|
||||
import { produce } from "immer";
|
||||
|
||||
import { notifyChannelsMap } from "@/domain/settings";
|
||||
@ -40,12 +40,12 @@ const NotifyNode = ({ node, disabled }: NotifyNodeProps) => {
|
||||
const config = (node.config as WorkflowNodeConfigForNotify) ?? {};
|
||||
const channel = notifyChannelsMap.get(config.channel as string);
|
||||
return (
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
<Typography.Text className="truncate">{t(channel?.name ?? " ")}</Typography.Text>
|
||||
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
||||
<Typography.Text className="flex-1 truncate">{t(channel?.name ?? " ")}</Typography.Text>
|
||||
<Typography.Text className="truncate" type="secondary">
|
||||
{config.subject ?? ""}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</Flex>
|
||||
);
|
||||
}, [node]);
|
||||
|
||||
|
@ -26,6 +26,7 @@ export interface AccessModel extends BaseModel {
|
||||
| AccessConfigForQiniu
|
||||
| AccessConfigForSSH
|
||||
| AccessConfigForTencentCloud
|
||||
| AccessConfigForUCloud
|
||||
| AccessConfigForVolcEngine
|
||||
| AccessConfigForWebhook
|
||||
);
|
||||
@ -125,6 +126,12 @@ export type AccessConfigForTencentCloud = {
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
export type AccessConfigForUCloud = {
|
||||
privateKey: string;
|
||||
publicKey: string;
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
export type AccessConfigForVolcEngine = {
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
|
@ -22,6 +22,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
||||
QINIU: "qiniu",
|
||||
SSH: "ssh",
|
||||
TENCENTCLOUD: "tencentcloud",
|
||||
UCLOUD: "ucloud",
|
||||
VOLCENGINE: "volcengine",
|
||||
WEBHOOK: "webhook",
|
||||
} as const);
|
||||
@ -61,6 +62,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.DOGECLOUD, "common.provider.dogecloud", "/imgs/providers/dogecloud.svg", ACCESS_USAGES.DEPLOY],
|
||||
[ACCESS_PROVIDERS.VOLCENGINE, "common.provider.volcengine", "/imgs/providers/volcengine.svg", ACCESS_USAGES.ALL],
|
||||
[ACCESS_PROVIDERS.BYTEPLUS, "common.provider.byteplus", "/imgs/providers/byteplus.svg", ACCESS_USAGES.DEPLOY],
|
||||
[ACCESS_PROVIDERS.UCLOUD, "common.provider.ucloud", "/imgs/providers/ucloud.svg", ACCESS_USAGES.DEPLOY],
|
||||
[ACCESS_PROVIDERS.AWS, "common.provider.aws", "/imgs/providers/aws.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.AZURE, "common.provider.azure", "/imgs/providers/azure.svg", ACCESS_USAGES.APPLY],
|
||||
[ACCESS_PROVIDERS.CLOUDFLARE, "common.provider.cloudflare", "/imgs/providers/cloudflare.svg", ACCESS_USAGES.APPLY],
|
||||
@ -173,6 +175,8 @@ export const DEPLOY_PROVIDERS = Object.freeze({
|
||||
TENCENTCLOUD_CSS: `${ACCESS_PROVIDERS.TENCENTCLOUD}-css`,
|
||||
TENCENTCLOUD_ECDN: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ecdn`,
|
||||
TENCENTCLOUD_EO: `${ACCESS_PROVIDERS.TENCENTCLOUD}-eo`,
|
||||
UCLOUD_UCDN: `${ACCESS_PROVIDERS.UCLOUD}-ucdn`,
|
||||
UCLOUD_US3: `${ACCESS_PROVIDERS.UCLOUD}-us3`,
|
||||
VOLCENGINE_CDN: `${ACCESS_PROVIDERS.VOLCENGINE}-cdn`,
|
||||
VOLCENGINE_CLB: `${ACCESS_PROVIDERS.VOLCENGINE}-clb`,
|
||||
VOLCENGINE_DCDN: `${ACCESS_PROVIDERS.VOLCENGINE}-dcdn`,
|
||||
@ -224,6 +228,8 @@ export const deployProvidersMap: Map<DeployProvider["type"] | string, DeployProv
|
||||
[DEPLOY_PROVIDERS.QINIU_CDN, "common.provider.qiniu.cdn"],
|
||||
[DEPLOY_PROVIDERS.DOGECLOUD_CDN, "common.provider.dogecloud.cdn"],
|
||||
[DEPLOY_PROVIDERS.BYTEPLUS_CDN, "common.provider.byteplus.cdn"],
|
||||
[DEPLOY_PROVIDERS.UCLOUD_US3, "common.provider.ucloud.us3"],
|
||||
[DEPLOY_PROVIDERS.UCLOUD_UCDN, "common.provider.ucloud.ucdn"],
|
||||
].map(([type, name]) => [
|
||||
type,
|
||||
{
|
||||
|
@ -121,6 +121,15 @@
|
||||
"access.form.tencentcloud_secret_key.label": "Tencent Cloud SecretKey",
|
||||
"access.form.tencentcloud_secret_key.placeholder": "Please enter Tencent Cloud SecretKey",
|
||||
"access.form.tencentcloud_secret_key.tooltip": "For more information, see <a href=\"https://cloud.tencent.com/document/product/598/40488?lang=en\" target=\"_blank\">https://cloud.tencent.com/document/product/598/40488?lang=en</a>",
|
||||
"access.form.ucloud_private_key.label": "UCloud API private key",
|
||||
"access.form.ucloud_private_key.placeholder": "Please enter UCloud API private key",
|
||||
"access.form.ucloud_private_key.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/uaccount/api_manage\" target=\"_blank\">https://console.ucloud-global.com/uaccount/api_manage</a>",
|
||||
"access.form.ucloud_public_key.label": "UCloud API public key",
|
||||
"access.form.ucloud_public_key.placeholder": "Please enter UCloud API public key",
|
||||
"access.form.ucloud_public_key.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/uaccount/api_manage\" target=\"_blank\">https://console.ucloud-global.com/uaccount/api_manage</a>",
|
||||
"access.form.ucloud_project_id.label": "UCloud project ID (Optional)",
|
||||
"access.form.ucloud_project_id.placeholder": "Please enter UCloud project ID",
|
||||
"access.form.ucloud_project_id.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/uaccount/iam/project_manage\" target=\"_blank\">https://console.ucloud-global.com/uaccount/iam/project_manage</a>",
|
||||
"access.form.volcengine_access_key_id.label": "VolcEngine AccessKeyId",
|
||||
"access.form.volcengine_access_key_id.placeholder": "Please enter VolcEngine AccessKeyId",
|
||||
"access.form.volcengine_access_key_id.tooltip": "For more information, see <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
|
||||
|
@ -78,6 +78,9 @@
|
||||
"common.provider.tencentcloud.dns": "Tencent Cloud - Domain Name Service (DNS)",
|
||||
"common.provider.tencentcloud.ecdn": "Tencent Cloud - Enterprise Content Delivery Network (ECDN)",
|
||||
"common.provider.tencentcloud.eo": "Tencent Cloud - EdgeOne",
|
||||
"common.provider.ucloud": "UCloud",
|
||||
"common.provider.ucloud.ucdn": "UCloud - UCloud Content Delivery Network (UCDN)",
|
||||
"common.provider.ucloud.us3": "UCloud - UCloud Object-based Storage (US3)",
|
||||
"common.provider.volcengine": "Volcengine",
|
||||
"common.provider.volcengine.cdn": "Volcengine - Content Delivery Network (CDN)",
|
||||
"common.provider.volcengine.clb": "Volcengine - Cloud Load Balancer (CLB)",
|
||||
|
@ -301,6 +301,18 @@
|
||||
"workflow_node.deploy.form.tencentcloud_eo_domain.label": "Tencent Cloud EdgeOne domain",
|
||||
"workflow_node.deploy.form.tencentcloud_eo_domain.placeholder": "Please enter Tencent Cloud EdgeOne domain name",
|
||||
"workflow_node.deploy.form.tencentcloud_eo_domain.tooltip": "For more information, see <a href=\"https://console.tencentcloud.com/edgeone\" target=\"_blank\">https://console.tencentcloud.com/edgeone</a>",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.label": "UCloud UCDN domain ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder": "Please enter UCloud UCDN domain ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/ucdn\" target=\"_blank\">https://console.ucloud-global.com/ucdn</a>",
|
||||
"workflow_node.deploy.form.ucloud_us3_region.label": "UCloud region",
|
||||
"workflow_node.deploy.form.ucloud_us3_region.placeholder": "Please enter VolcEngine region (e.g. cn-bj2)",
|
||||
"workflow_node.deploy.form.ucloud_us3_region.tooltip": "For more information, see <a href=\"https://www.ucloud-global.com/en/docs/api/summary/regionlist\" target=\"_blank\">https://www.ucloud-global.com/en/docs/api/summary/regionlist</a>",
|
||||
"workflow_node.deploy.form.ucloud_us3_bucket.label": "UCloud US3 bucket",
|
||||
"workflow_node.deploy.form.ucloud_us3_bucket.placeholder": "Please enter UCloud US3 bucket name",
|
||||
"workflow_node.deploy.form.ucloud_us3_bucket.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/ufile\" target=\"_blank\">https://console.ucloud-global.com/ufile</a>",
|
||||
"workflow_node.deploy.form.ucloud_us3_domain.label": "UCloud US3 domain",
|
||||
"workflow_node.deploy.form.ucloud_us3_domain.placeholder": "Please enter UCloud US3 domain name",
|
||||
"workflow_node.deploy.form.ucloud_us3_domain.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/ufile\" target=\"_blank\">https://console.ucloud-global.com/ufile</a>",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.label": "VolcEngine CDN domain",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "Please enter VolcEngine CDN domain name",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "For more information, see <a href=\"https://console.volcengine.com/cdn/homepage\" target=\"_blank\">https://console.volcengine.com/cdn/homepage</a>",
|
||||
|
@ -121,6 +121,15 @@
|
||||
"access.form.tencentcloud_secret_key.label": "腾讯云 SecretKey",
|
||||
"access.form.tencentcloud_secret_key.placeholder": "请输入腾讯云 SecretKey",
|
||||
"access.form.tencentcloud_secret_key.tooltip": "这是什么?请参阅 <a href=\"https://cloud.tencent.com/document/product/598/40488\" target=\"_blank\">https://cloud.tencent.com/document/product/598/40488</a>",
|
||||
"access.form.ucloud_private_key.label": "优刻得 API 私钥",
|
||||
"access.form.ucloud_private_key.placeholder": "请输入优刻得 API 私钥",
|
||||
"access.form.ucloud_private_key.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/uaccount/api_manage\" target=\"_blank\">https://console.ucloud.cn/uaccount/api_manage</a>",
|
||||
"access.form.ucloud_public_key.label": "优刻得 API 公钥",
|
||||
"access.form.ucloud_public_key.placeholder": "请输入优刻得 API 公钥",
|
||||
"access.form.ucloud_public_key.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/uaccount/api_manage\" target=\"_blank\">https://console.ucloud.cn/uaccount/api_manage</a>",
|
||||
"access.form.ucloud_project_id.label": "优刻得项目 ID(可选)",
|
||||
"access.form.ucloud_project_id.placeholder": "请输入优刻得项目 ID",
|
||||
"access.form.ucloud_project_id.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/uaccount/iam/project_manage\" target=\"_blank\">https://console.ucloud.cn/uaccount/iam/project_manage</a>",
|
||||
"access.form.volcengine_access_key_id.label": "火山引擎 AccessKeyId",
|
||||
"access.form.volcengine_access_key_id.placeholder": "请输入火山引擎 AccessKeyId",
|
||||
"access.form.volcengine_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
|
||||
|
@ -78,6 +78,9 @@
|
||||
"common.provider.tencentcloud.dns": "腾讯云 - 云解析 DNS",
|
||||
"common.provider.tencentcloud.ecdn": "腾讯云 - 全站加速网络 ECDN",
|
||||
"common.provider.tencentcloud.eo": "腾讯云 - 边缘安全加速平台 EdgeOne",
|
||||
"common.provider.ucloud": "优刻得",
|
||||
"common.provider.ucloud.ucdn": "优刻得 - 内容分发 UCDN",
|
||||
"common.provider.ucloud.us3": "优刻得 - 对象存储 US3",
|
||||
"common.provider.volcengine": "火山引擎",
|
||||
"common.provider.volcengine.cdn": "火山引擎 - 内容分发网络 CDN",
|
||||
"common.provider.volcengine.clb": "火山引擎 - 负载均衡 CLB",
|
||||
|
@ -301,6 +301,18 @@
|
||||
"workflow_node.deploy.form.tencentcloud_eo_domain.label": "腾讯云 EdgeOne 加速域名",
|
||||
"workflow_node.deploy.form.tencentcloud_eo_domain.placeholder": "请输入腾讯云 EdgeOne 加速域名",
|
||||
"workflow_node.deploy.form.tencentcloud_eo_domain.tooltip": "这是什么?请参阅 <a href=\"https://console.cloud.tencent.com/edgeone\" target=\"_blank\">https://console.cloud.tencent.com/edgeone</a>",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.label": "优刻得 UCDN 域名 ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder": "请输入优刻得 UCDN 域名 ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/ucdn\" target=\"_blank\">https://console.ucloud.cn/ucdn</a>",
|
||||
"workflow_node.deploy.form.ucloud_us3_region.label": "优刻得地域",
|
||||
"workflow_node.deploy.form.ucloud_us3_region.placeholder": "优刻得地域(例如:cn-bj2)",
|
||||
"workflow_node.deploy.form.ucloud_us3_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.ucloud.cn/api/summary/regionlist\" target=\"_blank\">https://docs.ucloud.cn/api/summary/regionlist</a>",
|
||||
"workflow_node.deploy.form.ucloud_us3_bucket.label": "优刻得 US3 存储桶名",
|
||||
"workflow_node.deploy.form.ucloud_us3_bucket.placeholder": "请输入优刻得 US3 存储桶名",
|
||||
"workflow_node.deploy.form.ucloud_us3_bucket.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/ufile\" target=\"_blank\">https://console.ucloud.cn/ufile</a>",
|
||||
"workflow_node.deploy.form.ucloud_us3_domain.label": "优刻得 US3 自定义域名",
|
||||
"workflow_node.deploy.form.ucloud_us3_domain.placeholder": "请输入优刻得 US3 自定义域名",
|
||||
"workflow_node.deploy.form.ucloud_us3_domain.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/ufile\" target=\"_blank\">https://console.ucloud.cn/ufile</a>",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.label": "火山引擎 CDN 加速域名(支持泛域名)",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "请输入火山引擎 CDN 加速域名",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://console.volcengine.com/cdn/homepage\" target=\"_blank\">https://console.volcengine.com/cdn/homepage</a><br><br>泛域名表示形式为:*.example.com",
|
||||
|
@ -300,7 +300,7 @@ const WorkflowDetail = () => {
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-12 py-8">
|
||||
<div className="px-12 py-8 max-md:px-4">
|
||||
<WorkflowElements />
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user