From b2eb5d2754fbe99d322b7683a7c0ba3116d58e97 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 17 Feb 2025 20:19:31 +0800 Subject: [PATCH] feat: add baishan cdn deployer --- README.md | 1 + README_EN.md | 1 + internal/deployer/providers.go | 21 ++++ internal/domain/access.go | 4 + internal/domain/provider.go | 3 +- .../lego-providers/gname/internal/lego.go | 4 +- .../providers/baishan-cdn/baishan_cdn.go | 116 ++++++++++++++++++ .../providers/baishan-cdn/baishan_cdn_test.go | 70 +++++++++++ .../baotapanel-console/baotapanel_console.go | 6 +- .../baotapanel-site/baotapanel_site.go | 8 +- .../deployer/providers/safeline/safeline.go | 6 +- internal/pkg/vendors/baishan-sdk/api.go | 45 +++++++ internal/pkg/vendors/baishan-sdk/client.go | 84 +++++++++++++ internal/pkg/vendors/baishan-sdk/models.go | 77 ++++++++++++ internal/pkg/vendors/btpanel-sdk/api.go | 76 ++++++------ internal/pkg/vendors/btpanel-sdk/client.go | 53 ++------ internal/pkg/vendors/btpanel-sdk/models.go | 48 ++++++++ internal/pkg/vendors/gname-sdk/api.go | 116 +++++++----------- internal/pkg/vendors/gname-sdk/client.go | 66 ++-------- internal/pkg/vendors/gname-sdk/models.go | 79 ++++++++++++ internal/pkg/vendors/safeline-sdk/api.go | 42 ++----- internal/pkg/vendors/safeline-sdk/client.go | 25 +--- internal/pkg/vendors/safeline-sdk/models.go | 34 +++++ ui/public/imgs/providers/baishan.png | Bin 0 -> 2565 bytes ui/src/components/access/AccessForm.tsx | 3 + .../access/AccessFormBaishanConfig.tsx | 56 +++++++++ .../workflow/node/DeployNodeConfigForm.tsx | 3 + .../DeployNodeConfigFormBaishanCDNConfig.tsx | 65 ++++++++++ ui/src/domain/access.ts | 5 + ui/src/domain/provider.ts | 4 + ui/src/i18n/locales/en/nls.access.json | 2 + .../i18n/locales/en/nls.workflow.nodes.json | 3 + ui/src/i18n/locales/zh/nls.access.json | 2 + .../i18n/locales/zh/nls.workflow.nodes.json | 23 ++-- 34 files changed, 866 insertions(+), 285 deletions(-) create mode 100644 internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go create mode 100644 internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn_test.go create mode 100644 internal/pkg/vendors/baishan-sdk/api.go create mode 100644 internal/pkg/vendors/baishan-sdk/client.go create mode 100644 internal/pkg/vendors/baishan-sdk/models.go create mode 100644 internal/pkg/vendors/btpanel-sdk/models.go create mode 100644 internal/pkg/vendors/gname-sdk/models.go create mode 100644 internal/pkg/vendors/safeline-sdk/models.go create mode 100644 ui/public/imgs/providers/baishan.png create mode 100644 ui/src/components/access/AccessFormBaishanConfig.tsx create mode 100644 ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx diff --git a/README.md b/README.md index 24f2859d..32b5ce17 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ make local.run | [华为云](https://www.huaweicloud.com/) | 可部署到华为云 CDN、ELB、WAF 等服务 | | [火山引擎](https://www.volcengine.com/) | 可部署到火山引擎 TOS、CDN、DCDN、CLB、ImageX、Live 等服务 | | [七牛云](https://www.qiniu.com/) | 可部署到七牛云 CDN、直播云等服务 | +| [白山云](https://www.baishan.com/) | 可部署到白山云 CDN | | [多吉云](https://www.dogecloud.com/) | 可部署到多吉云 CDN | | [优刻得](https://www.ucloud.cn/) | 可部署到优刻得 US3、UCDN 等服务 | | [雷池](https://waf-ce.chaitin.cn/) | 可部署到雷池 WAF | diff --git a/README_EN.md b/README_EN.md index dcb69efd..1966512b 100644 --- a/README_EN.md +++ b/README_EN.md @@ -127,6 +127,7 @@ The following hosting providers are supported: | [Huawei Cloud](https://www.huaweicloud.com/) | Supports deployment to Huawei Cloud CDN, ELB, WAF | | [Volcengine](https://www.volcengine.com/) | Supports deployment to Volcengine TOS, CDN, DCDN, CLB, ImageX, Live | | [Qiniu Cloud](https://www.qiniu.com/) | Supports deployment to Qiniu Cloud CDN, Pili | +| [Baishan Cloud](https://intl.baishancloud.com/) | Supports deployment to Baishan Cloud CDN | | [Doge Cloud](https://www.dogecloud.com/) | Supports deployment to Doge Cloud CDN | | [UCloud](https://www.ucloud-global.com/) | Supports deployment to UCloud US3, UCDN | | [SafeLine](https://waf.chaitin.com/) | Supports deployment to SafeLine WAF | diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 4c6acc22..d5ce4ae7 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -18,6 +18,7 @@ import ( pAliyunWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-waf" pAWSCloudFront "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-cloudfront" pBaiduCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-cdn" + pBaishanCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baishan-cdn" pBaotaPanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console" pBaotaPanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site" pBytePlusCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/byteplus-cdn" @@ -216,6 +217,26 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, } } + case domain.DeployProviderTypeBaishanCDN: + { + access := domain.AccessConfigForBaishan{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeployProviderTypeBaishanCDN: + deployer, err := pBaishanCDN.NewWithLogger(&pBaishanCDN.BaishanCDNDeployerConfig{ + ApiToken: access.ApiToken, + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }, logger) + return deployer, logger, err + + default: + break + } + } + case domain.DeployProviderTypeBaotaPanelConsole, domain.DeployProviderTypeBaotaPanelSite: { access := domain.AccessConfigForBaotaPanel{} diff --git a/internal/domain/access.go b/internal/domain/access.go index ec2e093e..d4f4f714 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -53,6 +53,10 @@ type AccessConfigForBaiduCloud struct { SecretAccessKey string `json:"secretAccessKey"` } +type AccessConfigForBaishan struct { + ApiToken string `json:"apiToken"` +} + type AccessConfigForBaotaPanel struct { ApiUrl string `json:"apiUrl"` ApiKey string `json:"apiKey"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 08ee9836..70b90af5 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -16,7 +16,7 @@ const ( AccessProviderTypeAWS = AccessProviderType("aws") AccessProviderTypeAzure = AccessProviderType("azure") AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud") - AccessProviderTypeBaishan = AccessProviderType("baishan") // 白山云(预留) + AccessProviderTypeBaishan = AccessProviderType("baishan") AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel") AccessProviderTypeBytePlus = AccessProviderType("byteplus") AccessProviderTypeCacheFly = AccessProviderType("cachefly") // CacheFly(预留) @@ -107,6 +107,7 @@ const ( DeployProviderTypeAliyunWAF = DeployProviderType("aliyun-waf") DeployProviderTypeAWSCloudFront = DeployProviderType("aws-cloudfront") DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn") + DeployProviderTypeBaishanCDN = DeployProviderType("baishan-cdn") DeployProviderTypeBaotaPanelConsole = DeployProviderType("baotapanel-console") DeployProviderTypeBaotaPanelSite = DeployProviderType("baotapanel-site") DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn") diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go index 03dc633f..94a8c35d 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go @@ -37,7 +37,7 @@ type Config struct { } type DNSProvider struct { - client *gnamesdk.GnameClient + client *gnamesdk.Client config *Config } @@ -68,7 +68,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { return nil, errors.New("gname: the configuration of the DNS provider is nil") } - client := gnamesdk.NewGnameClient(config.AppID, config.AppKey). + client := gnamesdk.NewClient(config.AppID, config.AppKey). WithTimeout(config.HTTPTimeout) return &DNSProvider{ diff --git a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go new file mode 100644 index 00000000..214f050e --- /dev/null +++ b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go @@ -0,0 +1,116 @@ +package baishancdn + +import ( + "context" + "errors" + "fmt" + "time" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + bssdk "github.com/usual2970/certimate/internal/pkg/vendors/baishan-sdk" +) + +type BaishanCDNDeployerConfig struct { + // 白山云 API Token。 + ApiToken string `json:"apiToken"` + // 加速域名(支持泛域名)。 + Domain string `json:"domain"` +} + +type BaishanCDNDeployer struct { + config *BaishanCDNDeployerConfig + logger logger.Logger + sdkClient *bssdk.Client +} + +var _ deployer.Deployer = (*BaishanCDNDeployer)(nil) + +func New(config *BaishanCDNDeployerConfig) (*BaishanCDNDeployer, error) { + return NewWithLogger(config, logger.NewNilLogger()) +} + +func NewWithLogger(config *BaishanCDNDeployerConfig, logger logger.Logger) (*BaishanCDNDeployer, 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.ApiToken) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &BaishanCDNDeployer{ + logger: logger, + config: config, + sdkClient: client, + }, nil +} + +func (d *BaishanCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + if d.config.Domain == "" { + return nil, errors.New("config `domain` is required") + } + + // 查询域名配置 + // REF: https://portal.baishancloud.com/track/document/api/1/1065 + getDomainConfigReq := &bssdk.GetDomainConfigRequest{ + Domains: d.config.Domain, + Config: "https", + } + getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.GetDomainConfig'") + } else if len(getDomainConfigResp.Data) == 0 { + return nil, errors.New("domain config not found") + } else { + d.logger.Logt("已查询到域名配置", getDomainConfigResp) + } + + // 新增证书 + // REF: https://portal.baishancloud.com/track/document/downloadPdf/1441 + createCertificateReq := &bssdk.CreateCertificateRequest{ + Certificate: certPem, + Key: privkeyPem, + Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()), + } + createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'") + } else { + d.logger.Logt("已新增证书", createCertificateResp) + } + + // 设置域名配置 + // REF: https://portal.baishancloud.com/track/document/api/1/1045 + setDomainConfigReq := &bssdk.SetDomainConfigRequest{ + Domains: d.config.Domain, + Config: &bssdk.DomainConfig{ + Https: &bssdk.DomainConfigHttps{ + CertId: createCertificateResp.Data.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.SetDomainConfig(setDomainConfigReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.SetDomainConfig'") + } else { + d.logger.Logt("已设置域名配置", setDomainConfigResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiToken string) (*bssdk.Client, error) { + client := bssdk.NewClient(apiToken) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn_test.go b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn_test.go new file mode 100644 index 00000000..b6ceb64f --- /dev/null +++ b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn_test.go @@ -0,0 +1,70 @@ +package baishancdn_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baishan-cdn" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiToken string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_BAISHANCDN_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./baishan_cdn_test.go -args \ + --CERTIMATE_DEPLOYER_BAISHANCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_BAISHANCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_BAISHANCDN_APITOKEN="your-api-token" \ + --CERTIMATE_DEPLOYER_BAISHANCDN_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("APITOKEN: %v", fApiToken), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.New(&provider.BaishanCDNDeployerConfig{ + ApiToken: fApiToken, + Domain: fDomain, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go index 28765cff..e9c955c7 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go +++ b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go @@ -23,7 +23,7 @@ type BaotaPanelConsoleDeployerConfig struct { type BaotaPanelConsoleDeployer struct { config *BaotaPanelConsoleDeployerConfig logger logger.Logger - sdkClient *btsdk.BaoTaPanelClient + sdkClient *btsdk.Client } var _ deployer.Deployer = (*BaotaPanelConsoleDeployer)(nil) @@ -81,7 +81,7 @@ func (d *BaotaPanelConsoleDeployer) Deploy(ctx context.Context, certPem string, return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string) (*btsdk.BaoTaPanelClient, error) { - client := btsdk.NewBaoTaPanelClient(apiUrl, apiKey) +func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { + client := btsdk.NewClient(apiUrl, apiKey) return client, nil } diff --git a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go index 6422a2cb..d2d8622f 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go @@ -16,14 +16,14 @@ type BaotaPanelSiteDeployerConfig struct { ApiUrl string `json:"apiUrl"` // 宝塔面板接口密钥。 ApiKey string `json:"apiKey"` - // 站点名称 + // 站点名称。 SiteName string `json:"siteName"` } type BaotaPanelSiteDeployer struct { config *BaotaPanelSiteDeployerConfig logger logger.Logger - sdkClient *btsdk.BaoTaPanelClient + sdkClient *btsdk.Client } var _ deployer.Deployer = (*BaotaPanelSiteDeployer)(nil) @@ -75,7 +75,7 @@ func (d *BaotaPanelSiteDeployer) Deploy(ctx context.Context, certPem string, pri return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string) (*btsdk.BaoTaPanelClient, error) { - client := btsdk.NewBaoTaPanelClient(apiUrl, apiKey) +func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { + client := btsdk.NewClient(apiUrl, apiKey) return client, nil } diff --git a/internal/pkg/core/deployer/providers/safeline/safeline.go b/internal/pkg/core/deployer/providers/safeline/safeline.go index b759981a..d6b37aea 100644 --- a/internal/pkg/core/deployer/providers/safeline/safeline.go +++ b/internal/pkg/core/deployer/providers/safeline/safeline.go @@ -27,7 +27,7 @@ type SafeLineDeployerConfig struct { type SafeLineDeployer struct { config *SafeLineDeployerConfig logger logger.Logger - sdkClient *safelinesdk.SafeLineClient + sdkClient *safelinesdk.Client } var _ deployer.Deployer = (*SafeLineDeployer)(nil) @@ -96,7 +96,7 @@ func (d *SafeLineDeployer) deployToCertificate(ctx context.Context, certPem stri return nil } -func createSdkClient(apiUrl, apiToken string) (*safelinesdk.SafeLineClient, error) { - client := safelinesdk.NewSafeLineClient(apiUrl, apiToken) +func createSdkClient(apiUrl, apiToken string) (*safelinesdk.Client, error) { + client := safelinesdk.NewClient(apiUrl, apiToken) return client, nil } diff --git a/internal/pkg/vendors/baishan-sdk/api.go b/internal/pkg/vendors/baishan-sdk/api.go new file mode 100644 index 00000000..9e6a2bc6 --- /dev/null +++ b/internal/pkg/vendors/baishan-sdk/api.go @@ -0,0 +1,45 @@ +package baishansdk + +import ( + "encoding/json" + "net/http" +) + +func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := CreateCertificateResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/v2/domain/certificate", params, &result) + if err != nil { + return nil, err + } + return &result, nil +} + +func (c *Client) GetDomainConfig(req *GetDomainConfigRequest) (*GetDomainConfigResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := GetDomainConfigResponse{} + err := c.sendRequestWithResult(http.MethodGet, "/v2/domain/config", params, &result) + if err != nil { + return nil, err + } + return &result, nil +} + +func (c *Client) SetDomainConfig(req *SetDomainConfigRequest) (*SetDomainConfigResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := SetDomainConfigResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/v2/domain/config", params, &result) + if err != nil { + return nil, err + } + return &result, nil +} diff --git a/internal/pkg/vendors/baishan-sdk/client.go b/internal/pkg/vendors/baishan-sdk/client.go new file mode 100644 index 00000000..28cb0bc3 --- /dev/null +++ b/internal/pkg/vendors/baishan-sdk/client.go @@ -0,0 +1,84 @@ +package baishansdk + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiToken string + client *resty.Client +} + +func NewClient(apiToken string) *Client { + client := resty.New() + + return &Client{ + apiToken: apiToken, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) sendRequest(method string, path string, params map[string]any) (*resty.Response, error) { + url := "https://cdn.api.baishan.com" + path + + req := c.client.R() + if method == http.MethodGet { + data := make(map[string]string) + for k, v := range params { + data[k] = fmt.Sprintf("%v", v) + } + req = req. + SetQueryParams(data). + SetQueryParam("token", c.apiToken) + } else if method == http.MethodPost { + req = req. + SetHeader("Content-Type", "application/json"). + SetQueryParam("token", c.apiToken). + SetBody(params) + } + + var resp *resty.Response + var err error + if method == http.MethodGet { + resp, err = req.Get(url) + } else if method == http.MethodPost { + resp, err = req.Post(url) + } else { + return nil, fmt.Errorf("baishan: unsupported method: %s", method) + } + + if err != nil { + return nil, fmt.Errorf("baishan: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("baishan: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params map[string]any, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("baishan: failed to parse response: %w", err) + } + + if result.GetCode() != 0 { + return fmt.Errorf("baishan api error: %d, %s", result.GetCode(), result.GetMessage()) + } + + return nil +} diff --git a/internal/pkg/vendors/baishan-sdk/models.go b/internal/pkg/vendors/baishan-sdk/models.go new file mode 100644 index 00000000..4cf1a918 --- /dev/null +++ b/internal/pkg/vendors/baishan-sdk/models.go @@ -0,0 +1,77 @@ +package baishansdk + +type BaseResponse interface { + GetCode() int + GetMessage() string +} + +type baseResponse struct { + Code int `json:"code"` + Message string `json:"message"` +} + +func (r *baseResponse) GetCode() int { + return r.Code +} + +func (r *baseResponse) GetMessage() string { + return r.Message +} + +type CreateCertificateRequest struct { + Certificate string `json:"certificate"` + Key string `json:"key"` + Name string `json:"name"` +} + +type CreateCertificateResponse struct { + baseResponse + Data *DomainCertificate `json:"data"` +} + +type GetDomainConfigRequest struct { + Domains string `json:"domains"` + Config string `json:"config"` +} + +type GetDomainConfigResponse struct { + baseResponse + Data []*GetDomainConfigResponseData `json:"data"` +} + +type GetDomainConfigResponseData struct { + Domain string `json:"domain"` + Config *DomainConfig `json:"config"` +} + +type SetDomainConfigRequest struct { + Domains string `json:"domains"` + Config *DomainConfig `json:"config"` +} + +type SetDomainConfigResponse struct { + baseResponse + Data *SetDomainConfigResponseData `json:"data"` +} + +type SetDomainConfigResponseData struct { + Config *DomainConfig `json:"config"` +} + +type DomainCertificate struct { + CertId int64 `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 int64 `json:"cert_id"` + ForceHttps *string `json:"force_https,omitempty"` + EnableHttp2 *string `json:"http2,omitempty"` + EnableOcsp *string `json:"ocsp,omitempty"` +} diff --git a/internal/pkg/vendors/btpanel-sdk/api.go b/internal/pkg/vendors/btpanel-sdk/api.go index f733d67a..f197e081 100644 --- a/internal/pkg/vendors/btpanel-sdk/api.go +++ b/internal/pkg/vendors/btpanel-sdk/api.go @@ -1,48 +1,44 @@ package btpanelsdk -type BaseResponse interface { - GetStatus() *bool - GetMsg() *string +import ( + "encoding/json" +) + +func (c *Client) ConfigSavePanelSSL(req *ConfigSavePanelSSLRequest) (*ConfigSavePanelSSLResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := ConfigSavePanelSSLResponse{} + err := c.sendRequestWithResult("/config?action=SavePanelSSL", params, &result) + if err != nil { + return nil, err + } + return &result, nil } -type baseResponse struct { - Status *bool `json:"status,omitempty"` - Msg *string `json:"msg,omitempty"` +func (c *Client) SiteSetSSL(req *SiteSetSSLRequest) (*SiteSetSSLResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := SiteSetSSLResponse{} + err := c.sendRequestWithResult("/site?action=SetSSL", params, &result) + if err != nil { + return nil, err + } + return &result, nil } -func (r *baseResponse) GetStatus() *bool { - return r.Status -} +func (c *Client) SystemServiceAdmin(req *SystemServiceAdminRequest) (*SystemServiceAdminResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) -func (r *baseResponse) GetMsg() *string { - return r.Msg -} - -type ConfigSavePanelSSLRequest struct { - PrivateKey string `json:"privateKey"` - Certificate string `json:"certPem"` -} - -type ConfigSavePanelSSLResponse struct { - baseResponse -} - -type SiteSetSSLRequest struct { - Type string `json:"type"` - SiteName string `json:"siteName"` - PrivateKey string `json:"key"` - Certificate string `json:"csr"` -} - -type SiteSetSSLResponse struct { - baseResponse -} - -type SystemServiceAdminRequest struct { - Name string `json:"name"` - Type string `json:"type"` -} - -type SystemServiceAdminResponse struct { - baseResponse + result := SystemServiceAdminResponse{} + err := c.sendRequestWithResult("/system?action=ServiceAdmin", params, &result) + if err != nil { + return nil, err + } + return &result, nil } diff --git a/internal/pkg/vendors/btpanel-sdk/client.go b/internal/pkg/vendors/btpanel-sdk/client.go index 047c9c54..513a9eb3 100644 --- a/internal/pkg/vendors/btpanel-sdk/client.go +++ b/internal/pkg/vendors/btpanel-sdk/client.go @@ -11,67 +11,28 @@ import ( "github.com/go-resty/resty/v2" ) -type BaoTaPanelClient struct { +type Client struct { apiHost string apiKey string client *resty.Client } -func NewBaoTaPanelClient(apiHost, apiKey string) *BaoTaPanelClient { +func NewClient(apiHost, apiKey string) *Client { client := resty.New() - return &BaoTaPanelClient{ + return &Client{ apiHost: apiHost, apiKey: apiKey, client: client, } } -func (c *BaoTaPanelClient) WithTimeout(timeout time.Duration) *BaoTaPanelClient { +func (c *Client) WithTimeout(timeout time.Duration) *Client { c.client.SetTimeout(timeout) return c } -func (c *BaoTaPanelClient) ConfigSavePanelSSL(req *ConfigSavePanelSSLRequest) (*ConfigSavePanelSSLResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := ConfigSavePanelSSLResponse{} - err := c.sendRequestWithResult("/config?action=SavePanelSSL", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *BaoTaPanelClient) SiteSetSSL(req *SiteSetSSLRequest) (*SiteSetSSLResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := SiteSetSSLResponse{} - err := c.sendRequestWithResult("/site?action=SetSSL", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *BaoTaPanelClient) SystemServiceAdmin(req *SystemServiceAdminRequest) (*SystemServiceAdminResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := SystemServiceAdminResponse{} - err := c.sendRequestWithResult("/system?action=ServiceAdmin", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *BaoTaPanelClient) generateSignature(timestamp string) string { +func (c *Client) generateSignature(timestamp string) string { keyMd5 := md5.Sum([]byte(c.apiKey)) keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:])) @@ -80,7 +41,7 @@ func (c *BaoTaPanelClient) generateSignature(timestamp string) string { return signMd5Hex } -func (c *BaoTaPanelClient) sendRequest(path string, params map[string]any) (*resty.Response, error) { +func (c *Client) sendRequest(path string, params map[string]any) (*resty.Response, error) { if params == nil { params = make(map[string]any) } @@ -105,7 +66,7 @@ func (c *BaoTaPanelClient) sendRequest(path string, params map[string]any) (*res return resp, nil } -func (c *BaoTaPanelClient) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { +func (c *Client) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { resp, err := c.sendRequest(path, params) if err != nil { return err diff --git a/internal/pkg/vendors/btpanel-sdk/models.go b/internal/pkg/vendors/btpanel-sdk/models.go new file mode 100644 index 00000000..f733d67a --- /dev/null +++ b/internal/pkg/vendors/btpanel-sdk/models.go @@ -0,0 +1,48 @@ +package btpanelsdk + +type BaseResponse interface { + GetStatus() *bool + GetMsg() *string +} + +type baseResponse struct { + Status *bool `json:"status,omitempty"` + Msg *string `json:"msg,omitempty"` +} + +func (r *baseResponse) GetStatus() *bool { + return r.Status +} + +func (r *baseResponse) GetMsg() *string { + return r.Msg +} + +type ConfigSavePanelSSLRequest struct { + PrivateKey string `json:"privateKey"` + Certificate string `json:"certPem"` +} + +type ConfigSavePanelSSLResponse struct { + baseResponse +} + +type SiteSetSSLRequest struct { + Type string `json:"type"` + SiteName string `json:"siteName"` + PrivateKey string `json:"key"` + Certificate string `json:"csr"` +} + +type SiteSetSSLResponse struct { + baseResponse +} + +type SystemServiceAdminRequest struct { + Name string `json:"name"` + Type string `json:"type"` +} + +type SystemServiceAdminResponse struct { + baseResponse +} diff --git a/internal/pkg/vendors/gname-sdk/api.go b/internal/pkg/vendors/gname-sdk/api.go index 282439d2..20891405 100644 --- a/internal/pkg/vendors/gname-sdk/api.go +++ b/internal/pkg/vendors/gname-sdk/api.go @@ -1,79 +1,57 @@ package gnamesdk -type BaseResponse interface { - GetCode() int - GetMsg() string +import ( + "encoding/json" +) + +func (c *Client) AddDomainResolution(req *AddDomainResolutionRequest) (*AddDomainResolutionResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := AddDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/add", params, &result) + if err != nil { + return nil, err + } + return &result, nil } -type baseResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` +func (c *Client) ModifyDomainResolution(req *ModifyDomainResolutionRequest) (*ModifyDomainResolutionResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := ModifyDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/edit", params, &result) + if err != nil { + return nil, err + } + return &result, nil } -func (r *baseResponse) GetCode() int { - return r.Code +func (c *Client) DeleteDomainResolution(req *DeleteDomainResolutionRequest) (*DeleteDomainResolutionResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) + + result := DeleteDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/delete", params, &result) + if err != nil { + return nil, err + } + return &result, nil } -func (r *baseResponse) GetMsg() string { - return r.Msg -} +func (c *Client) ListDomainResolution(req *ListDomainResolutionRequest) (*ListDomainResolutionResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) -type AddDomainResolutionRequest struct { - ZoneName string `json:"ym"` - RecordType string `json:"lx"` - RecordName string `json:"zj"` - RecordValue string `json:"jlz"` - MX int `json:"mx"` - TTL int `json:"ttl"` -} - -type AddDomainResolutionResponse struct { - baseResponse - Data int `json:"data"` -} - -type ModifyDomainResolutionRequest struct { - ID string `json:"jxid"` - ZoneName string `json:"ym"` - RecordType string `json:"lx"` - RecordName string `json:"zj"` - RecordValue string `json:"jlz"` - MX int `json:"mx"` - TTL int `json:"ttl"` -} - -type ModifyDomainResolutionResponse struct { - baseResponse -} - -type DeleteDomainResolutionRequest struct { - ZoneName string `json:"ym"` - RecordID string `json:"jxid"` -} - -type DeleteDomainResolutionResponse struct { - baseResponse -} - -type ListDomainResolutionRequest struct { - ZoneName string `json:"ym"` - Page *int `json:"page,omitempty"` - PageSize *int `json:"limit,omitempty"` -} - -type ListDomainResolutionResponse struct { - baseResponse - Count int `json:"count"` - Data []*ResolutionRecord `json:"data"` - Page int `json:"page"` - PageSize int `json:"pagesize"` -} - -type ResolutionRecord struct { - ID string `json:"id"` - ZoneName string `json:"ym"` - RecordType string `json:"lx"` - RecordName string `json:"zjt"` - RecordValue string `json:"jxz"` - MX int `json:"mx"` + result := ListDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/list", params, &result) + if err != nil { + return nil, err + } + return &result, nil } diff --git a/internal/pkg/vendors/gname-sdk/client.go b/internal/pkg/vendors/gname-sdk/client.go index 66c2b995..d73782e4 100644 --- a/internal/pkg/vendors/gname-sdk/client.go +++ b/internal/pkg/vendors/gname-sdk/client.go @@ -12,80 +12,28 @@ import ( "github.com/go-resty/resty/v2" ) -type GnameClient struct { +type Client struct { appId string appKey string client *resty.Client } -func NewGnameClient(appId, appKey string) *GnameClient { +func NewClient(appId, appKey string) *Client { client := resty.New() - return &GnameClient{ + return &Client{ appId: appId, appKey: appKey, client: client, } } -func (c *GnameClient) WithTimeout(timeout time.Duration) *GnameClient { +func (c *Client) WithTimeout(timeout time.Duration) *Client { c.client.SetTimeout(timeout) return c } -func (c *GnameClient) AddDomainResolution(req *AddDomainResolutionRequest) (*AddDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := AddDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/add", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) ModifyDomainResolution(req *ModifyDomainResolutionRequest) (*ModifyDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := ModifyDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/edit", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) DeleteDomainResolution(req *DeleteDomainResolutionRequest) (*DeleteDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := DeleteDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/delete", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) ListDomainResolution(req *ListDomainResolutionRequest) (*ListDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := ListDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/list", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) generateSignature(params map[string]string) string { +func (c *Client) generateSignature(params map[string]string) string { // Step 1: Sort parameters by ASCII order var keys []string for k := range params { @@ -109,7 +57,7 @@ func (c *GnameClient) generateSignature(params map[string]string) string { return strings.ToUpper(fmt.Sprintf("%x", hash)) } -func (c *GnameClient) sendRequest(path string, params map[string]any) (*resty.Response, error) { +func (c *Client) sendRequest(path string, params map[string]any) (*resty.Response, error) { if params == nil { params = make(map[string]any) } @@ -136,7 +84,7 @@ func (c *GnameClient) sendRequest(path string, params map[string]any) (*resty.Re return resp, nil } -func (c *GnameClient) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { +func (c *Client) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { resp, err := c.sendRequest(path, params) if err != nil { return err diff --git a/internal/pkg/vendors/gname-sdk/models.go b/internal/pkg/vendors/gname-sdk/models.go new file mode 100644 index 00000000..282439d2 --- /dev/null +++ b/internal/pkg/vendors/gname-sdk/models.go @@ -0,0 +1,79 @@ +package gnamesdk + +type BaseResponse interface { + GetCode() int + GetMsg() string +} + +type baseResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` +} + +func (r *baseResponse) GetCode() int { + return r.Code +} + +func (r *baseResponse) GetMsg() string { + return r.Msg +} + +type AddDomainResolutionRequest struct { + ZoneName string `json:"ym"` + RecordType string `json:"lx"` + RecordName string `json:"zj"` + RecordValue string `json:"jlz"` + MX int `json:"mx"` + TTL int `json:"ttl"` +} + +type AddDomainResolutionResponse struct { + baseResponse + Data int `json:"data"` +} + +type ModifyDomainResolutionRequest struct { + ID string `json:"jxid"` + ZoneName string `json:"ym"` + RecordType string `json:"lx"` + RecordName string `json:"zj"` + RecordValue string `json:"jlz"` + MX int `json:"mx"` + TTL int `json:"ttl"` +} + +type ModifyDomainResolutionResponse struct { + baseResponse +} + +type DeleteDomainResolutionRequest struct { + ZoneName string `json:"ym"` + RecordID string `json:"jxid"` +} + +type DeleteDomainResolutionResponse struct { + baseResponse +} + +type ListDomainResolutionRequest struct { + ZoneName string `json:"ym"` + Page *int `json:"page,omitempty"` + PageSize *int `json:"limit,omitempty"` +} + +type ListDomainResolutionResponse struct { + baseResponse + Count int `json:"count"` + Data []*ResolutionRecord `json:"data"` + Page int `json:"page"` + PageSize int `json:"pagesize"` +} + +type ResolutionRecord struct { + ID string `json:"id"` + ZoneName string `json:"ym"` + RecordType string `json:"lx"` + RecordName string `json:"zjt"` + RecordValue string `json:"jxz"` + MX int `json:"mx"` +} diff --git a/internal/pkg/vendors/safeline-sdk/api.go b/internal/pkg/vendors/safeline-sdk/api.go index 9fbfb7c9..ae0a56d1 100644 --- a/internal/pkg/vendors/safeline-sdk/api.go +++ b/internal/pkg/vendors/safeline-sdk/api.go @@ -1,34 +1,18 @@ package safelinesdk -type BaseResponse interface { - GetErrCode() *string - GetErrMsg() *string -} +import ( + "encoding/json" +) -type baseResponse struct { - ErrCode *string `json:"err,omitempty"` - ErrMsg *string `json:"msg,omitempty"` -} +func (c *Client) UpdateCertificate(req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) { + params := make(map[string]any) + jsonData, _ := json.Marshal(req) + json.Unmarshal(jsonData, ¶ms) -func (r *baseResponse) GetErrCode() *string { - return r.ErrCode -} - -func (r *baseResponse) GetErrMsg() *string { - return r.ErrMsg -} - -type UpdateCertificateRequest struct { - Id int32 `json:"id"` - Type int32 `json:"type"` - Manual *UpdateCertificateRequestBodyManul `json:"manual"` -} - -type UpdateCertificateRequestBodyManul struct { - Crt string `json:"crt"` - Key string `json:"key"` -} - -type UpdateCertificateResponse struct { - baseResponse + result := UpdateCertificateResponse{} + err := c.sendRequestWithResult("/api/open/cert", params, &result) + if err != nil { + return nil, err + } + return &result, nil } diff --git a/internal/pkg/vendors/safeline-sdk/client.go b/internal/pkg/vendors/safeline-sdk/client.go index 45ec7f51..be04cb94 100644 --- a/internal/pkg/vendors/safeline-sdk/client.go +++ b/internal/pkg/vendors/safeline-sdk/client.go @@ -9,41 +9,28 @@ import ( "github.com/go-resty/resty/v2" ) -type SafeLineClient struct { +type Client struct { apiHost string apiToken string client *resty.Client } -func NewSafeLineClient(apiHost, apiToken string) *SafeLineClient { +func NewClient(apiHost, apiToken string) *Client { client := resty.New() - return &SafeLineClient{ + return &Client{ apiHost: apiHost, apiToken: apiToken, client: client, } } -func (c *SafeLineClient) WithTimeout(timeout time.Duration) *SafeLineClient { +func (c *Client) WithTimeout(timeout time.Duration) *Client { c.client.SetTimeout(timeout) return c } -func (c *SafeLineClient) UpdateCertificate(req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := UpdateCertificateResponse{} - err := c.sendRequestWithResult("/api/open/cert", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *SafeLineClient) sendRequest(path string, params map[string]any) (*resty.Response, error) { +func (c *Client) sendRequest(path string, params map[string]any) (*resty.Response, error) { if params == nil { params = make(map[string]any) } @@ -65,7 +52,7 @@ func (c *SafeLineClient) sendRequest(path string, params map[string]any) (*resty return resp, nil } -func (c *SafeLineClient) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { +func (c *Client) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { resp, err := c.sendRequest(path, params) if err != nil { return err diff --git a/internal/pkg/vendors/safeline-sdk/models.go b/internal/pkg/vendors/safeline-sdk/models.go new file mode 100644 index 00000000..9fbfb7c9 --- /dev/null +++ b/internal/pkg/vendors/safeline-sdk/models.go @@ -0,0 +1,34 @@ +package safelinesdk + +type BaseResponse interface { + GetErrCode() *string + GetErrMsg() *string +} + +type baseResponse struct { + ErrCode *string `json:"err,omitempty"` + ErrMsg *string `json:"msg,omitempty"` +} + +func (r *baseResponse) GetErrCode() *string { + return r.ErrCode +} + +func (r *baseResponse) GetErrMsg() *string { + return r.ErrMsg +} + +type UpdateCertificateRequest struct { + Id int32 `json:"id"` + Type int32 `json:"type"` + Manual *UpdateCertificateRequestBodyManul `json:"manual"` +} + +type UpdateCertificateRequestBodyManul struct { + Crt string `json:"crt"` + Key string `json:"key"` +} + +type UpdateCertificateResponse struct { + baseResponse +} diff --git a/ui/public/imgs/providers/baishan.png b/ui/public/imgs/providers/baishan.png new file mode 100644 index 0000000000000000000000000000000000000000..af1e555da93f0418d1e5678ea3adaa817b010f82 GIT binary patch literal 2565 zcmaJ@dpwi-AAitTmNdz&4l^qKWY0Dmwn*5PmElMzGP6Bc+NEu5Imy~NhbW~^2dB$% z=}P2MiqxW0gz}q8Dxz8>DJ10l`Qu6T_g!nCZ=nwW zfC1f`5};Yv%)D@2&9{)dy;HN8OQ<1|4T30%lqG@y4~`%bLeY7wXea<;advEPfLsAU zXBjszL=wXAA+rTM3~L61k@18YHUPM~%Y-a;EF?iiLeX5l8+xGnIvU00xS@lI3@k(F z1;uc^6GYI41m8e*LM)raLA$R;xyr~I0Ujh_p=7*md@)((hW?^U*6e4lK{Vag0ES z!V@q~D7#=TpCgcpS9~Eb7-TwMEMf845S`+N)<|HuTn^cbfF;rhPDCmNN5$c&G*3rI ziU)y6#d{J7L}wadmP-+^<9HBXGRx)s!*%*DcV--TLQP}}B;v+H9GXbLLw(7a%>BL> z$M5QW<#N97h45W2s4)Z1boReGJ$t1YpPB8q(bXKj4L`)!OuR@l+WUWgY779nade7D zpzKNi(NLc-s#$$>^QMTb?x1-hg!M>}*TUEn0R~zMxm`uEO5bx+Zn~fHks>{DuvX7% zt9RKli>`}%j6nz6&MG=QuZ6a7WVh^GD()h@H6Wtu9ZBt+!Z>;N-LZlG=1#>c$a>YP zpPG}DO#`S>UlpY6ztMC8_eT40X-{s@-a|%f+hgK=^fNk~b{b}fvNApv8YLF5SOyDe zt1vMi?)~Lr-7z5NQ;A~aw*>l+=TK$5-l=S(-1u!phmrATipB_A+>JspHG9@?#X?2r zE7h@~K5$`Mft8vy65HKJFIQIMr)55HEYa<=afj$g|Bkr2Fr2mAH)KQ1)wKR@j(MxL zi{JdN`Cw~as{Ng+t5+m;g)miSMf5z`+}2y(8v+qPEqGF;J)A{)qC1=)0PI%|malry z9(=lqQFd=m#;;1ay~~m~ZL{9>w^>Feu#nyA(Fj)H+=yI|J!b1;irq~p;~nZZdYg6l z-euI8k_lRPx#@)z`E~<&-COl?%a4>Wc~RCfqY`jszADRzd_{D+kCZgfo?}%x4=k~H zu_oCx-95b$(GenXPo*)}buPSCOn&gGmU2;;Uxu!=I)LUS-8z^d3n$!6ER596l$xd1 zO+dNZ{bwA}Vf>+n`ZlJ+pU&5;*LBgNbSB<61|(8or3&R>#MA8U1$5uRSaOP_Aajp? zjU6ei+K)W3#SM@K^aR3Y42i6HygCe!mLgUJmYh0Fr8_4S)!(;3 zYPlXso{HS~V`mv&%H+N_8@yrVVvjOlnaWRqb1G<@4>@6dMU$P4ldZ(LlaqydulKA{ zc&O!b&YD}<>rFRN$CLa}UC1+Mw~W5^c-B5BpOZ_r^gJ6`o8!C%aeUEr`Qk9o{L#EM z=jt+H&w3FbcP!YeY&w46v-wTS6MD}3pq;BKO2L)dcO0(d^o)>BPD>A>FtIU3)i=<< zXsFKn=URzBe6EE@W{}c5iQxe!euNv@WZB$iq;&=9ftWq>l(rGfzY4zCV;(lbKiPNf1v>C zJr?Q8i=niNp6k_tEd__SK2%t51{iIN%h+0p|3;<;GwBUf?}Ds@1sjyW61?3d?S;U2 zzRIl1;{}mAF_eey@32d_LLf4m&EW;To9=|)Fr412s+2N@ukJ$xSul&{K1krbJ38F9 zJjUHgrK7e$o-0|Q{}hw&ekn0{(&u3xarEKKqaDfr>NYoBe%**+_-V-C{7_nRHxwQH z9_X|2-z?Sw$1T^4ca@rtH@_^hx;paQdG%IHc8y_1`_@dSk+#;vfJphG4=_X@(b?~F zX-;C|)2>TJwk>Pb>Ia4-R{qsB^{2KCqi%;F@S|1t4;`~gP44i%`|9lG?w{i5<$wez;ZOgNX4WDnF^89d|(NuNxj}L~z zH!A7L2kR+nPeGR=PU~uKs2nl%^4KQJHbg)UHOgo>o2`|8cihBSYdpW&kyn`TaLG=g zZ9_3<^WBaW`<9k$^v!KCa}p|R*4x$SjvH-zuGahXI*s0vkwT8o@;Ksk`PzNA*LUH1 z1GFn1s|T2+wt#y=Pn;9S@-2?Jagx?JF*hrwbsw@&0bbH~@=hBVw@6T*KrRiJy}bK8 z*=v7A`QnD2ARCLnlGf?eO0_>t7G+)@%%AgYZS!QW`2i&qO!ac<81-Zhzd)=~jPByJ zEK)s+c}|5#NZ9zO`qnoK);@+;4zYFh?x`n17HX1C~0&oo{bl>MjotybF Nqf>n;=RG47{{d1>M6dt= literal 0 HcmV?d00001 diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 71aa3fba..e10d2a89 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -14,6 +14,7 @@ import AccessFormAliyunConfig from "./AccessFormAliyunConfig"; import AccessFormAWSConfig from "./AccessFormAWSConfig"; import AccessFormAzureConfig from "./AccessFormAzureConfig"; import AccessFormBaiduCloudConfig from "./AccessFormBaiduCloudConfig"; +import AccessFormBaishanConfig from "./AccessFormBaishanConfig"; import AccessFormBaotaPanelConfig from "./AccessFormBaotaPanelConfig"; import AccessFormBytePlusConfig from "./AccessFormBytePlusConfig"; import AccessFormCloudflareConfig from "./AccessFormCloudflareConfig"; @@ -101,6 +102,8 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.BAIDUCLOUD: return ; + case ACCESS_PROVIDERS.BAISHAN: + return ; case ACCESS_PROVIDERS.BAOTAPANEL: return ; case ACCESS_PROVIDERS.BYTEPLUS: diff --git a/ui/src/components/access/AccessFormBaishanConfig.tsx b/ui/src/components/access/AccessFormBaishanConfig.tsx new file mode 100644 index 00000000..0450d9cd --- /dev/null +++ b/ui/src/components/access/AccessFormBaishanConfig.tsx @@ -0,0 +1,56 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForBaishan } from "@/domain/access"; + +type AccessFormBaishanConfigFieldValues = Nullish; + +export type AccessFormBaishanConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormBaishanConfigFieldValues; + onValuesChange?: (values: AccessFormBaishanConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormBaishanConfigFieldValues => { + return { + apiToken: "", + }; +}; + +const AccessFormBaishanConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormBaishanConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiToken: z + .string() + .min(1, t("access.form.baishan_api_token.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + +
+ ); +}; + +export default AccessFormBaishanConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index 8cbc8c57..50faa78b 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -27,6 +27,7 @@ import DeployNodeConfigFormAliyunOSSConfig from "./DeployNodeConfigFormAliyunOSS import DeployNodeConfigFormAliyunWAFConfig from "./DeployNodeConfigFormAliyunWAFConfig"; import DeployNodeConfigFormAWSCloudFrontConfig from "./DeployNodeConfigFormAWSCloudFrontConfig"; import DeployNodeConfigFormBaiduCloudCDNConfig from "./DeployNodeConfigFormBaiduCloudCDNConfig"; +import DeployNodeConfigFormBaishanCDNConfig from "./DeployNodeConfigFormBaishanCDNConfig"; import DeployNodeConfigFormBaotaPanelConsoleConfig from "./DeployNodeConfigFormBaotaPanelConsoleConfig"; import DeployNodeConfigFormBaotaPanelSiteConfig from "./DeployNodeConfigFormBaotaPanelSiteConfig"; import DeployNodeConfigFormBytePlusCDNConfig from "./DeployNodeConfigFormBytePlusCDNConfig"; @@ -154,6 +155,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOY_PROVIDERS.BAIDUCLOUD_CDN: return ; + case DEPLOY_PROVIDERS.BAISHAN_CDN: + return ; case DEPLOY_PROVIDERS.BAOTAPANEL_CONSOLE: return ; case DEPLOY_PROVIDERS.BAOTAPANEL_SITE: diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx new file mode 100644 index 00000000..828d5845 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx @@ -0,0 +1,65 @@ +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 DeployNodeConfigFormBaishanCDNConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormBaishanCDNConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormBaishanCDNConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormBaishanCDNConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormBaishanCDNConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormBaishanCDNConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormBaishanCDNConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + domain: z + .string({ message: t("workflow_node.deploy.form.baishan_cdn_domain.placeholder") }) + .refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default DeployNodeConfigFormBaishanCDNConfig; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index d8a64dd4..548716b4 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -11,6 +11,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForAWS | AccessConfigForAzure | AccessConfigForBaiduCloud + | AccessConfigForBaishan | AccessConfigForBaotaPanel | AccessConfigForBytePlus | AccessConfigForCloudflare @@ -67,6 +68,10 @@ export type AccessConfigForBaiduCloud = { secretAccessKey: string; }; +export type AccessConfigForBaishan = { + apiToken: string; +}; + export type AccessConfigForBaotaPanel = { apiUrl: string; apiKey: string; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index d68e5210..75b954eb 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -9,6 +9,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ AWS: "aws", AZURE: "azure", BAIDUCLOUD: "baiducloud", + BAISHAN: "baishan", BAOTAPANEL: "baotapanel", BYTEPLUS: "byteplus", CLOUDFLARE: "cloudflare", @@ -68,6 +69,7 @@ export const accessProvidersMap: Maphttps://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en", + "access.form.baishan_api_token.label": "Baishan Cloud API token", + "access.form.baishan_api_token.placeholder": "Please enter Baishan Cloud API token", "access.form.baotapanel_api_url.label": "BaoTa Panel URL", "access.form.baotapanel_api_url.placeholder": "Please enter BaoTa Panel URL", "access.form.baotapanel_api_url.tooltip": "For more information, see https://www.bt.cn/bbs/thread-20376-1-1.html", diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index 360a0607..dbfded50 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -190,6 +190,9 @@ "workflow_node.deploy.form.baiducloud_cdn_domain.label": "Baidu Cloud CDN domain", "workflow_node.deploy.form.baiducloud_cdn_domain.placeholder": "Please enter Baidu Cloud CDN domain name", "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "For more information, see https://console.bce.baidu.com/cdn", + "workflow_node.deploy.form.baishan_cdn_domain.label": "Baishan CDN domain", + "workflow_node.deploy.form.baishan_cdn_domain.placeholder": "Please enter Baishan CDN domain name", + "workflow_node.deploy.form.baishan_cdn_domain.tooltip": "For more information, see https://cdnx.console.baishan.com", "workflow_node.deploy.form.baotapanel_console_auto_restart.label": "Auto restart after deployment", "workflow_node.deploy.form.baotapanel_site_name.label": "BaoTa Panel site name", "workflow_node.deploy.form.baotapanel_site_name.placeholder": "Please enter BaoTa Panel site name", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index 586af5f3..cca17a8d 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -65,6 +65,8 @@ "access.form.baiducloud_secret_access_key.label": "百度智能云 SecretAccessKey", "access.form.baiducloud_secret_access_key.placeholder": "请输入百度智能云 SecretAccessKey", "access.form.baiducloud_secret_access_key.tooltip": "这是什么?请参阅 https://cloud.baidu.com/doc/Reference/s/jjwvz2e3p", + "access.form.baishan_api_token.label": "白山云 API Token", + "access.form.baishan_api_token.placeholder": "请输入白山云 API Token", "access.form.baotapanel_api_url.label": "宝塔面板 URL", "access.form.baotapanel_api_url.placeholder": "请输入宝塔面板 URL", "access.form.baotapanel_api_url.tooltip": "这是什么?请参阅 https://www.bt.cn/bbs/thread-20376-1-1.html", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 7fe81657..2a0f2313 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -137,10 +137,10 @@ "workflow_node.deploy.form.aliyun_clb_snidomain.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/clb

不填写时,将替换监听器的默认证书。", "workflow_node.deploy.form.aliyun_cdn_domain.label": "阿里云 CDN 加速域名(支持泛域名)", "workflow_node.deploy.form.aliyun_cdn_domain.placeholder": "请输入阿里云 CDN 加速域名", - "workflow_node.deploy.form.aliyun_cdn_domain.tooltip": "这是什么?请参阅 https://cdn.console.aliyun.com

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.aliyun_cdn_domain.tooltip": "这是什么?请参阅 https://cdn.console.aliyun.com", "workflow_node.deploy.form.aliyun_dcdn_domain.label": "阿里云 DCDN 加速域名(支持泛域名)", "workflow_node.deploy.form.aliyun_dcdn_domain.placeholder": "请输入阿里云 DCDN 加速域名", - "workflow_node.deploy.form.aliyun_dcdn_domain.tooltip": "这是什么?请参阅 https://dcdn.console.aliyun.com

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.aliyun_dcdn_domain.tooltip": "这是什么?请参阅 https://dcdn.console.aliyun.com", "workflow_node.deploy.form.aliyun_esa_region.label": "阿里云 ESA 服务地域", "workflow_node.deploy.form.aliyun_esa_region.placeholder": "请输入阿里云 ESA 服务地域(例如:cn-hangzhou)", "workflow_node.deploy.form.aliyun_esa_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/edge-security-acceleration/esa/api-esa-2024-09-10-endpoint", @@ -189,14 +189,17 @@ "workflow_node.deploy.form.aws_cloudfront_distribution_id.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-working-with.html", "workflow_node.deploy.form.baiducloud_cdn_domain.label": "百度智能云 CDN 加速域名(支持泛域名)", "workflow_node.deploy.form.baiducloud_cdn_domain.placeholder": "请输入百度智能云 CDN 加速域名", - "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.bce.baidu.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.bce.baidu.com/cdn", + "workflow_node.deploy.form.baishan_cdn_domain.label": "白山云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.baishan_cdn_domain.placeholder": "请输入白山云 CDN 加速域名", + "workflow_node.deploy.form.baishan_cdn_domain.tooltip": "这是什么?请参阅 https://cdnx.console.baishan.com", "workflow_node.deploy.form.baotapanel_console_auto_restart.label": "部署后自动重启面板服务", "workflow_node.deploy.form.baotapanel_site_name.label": "宝塔面板网站名称", "workflow_node.deploy.form.baotapanel_site_name.placeholder": "请输入宝塔面板网站名称", "workflow_node.deploy.form.baotapanel_site_name.tooltip": "通常为网站域名。", "workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN 域名(支持泛域名)", "workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "请输入 BytePlus CDN 域名", - "workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "这是什么?请参阅 https://console.byteplus.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "这是什么?请参阅 https://console.byteplus.com/cdn", "workflow_node.deploy.form.dogecloud_cdn_domain.label": "多吉云 CDN 加速域名", "workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "请输入多吉云 CDN 加速域名", "workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.dogecloud.com", @@ -293,7 +296,7 @@ "workflow_node.deploy.form.local_preset_scripts.option.binding_netsh.label": "PowerShell - 导入并绑定到 netsh(需管理员权限)", "workflow_node.deploy.form.qiniu_cdn_domain.label": "七牛云 CDN 加速域名(支持泛域名)", "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "请输入七牛云 CDN 加速域名", - "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "这是什么?请参阅 https://portal.qiniu.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "这是什么?请参阅 https://portal.qiniu.com/cdn", "workflow_node.deploy.form.qiniu_pili_hub.label": "七牛云视频直播空间名", "workflow_node.deploy.form.qiniu_pili_hub.placeholder": "请输入七牛云视频直播空间名", "workflow_node.deploy.form.qiniu_pili_hub.tooltip": "这是什么?请参阅 https://portal.qiniu.com/hub", @@ -340,7 +343,7 @@ "workflow_node.deploy.form.ssh_use_scp.tooltip": "如果你的远程服务器不支持 SFTP,请开启此选项回退为 SCP。", "workflow_node.deploy.form.tencentcloud_cdn_domain.label": "腾讯云 CDN 加速域名(支持泛域名)", "workflow_node.deploy.form.tencentcloud_cdn_domain.placeholder": "请输入腾讯云 CDN 加速域名", - "workflow_node.deploy.form.tencentcloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.tencentcloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn", "workflow_node.deploy.form.tencentcloud_clb_resource_type.label": "证书替换方式", "workflow_node.deploy.form.tencentcloud_clb_resource_type.placeholder": "请选择证书替换方式", "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ssl_deploy.label": "通过 SSL 服务部署到云资源实例", @@ -376,7 +379,7 @@ "workflow_node.deploy.form.tencentcloud_css_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/live/livestat", "workflow_node.deploy.form.tencentcloud_ecdn_domain.label": "腾讯云 ECDN 加速域名(支持泛域名)", "workflow_node.deploy.form.tencentcloud_ecdn_domain.placeholder": "请输入腾讯云 ECDN 加速域名", - "workflow_node.deploy.form.tencentcloud_ecdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.tencentcloud_ecdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn", "workflow_node.deploy.form.tencentcloud_eo_zone_id.label": "腾讯云 EdgeOne 站点 ID", "workflow_node.deploy.form.tencentcloud_eo_zone_id.placeholder": "请输入腾讯云 EdgeOne 站点 ID", "workflow_node.deploy.form.tencentcloud_eo_zone_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/edgeone", @@ -422,7 +425,7 @@ "workflow_node.deploy.form.ucloud_us3_domain.tooltip": "这是什么?请参阅 https://console.ucloud.cn/ufile", "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": "这是什么?请参阅 https://console.volcengine.com/cdn/homepage

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/cdn/homepage", "workflow_node.deploy.form.volcengine_clb_resource_type.label": "证书替换方式", "workflow_node.deploy.form.volcengine_clb_resource_type.placeholder": "请选择证书替换方式", "workflow_node.deploy.form.volcengine_clb_resource_type.option.listener.label": "替换指定监听器的证书", @@ -434,7 +437,7 @@ "workflow_node.deploy.form.volcengine_clb_listener_id.tooltip": "这是什么?请参阅 https://console.volcengine.com/clb/LoadBalancer", "workflow_node.deploy.form.volcengine_dcdn_domain.label": "火山引擎 DCDN 加速域名(支持泛域名)", "workflow_node.deploy.form.volcengine_dcdn_domain.placeholder": "请输入火山引擎 DCDN 加速域名", - "workflow_node.deploy.form.volcengine_dcdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/dcdn/dashboard

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.volcengine_dcdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/dcdn/dashboard", "workflow_node.deploy.form.volcengine_imagex_region.label": "火山引擎 ImageX 服务地域", "workflow_node.deploy.form.volcengine_imagex_region.placeholder": "请输入火山引擎 ImageX 服务地域(例如:cn-north-1)", "workflow_node.deploy.form.volcengine_imagex_region.tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/508/23757", @@ -446,7 +449,7 @@ "workflow_node.deploy.form.volcengine_imagex_domain.tooltip": "这是什么?请参阅 see https://console.volcengine.com/imagex", "workflow_node.deploy.form.volcengine_live_domain.label": "火山引擎视频直播流域名(支持泛域名)", "workflow_node.deploy.form.volcengine_live_domain.placeholder": "请输入火山引擎视频直播流域名", - "workflow_node.deploy.form.volcengine_live_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/live

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.volcengine_live_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/live", "workflow_node.deploy.form.volcengine_tos_region.label": "火山引擎 TOS 服务地域", "workflow_node.deploy.form.volcengine_tos_region.placeholder": "请输入火山引擎 TOS 服务地域(例如:cn-beijing)", "workflow_node.deploy.form.volcengine_tos_region.tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/6349/107356",