mirror of
https://github.com/certimate-go/certimate.git
synced 2026-06-22 21:05:48 +08:00
Merge branch 'next' of https://github.com/YangRucheng/certimate into YangRucheng-next
This commit is contained in:
commit
eb17efa256
@ -252,6 +252,7 @@ const (
|
||||
DeploymentProviderTypeHuaweiCloudCDN = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-cdn")
|
||||
DeploymentProviderTypeHuaweiCloudELB = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-elb")
|
||||
DeploymentProviderTypeHuaweiCloudSCM = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-scm")
|
||||
DeploymentProviderTypeHuaweiCloudOBS = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-obs")
|
||||
DeploymentProviderTypeHuaweiCloudWAF = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-waf")
|
||||
DeploymentProviderTypeJDCloudALB = DeploymentProviderType(AccessProviderTypeJDCloud + "-alb")
|
||||
DeploymentProviderTypeJDCloudCDN = DeploymentProviderType(AccessProviderTypeJDCloud + "-cdn")
|
||||
|
||||
@ -0,0 +1,124 @@
|
||||
package huaweicloudobs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
)
|
||||
|
||||
type SSLDeployerProviderConfig struct {
|
||||
// 华为云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云 Bucket 对应的 Endpoint。
|
||||
Endpoint string `json:"endpoint"`
|
||||
// 华为云 OBS 桶名。
|
||||
Bucket string `json:"bucket"`
|
||||
// 自定义域名。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type SSLDeployerProvider struct {
|
||||
config *SSLDeployerProviderConfig
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
var _ core.SSLDeployer = (*SSLDeployerProvider)(nil)
|
||||
|
||||
func NewSSLDeployerProvider(config *SSLDeployerProviderConfig) (*SSLDeployerProvider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("the configuration of the ssl deployer provider is nil")
|
||||
}
|
||||
|
||||
config.Endpoint = strings.TrimPrefix(strings.TrimPrefix(config.Endpoint, "http://"), "https://")
|
||||
|
||||
return &SSLDeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *SSLDeployerProvider) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// REF: https://support.huaweicloud.com/usermanual-obs/obs_06_3200.html
|
||||
// REF: https://support.huaweicloud.com/api-obs/obs_04_0059.html
|
||||
func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLDeployResult, error) {
|
||||
if d.config.Domain == "" {
|
||||
return nil, fmt.Errorf("config `domain` is required")
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://%s.%s/?customdomain=%s", d.config.Bucket, d.config.Endpoint, d.config.Domain)
|
||||
bodyXML := fmt.Sprintf(`
|
||||
<CustomDomainConfiguration>
|
||||
<Name>%s</Name>
|
||||
<Certificate>%s</Certificate>
|
||||
<CertificateChain>%s</CertificateChain>
|
||||
<PrivateKey>%s</PrivateKey>
|
||||
</CustomDomainConfiguration>`,
|
||||
d.config.Bucket+"_"+d.config.Domain, certPEM, certPEM, privkeyPEM,
|
||||
)
|
||||
|
||||
// 计算 Content-MD5(Base64 编码)
|
||||
md5sum := md5.Sum([]byte(bodyXML))
|
||||
contentMD5 := base64.StdEncoding.EncodeToString(md5sum[:])
|
||||
|
||||
// 日期
|
||||
date := time.Now().UTC().Format(http.TimeFormat)
|
||||
|
||||
// 构造签名字符串
|
||||
method := "PUT"
|
||||
contentType := "application/xml"
|
||||
canonicalizedResource := fmt.Sprintf("/%s/?customdomain=%s", d.config.Bucket, d.config.Domain)
|
||||
stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s\n%s", method, contentMD5, contentType, date, canonicalizedResource)
|
||||
|
||||
// HMAC-SHA1 签名
|
||||
h := hmac.New(sha1.New, []byte(d.config.SecretAccessKey))
|
||||
h.Write([]byte(stringToSign))
|
||||
signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
|
||||
// Authorization
|
||||
authHeader := fmt.Sprintf("OBS %s:%s", d.config.AccessKeyId, signature)
|
||||
|
||||
// 创建请求
|
||||
req, err := http.NewRequest(method, url, bytes.NewBuffer([]byte(bodyXML)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Date", date)
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Content-MD5", contentMD5)
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
|
||||
// 请求
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body := new(bytes.Buffer)
|
||||
body.ReadFrom(resp.Body)
|
||||
return nil, fmt.Errorf("HTTP request failed with status %d: %s", resp.StatusCode, body.String())
|
||||
}
|
||||
return &core.SSLDeployResult{}, nil
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package huaweicloudobs_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/huaweicloud-obs"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fEndpoint string
|
||||
fBucket string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||
flag.StringVar(&fEndpoint, argsPrefix+"ENDPOINT", "", "")
|
||||
flag.StringVar(&fBucket, argsPrefix+"BUCKET", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./huaweicloud_obs_test.go -args \
|
||||
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_ENDPOINT="https://your-endpoint" \
|
||||
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_BUCKET="your-bucket" \
|
||||
--CERTIMATE_SSLDEPLOYER_HUAWEICLOUDCDN_DOMAIN="example.com"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
fmt.Sprintf("ENDPOINT: %v", fEndpoint),
|
||||
fmt.Sprintf("BUCKET: %v", fBucket),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewSSLDeployerProvider(&provider.SSLDeployerProviderConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
Endpoint: fEndpoint,
|
||||
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)
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderHuaweiCloudOBS = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "endpoint"]}
|
||||
initialValue={initialValues.endpoint}
|
||||
label={t("workflow_node.deploy.form.huaweicloud_obs_endpoint.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.huaweicloud_obs_endpoint.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "bucket"]}
|
||||
initialValue={initialValues.bucket}
|
||||
label={t("workflow_node.deploy.form.huaweicloud_obs_bucket.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.huaweicloud_obs_bucket.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.huaweicloud_obs_domain.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.huaweicloud_obs_domain.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.huaweicloud_obs_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
endpoint: "",
|
||||
bucket: "",
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
endpoint: z
|
||||
.string(t("workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder"))
|
||||
.nonempty(t("workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder")),
|
||||
bucket: z
|
||||
.string(t("workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder"))
|
||||
.nonempty(t("workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder")),
|
||||
domain: z
|
||||
.string(t("workflow_node.deploy.form.huaweicloud_obs_domain.placeholder"))
|
||||
.refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderHuaweiCloudOBS, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@ -64,6 +64,7 @@ import BizDeployNodeConfigFieldsProviderGcoreCDN from "./BizDeployNodeConfigFiel
|
||||
import BizDeployNodeConfigFieldsProviderGoEdge from "./BizDeployNodeConfigFieldsProviderGoEdge";
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiCloudCDN from "./BizDeployNodeConfigFieldsProviderHuaweiCloudCDN";
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiCloudELB from "./BizDeployNodeConfigFieldsProviderHuaweiCloudELB";
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiCloudOBS from "./BizDeployNodeConfigFieldsProviderHuaweiCloudOBS";
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiCloudWAF from "./BizDeployNodeConfigFieldsProviderHuaweiCloudWAF";
|
||||
import BizDeployNodeConfigFieldsProviderJDCloudALB from "./BizDeployNodeConfigFieldsProviderJDCloudALB";
|
||||
import BizDeployNodeConfigFieldsProviderJDCloudCDN from "./BizDeployNodeConfigFieldsProviderJDCloudCDN";
|
||||
@ -322,6 +323,9 @@ const BizDeployNodeConfigForm = ({ node, ...props }: BizDeployNodeConfigFormProp
|
||||
case DEPLOYMENT_PROVIDERS.HUAWEICLOUD_ELB: {
|
||||
return BizDeployNodeConfigFieldsProviderHuaweiCloudELB;
|
||||
}
|
||||
case DEPLOYMENT_PROVIDERS.HUAWEICLOUD_OBS: {
|
||||
return BizDeployNodeConfigFieldsProviderHuaweiCloudOBS;
|
||||
}
|
||||
case DEPLOYMENT_PROVIDERS.HUAWEICLOUD_WAF: {
|
||||
return BizDeployNodeConfigFieldsProviderHuaweiCloudWAF;
|
||||
}
|
||||
|
||||
@ -485,6 +485,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
HUAWEICLOUD_CDN: `${ACCESS_PROVIDERS.HUAWEICLOUD}-cdn`,
|
||||
HUAWEICLOUD_ELB: `${ACCESS_PROVIDERS.HUAWEICLOUD}-elb`,
|
||||
HUAWEICLOUD_SCM: `${ACCESS_PROVIDERS.HUAWEICLOUD}-scm`,
|
||||
HUAWEICLOUD_OBS: `${ACCESS_PROVIDERS.HUAWEICLOUD}-obs`,
|
||||
HUAWEICLOUD_WAF: `${ACCESS_PROVIDERS.HUAWEICLOUD}-waf`,
|
||||
JDCLOUD_ALB: `${ACCESS_PROVIDERS.JDCLOUD}-alb`,
|
||||
JDCLOUD_CDN: `${ACCESS_PROVIDERS.JDCLOUD}-cdn`,
|
||||
@ -605,6 +606,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
||||
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_APPBLB, "provider.baiducloud.appblb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_CERT, "provider.baiducloud.cert_upload", DEPLOYMENT_CATEGORIES.SSL],
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_CDN, "provider.huaweicloud.cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_OBS, "provider.huaweicloud.obs", DEPLOYMENT_CATEGORIES.STORAGE],
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_ELB, "provider.huaweicloud.elb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_WAF, "provider.huaweicloud.waf", DEPLOYMENT_CATEGORIES.FIREWALL],
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_SCM, "provider.huaweicloud.scm_upload", DEPLOYMENT_CATEGORIES.SSL],
|
||||
|
||||
@ -96,6 +96,7 @@
|
||||
"provider.huaweicloud.dns": "Huawei Cloud - DNS",
|
||||
"provider.huaweicloud.elb": "Huawei Cloud - ELB (Elastic Load Balance)",
|
||||
"provider.huaweicloud.scm_upload": "Huawei Cloud - Upload to SCM (SSL Certificate Manager)",
|
||||
"provider.huaweicloud.obs": "Huawei Cloud - OBS (Object Storage Service)",
|
||||
"provider.huaweicloud.waf": "Huawei Cloud - WAF (Web Application Firewall)",
|
||||
"provider.jdcloud": "JD Cloud",
|
||||
"provider.jdcloud.alb": "JD Cloud - ALB (Application Load Balancer)",
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
"workflow_node.start.form.trigger_cron.tooltip": "Exactly 5 space separated segments, in standard <em>crontab</em> rules.",
|
||||
"workflow_node.start.form.trigger_cron.help": "Expected execution time for the last 5 times (the actual time zone is based on the server):",
|
||||
"workflow_node.start.form.trigger_cron.guide": "If you have multiple workflows, it is recommended to set them to run at different times of the day instead of always running at a specific time. And please don't always set it to midnight every day to avoid spikes in traffic. <br><br>Reference links:<br>1. <a href=\"https://letsencrypt.org/docs/rate-limits/\" target=\"_blank\">Let’s Encrypt rate limits</a><br>2. <a href=\"https://letsencrypt.org/docs/faq/#why-should-my-let-s-encrypt-acme-client-run-at-a-random-time\" target=\"_blank\">Why should my Let’s Encrypt (ACME) client run at a random time?</a>",
|
||||
|
||||
"workflow_node.apply.label": "Request certificate",
|
||||
"workflow_node.apply.help": "Apply for SSL certificate issuance from the certificate authority.",
|
||||
"workflow_node.apply.default_name": "Application",
|
||||
@ -126,7 +125,6 @@
|
||||
"workflow_node.apply.form.skip_before_expiry_days.suffix": ", skip to re-apply.",
|
||||
"workflow_node.apply.form.skip_before_expiry_days.unit": "days",
|
||||
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "Be careful not to exceed the validity period limit of the issued certificate, otherwise the certificate may never be renewed.",
|
||||
|
||||
"workflow_node.upload.label": "Upload certificate",
|
||||
"workflow_node.upload.help": "Upload the user's existing SSL certificate.",
|
||||
"workflow_node.upload.default_name": "Uploading",
|
||||
@ -137,7 +135,6 @@
|
||||
"workflow_node.upload.form.certificate.placeholder": "-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----",
|
||||
"workflow_node.upload.form.private_key.label": "Private key (PEM format)",
|
||||
"workflow_node.upload.form.private_key.placeholder": "-----BEGIN (RSA|EC) PRIVATE KEY-----...-----END(RSA|EC) PRIVATE KEY-----",
|
||||
|
||||
"workflow_node.monitor.label": "Monitor certificate",
|
||||
"workflow_node.monitor.help": "Obtain the SSL certificate of the website through HTTPS protocol.",
|
||||
"workflow_node.monitor.default_name": "Monitoring",
|
||||
@ -152,7 +149,6 @@
|
||||
"workflow_node.monitor.form.domain.help": "Notes: It is only required when the host is an IP address.",
|
||||
"workflow_node.monitor.form.request_path.label": "Request path (Optional)",
|
||||
"workflow_node.monitor.form.request_path.placeholder": "Please enter request path",
|
||||
|
||||
"workflow_node.deploy.label": "Deploy certificate",
|
||||
"workflow_node.deploy.help": "Invoke the APIs of the service provider to deploy the SSL certificate.",
|
||||
"workflow_node.deploy.default_name": "Deployment",
|
||||
@ -522,6 +518,15 @@
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_domain.label": "Huawei Cloud CDN domain",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "Please enter Huawei Cloud CDN domain name",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/cdn\" target=\"_blank\">https://console-intl.huaweicloud.com/cdn</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_endpoint.label": "Huawei Cloud OBS Endpoint",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder": "Please enter the Huawei Cloud OBS endpoint (e.g., obs.cn-north-4.myhuaweicloud.com)",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_endpoint.tooltip": "What is this? Please refer to <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_bucket.label": "Huawei Cloud COS Bucket Name",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder": "Please enter the Huawei Cloud COS bucket name",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_bucket.tooltip": "What is this? Please refer to <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_domain.label": "Huawei Cloud COS Custom Domain",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_domain.placeholder": "Please enter the Huawei Cloud COS custom domain",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_domain.tooltip": "What is this? Please refer to <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_elb_region.label": "Huawei Cloud ELB region",
|
||||
"workflow_node.deploy.form.huaweicloud_elb_region.placeholder": "Please enter Huawei Cloud ELB region (e.g. cn-north-1)",
|
||||
"workflow_node.deploy.form.huaweicloud_elb_region.tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/apiexplorer/#/endpoint?locale=en-us\" target=\"_blank\">https://console-intl.huaweicloud.com/apiexplorer/#/endpoint</a>",
|
||||
@ -1021,7 +1026,6 @@
|
||||
"workflow_node.deploy.form.skip_on_last_succeeded.suffix": " to re-deploy.",
|
||||
"workflow_node.deploy.form.skip_on_last_succeeded.switch.on": "skip",
|
||||
"workflow_node.deploy.form.skip_on_last_succeeded.switch.off": "not skip",
|
||||
|
||||
"workflow_node.notify.label": "Send notification",
|
||||
"workflow_node.notify.help": "Invoke the APIs of the service provider to push message notifications.",
|
||||
"workflow_node.notify.default_name": "Notification",
|
||||
@ -1083,7 +1087,6 @@
|
||||
"workflow_node.condition.default_name": "Parallel",
|
||||
"workflow_node.condition.default_name.template_certtest_on_expire_soon": "If the certificate will be expiring soon ...",
|
||||
"workflow_node.condition.default_name.template_certtest_on_expired": "If the certificate has expired ...",
|
||||
|
||||
"workflow_node.branch_block.label": "Branch",
|
||||
"workflow_node.branch_block.default_name": "Branch",
|
||||
"workflow_node.branch_block.state.no": "Enter Unconditionally",
|
||||
@ -1112,7 +1115,6 @@
|
||||
"workflow_node.branch_block.form.expression.value.option.true.label": "True",
|
||||
"workflow_node.branch_block.form.expression.value.option.false.label": "False",
|
||||
"workflow_node.branch_block.form.expression.add_condition.button": "Add condition",
|
||||
|
||||
"workflow_node.try_catch.label": "Execution result branch",
|
||||
"workflow_node.try_catch.help": "Attempt to execute subsequent nodes, and when any node fails to execute, interrupt and enter the execution failure branch.",
|
||||
"workflow_node.try_catch.default_name": "Try to ...",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"provider.1panel": "1Panel",
|
||||
"provider.1panel.console": "1Panel - 面板自身",
|
||||
"provider.1panel.site": "1Panel - 网站",
|
||||
@ -96,6 +96,7 @@
|
||||
"provider.huaweicloud.dns": "华为云 - 云解析 DNS",
|
||||
"provider.huaweicloud.elb": "华为云 - 弹性负载均衡 ELB",
|
||||
"provider.huaweicloud.scm_upload": "华为云 - 上传到云证书管理服务 SCM",
|
||||
"provider.huaweicloud.obs": "华为云 - 对象储存 OBS",
|
||||
"provider.huaweicloud.waf": "华为云 - Web 应用防火墙 WAF",
|
||||
"provider.jdcloud": "京东云",
|
||||
"provider.jdcloud.alb": "京东云 - 应用负载均衡 ALB",
|
||||
@ -181,7 +182,6 @@
|
||||
"provider.wecombot": "企业微信群机器人",
|
||||
"provider.westcn": "西部数码",
|
||||
"provider.zerossl": "ZeroSSL",
|
||||
|
||||
"provider.category.all": "全部",
|
||||
"provider.category.cdn": "CDN",
|
||||
"provider.category.storage": "文件存储",
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
"workflow_node.start.form.trigger_cron.tooltip": "五段式表达式,使用 <em>crontab</em> 标准语法规则。<br>支持使用任意值(即 <strong>*</strong>)、值列表分隔符(即 <strong>,</strong>)、值的范围(即 <strong>-</strong>)、步骤值(即 <strong>/</strong>)等四种表达式。",
|
||||
"workflow_node.start.form.trigger_cron.help": "预计最近 5 次运行时间(实际时区以服务器设置为准):",
|
||||
"workflow_node.start.form.trigger_cron.guide": "如果你有多个工作流,建议将它们设置为在一天中的多个时间段运行,而非总是在相同的特定时间。也不要总是设置为每日零时,以免遭遇证书颁发机构的流量高峰。<br><br>参考链接:<br>1. <a href=\"https://letsencrypt.org/zh-cn/docs/rate-limits/\" target=\"_blank\">Let’s Encrypt 速率限制</a><br>2. <a href=\"https://letsencrypt.org/zh-cn/docs/faq/#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E7%9A%84-let-s-encrypt-acme-%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%AF%E5%8A%A8%E6%97%B6%E9%97%B4%E5%BA%94%E5%BD%93%E9%9A%8F%E6%9C%BA\" target=\"_blank\">为什么我的 Let’s Encrypt (ACME) 客户端启动时间应当随机?</a>",
|
||||
|
||||
"workflow_node.apply.label": "申请签发证书",
|
||||
"workflow_node.apply.help": "从证书颁发机构申请签发 SSL 证书。",
|
||||
"workflow_node.apply.default_name": "申请",
|
||||
@ -125,7 +124,6 @@
|
||||
"workflow_node.apply.form.skip_before_expiry_days.suffix": "时,再次运行工作流时跳过此申请节点。",
|
||||
"workflow_node.apply.form.skip_before_expiry_days.unit": "天",
|
||||
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "注意不要超过颁发的证书最大有效期,否则证书可能永远不会续期。",
|
||||
|
||||
"workflow_node.upload.label": "上传自有证书",
|
||||
"workflow_node.upload.help": "上传用户已有的本地 SSL 证书。",
|
||||
"workflow_node.upload.default_name": "上传",
|
||||
@ -136,7 +134,6 @@
|
||||
"workflow_node.upload.form.certificate.placeholder": "-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----",
|
||||
"workflow_node.upload.form.private_key.label": "私钥文件(PEM 格式)",
|
||||
"workflow_node.upload.form.private_key.placeholder": "-----BEGIN (RSA|EC) PRIVATE KEY-----...-----END(RSA|EC) PRIVATE KEY-----",
|
||||
|
||||
"workflow_node.monitor.label": "监控网站证书",
|
||||
"workflow_node.monitor.help": "通过 HTTPS 协议获取指定网站的 SSL 证书。",
|
||||
"workflow_node.monitor.default_name": "监控",
|
||||
@ -151,7 +148,6 @@
|
||||
"workflow_node.monitor.form.domain.help": "提示:仅当主机地址为 IP 时需要输入。",
|
||||
"workflow_node.monitor.form.request_path.label": "请求路径(可选)",
|
||||
"workflow_node.monitor.form.request_path.placeholder": "请输入请求路径",
|
||||
|
||||
"workflow_node.deploy.label": "部署证书到 ...",
|
||||
"workflow_node.deploy.help": "调用服务提供商相关 API,将 SSL 证书部署到指定的目标。",
|
||||
"workflow_node.deploy.default_name": "部署",
|
||||
@ -520,6 +516,15 @@
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_domain.label": "华为云 CDN 加速域名",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "请输入华为云 CDN 加速域名(支持泛域名)",
|
||||
"workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://console.huaweicloud.com/cdn\" target=\"_blank\">https://console.huaweicloud.com/cdn</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_endpoint.label": "华为云 OBS 接口端点",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_endpoint.placeholder": "请输入华为云 OBS 接口端点(例如:obs.cn-north-4.myhuaweicloud.com)",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_endpoint.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_bucket.label": "华为云 COS 存储桶名",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_bucket.placeholder": "请输入华为云 COS 存储桶名",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_bucket.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_domain.label": "华为云 COS 自定义域名",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_domain.placeholder": "请输入华为云 COS 自定义域名",
|
||||
"workflow_node.deploy.form.huaweicloud_obs_domain.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html\" target=\"_blank\">https://support.huaweicloud.com/productdesc-obs/obs_03_0207.html</a>",
|
||||
"workflow_node.deploy.form.huaweicloud_elb_region.label": "华为云 ELB 服务区域",
|
||||
"workflow_node.deploy.form.huaweicloud_elb_region.placeholder": "请输入华为云 ELB 服务区域(例如:cn-north-1)",
|
||||
"workflow_node.deploy.form.huaweicloud_elb_region.tooltip": "这是什么?请参阅 <a href=\"https://console.huaweicloud.com/apiexplorer/#/endpoint\" target=\"_blank\">https://console.huaweicloud.com/apiexplorer/#/endpoint</a>",
|
||||
@ -1019,7 +1024,6 @@
|
||||
"workflow_node.deploy.form.skip_on_last_succeeded.suffix": "此部署节点。",
|
||||
"workflow_node.deploy.form.skip_on_last_succeeded.switch.on": "跳过",
|
||||
"workflow_node.deploy.form.skip_on_last_succeeded.switch.off": "不跳过",
|
||||
|
||||
"workflow_node.notify.label": "推送通知",
|
||||
"workflow_node.notify.help": "调用服务提供商相关 API,将消息通知推送到指定的目标。",
|
||||
"workflow_node.notify.default_name": "通知",
|
||||
@ -1110,14 +1114,11 @@
|
||||
"workflow_node.branch_block.form.expression.value.option.true.label": "真",
|
||||
"workflow_node.branch_block.form.expression.value.option.false.label": "假",
|
||||
"workflow_node.branch_block.form.expression.add_condition.button": "添加条件",
|
||||
|
||||
"workflow_node.try_catch.label": "执行结果分支",
|
||||
"workflow_node.try_catch.help": "尝试执行后续节点,当任一节点执行失败后,中断并进入执行失败分支。",
|
||||
"workflow_node.try_catch.default_name": "尝试执行…",
|
||||
|
||||
"workflow_node.catch_block.label": "执行失败分支",
|
||||
"workflow_node.catch_block.default_name": "若执行失败…",
|
||||
|
||||
"workflow_node.end.label": "结束",
|
||||
"workflow_node.end.help": "中止工作流运行并退出。通常是一个工作流的最后一个节点。",
|
||||
"workflow_node.end.default_name": "结束"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user