feat: new acme dns-01 provider: hetzner

This commit is contained in:
Fu Diwei 2025-05-26 13:19:15 +08:00
parent b139139f50
commit 4c13a3e86a
13 changed files with 136 additions and 0 deletions

View File

@ -22,6 +22,7 @@ import (
pGcore "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore" pGcore "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore"
pGname "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname" pGname "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname"
pGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy" pGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy"
pHetzner "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/hetzner"
pHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud" pHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud"
pJDCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud" pJDCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud"
pNamecheap "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap" pNamecheap "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap"
@ -324,6 +325,21 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
return applicant, err return applicant, err
} }
case domain.ACMEDns01ProviderTypeHetzner:
{
access := domain.AccessConfigForHetzner{}
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
applicant, err := pHetzner.NewChallengeProvider(&pHetzner.ChallengeProviderConfig{
ApiToken: access.ApiToken,
DnsPropagationTimeout: options.DnsPropagationTimeout,
DnsTTL: options.DnsTTL,
})
return applicant, err
}
case domain.ACMEDns01ProviderTypeHuaweiCloud, domain.ACMEDns01ProviderTypeHuaweiCloudDNS: case domain.ACMEDns01ProviderTypeHuaweiCloud, domain.ACMEDns01ProviderTypeHuaweiCloudDNS:
{ {
access := domain.AccessConfigForHuaweiCloud{} access := domain.AccessConfigForHuaweiCloud{}

View File

@ -181,6 +181,10 @@ type AccessConfigForGoogleTrustServices struct {
EabHmacKey string `json:"eabHmacKey"` EabHmacKey string `json:"eabHmacKey"`
} }
type AccessConfigForHetzner struct {
ApiToken string `json:"apiToken"`
}
type AccessConfigForHuaweiCloud struct { type AccessConfigForHuaweiCloud struct {
AccessKeyId string `json:"accessKeyId"` AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"` SecretAccessKey string `json:"secretAccessKey"`

View File

@ -44,6 +44,7 @@ const (
AccessProviderTypeGoDaddy = AccessProviderType("godaddy") AccessProviderTypeGoDaddy = AccessProviderType("godaddy")
AccessProviderTypeGoEdge = AccessProviderType("goedge") AccessProviderTypeGoEdge = AccessProviderType("goedge")
AccessProviderTypeGoogleTrustServices = AccessProviderType("googletrustservices") AccessProviderTypeGoogleTrustServices = AccessProviderType("googletrustservices")
AccessProviderTypeHetzner = AccessProviderType("hetzner")
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud") AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
AccessProviderTypeJDCloud = AccessProviderType("jdcloud") AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
AccessProviderTypeKubernetes = AccessProviderType("k8s") AccessProviderTypeKubernetes = AccessProviderType("k8s")
@ -131,6 +132,7 @@ const (
ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore) ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore)
ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname) ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname)
ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy) ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy)
ACMEDns01ProviderTypeHetzner = ACMEDns01ProviderType(AccessProviderTypeHetzner)
ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS] ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS]
ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns") ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns")
ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS] ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS]

View File

@ -0,0 +1,36 @@
package namedotcom
import (
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/hetzner"
)
type ChallengeProviderConfig struct {
ApiToken string `json:"apiToken"`
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
DnsTTL int32 `json:"dnsTTL,omitempty"`
}
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
if config == nil {
panic("config is nil")
}
providerConfig := hetzner.NewDefaultConfig()
providerConfig.APIKey = config.ApiToken
if config.DnsPropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
}
if config.DnsTTL != 0 {
providerConfig.TTL = int(config.DnsTTL)
}
provider, err := hetzner.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="3000" height="380" viewBox="0 0 182 23" version="1.1"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g transform="translate(-1163.000000, -1368.000000)" fill="#D50C2D" fill-rule="nonzero"><g transform="translate(256.000000, 1363.000000)"><g transform="translate(907.000000, 5.000000)"><path d="M174.05,14.12 C175.70112,13.8347617 177.256782,13.1479352 178.58,12.12 L178.58,12.12 C179.800803,10.8420724 180.41283,9.10071075 180.26,7.34 C180.264681,5.90702289 179.869913,4.5010961 179.12,3.28 C178.012832,1.39206624 176.026262,0.191846827 173.84,0.09 L172.75,0.09 L170.2,0 L158.66,0 C157.96,0 157.66,0.29 157.66,1 L157.66,21.22 C157.66,21.92 157.95,22.22 158.66,22.22 L161.66,22.22 C162.36,22.22 162.66,21.93 162.66,21.22 L162.66,14.52 L166.33,14.52 C167.137054,14.5621636 167.904273,14.8839006 168.5,15.43 L174.32,21.28 C174.850563,21.8225831 175.56276,22.1501937 176.32,22.2 L180.79,22.2 C181.49,22.2 181.66,21.79 181.17,21.29 L174.05,14.12 Z M173.29,9.82 L162.64,9.82 L162.64,4.72 L173.29,4.72 C174.371509,4.85285283 175.178361,5.7805161 175.16,6.87 L175.16,7.66 C175.178907,8.75159761 174.373058,9.68241814 173.29,9.82 L173.29,9.82 Z"/><path d="M153,17.52 L136.47,17.52 L136.47,13.35 L149.66,13.35 C150.36,13.35 150.66,13.06 150.66,12.35 L150.66,9.92 C150.66,9.22 150.37,8.92 149.66,8.92 L136.46,8.92 L136.46,4.76 L153,4.76 C153.7,4.76 154,4.47 154,3.76 L154,1 C154,0.3 153.71,0 153,0 L132.38,0 C131.68,0 131.38,0.29 131.38,1 L131.38,21.24 C131.38,21.94 131.67,22.24 132.38,22.24 L153,22.24 C153.7,22.24 154,21.95 154,21.24 L154,18.51 C154,17.81 153.67,17.52 153,17.52 Z"/><path d="M127.73,7.3 C127.75181,5.88495547 127.358997,4.49446656 126.6,3.3 C125.485363,1.36532022 123.469349,0.124117692 121.24,0 L106.08,0 C105.37,0 105.08,0.29 105.08,1 L105.08,21.22 C105.08,21.92 105.37,22.22 106.08,22.22 L109.34,22.22 C110.04,22.22 110.34,21.94 110.34,21.22 L110.34,4.73 L119.12,4.73 C120.99,4.73 122.81,5.97 122.81,7.84 L122.81,21.24 C122.81,21.94 123.1,22.24 123.81,22.24 L126.76,22.24 C127.47,22.24 127.76,21.95 127.76,21.24 L127.73,7.3 Z"/><path d="M100.47,17.39 L86.22,17.39 L100.5,4.84 C101.079439,4.39644884 101.443005,3.72748773 101.5,3 L101.5,1 C101.5,0.3 101.2,0 100.5,0 L79.83,0 C79.13,0 78.83,0.29 78.83,1 L78.83,3.77 C78.83,4.47 79.12,4.77 79.83,4.77 L93.08,4.77 L79.79,17.24 C79.2153814,17.6876568 78.8530625,18.3543236 78.79,19.08 L78.79,21.25 C78.79,21.95 79.08,22.25 79.79,22.25 L100.44,22.25 C101.14,22.25 101.44,21.96 101.44,21.25 L101.44,18.38 C101.46,17.68 101.17,17.39 100.47,17.39 Z"/><path d="M74.19,0 L53.55,0 C52.84,0 52.55,0.28 52.55,1 L52.55,3.76 C52.55,4.46 52.83,4.76 53.55,4.76 L61.33,4.76 L61.33,21.24 C61.33,21.94 61.62,22.24 62.33,22.24 L65.63,22.24 C66.33,22.24 66.63,21.95 66.63,21.24 L66.63,4.75 L74.2,4.75 C74.9,4.75 75.2,4.46 75.2,3.75 L75.2,1 C75.18,0.32 74.89,0 74.19,0 Z"/><path d="M47.91,17.52 L31.41,17.52 L31.41,13.35 L44.6,13.35 C45.3,13.35 45.6,13.06 45.6,12.35 L45.6,9.92 C45.6,9.22 45.32,8.92 44.6,8.92 L31.41,8.92 L31.41,4.76 L47.91,4.76 C48.61,4.76 48.91,4.47 48.91,3.76 L48.91,1 C48.91,0.3 48.62,0 47.91,0 L27.33,0 C26.63,0 26.33,0.29 26.33,1 L26.33,21.24 C26.33,21.94 26.62,22.24 27.33,22.24 L47.91,22.24 C48.61,22.24 48.91,21.95 48.91,21.24 L48.91,18.51 C48.9,17.81 48.61,17.52 47.91,17.52 Z"/><path d="M21.63,0 L18.52,0 C17.82,0 17.52,0.29 17.52,1 L17.52,8.87 L5.13,8.87 L5.13,1 C5.13,0.3 4.84,0 4.13,0 L1,0 C0.29,0 0,0.29 0,1 L0,21.25 C0,21.96 0.29,22.25 1,22.25 L4.13,22.25 C4.83,22.25 5.13,21.97 5.13,21.25 L5.13,13.25 L17.53,13.25 L17.53,21.25 C17.53,21.95 17.82,22.25 18.53,22.25 L21.64,22.25 C22.34,22.25 22.64,21.96 22.64,21.25 L22.64,1 C22.62,0.32 22.33,0 21.63,0 Z"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -41,6 +41,7 @@ import AccessFormGnameConfig from "./AccessFormGnameConfig";
import AccessFormGoDaddyConfig from "./AccessFormGoDaddyConfig"; import AccessFormGoDaddyConfig from "./AccessFormGoDaddyConfig";
import AccessFormGoEdgeConfig from "./AccessFormGoEdgeConfig"; import AccessFormGoEdgeConfig from "./AccessFormGoEdgeConfig";
import AccessFormGoogleTrustServicesConfig from "./AccessFormGoogleTrustServicesConfig"; import AccessFormGoogleTrustServicesConfig from "./AccessFormGoogleTrustServicesConfig";
import AccessFormHetznerConfig from "./AccessFormHetznerConfig";
import AccessFormHuaweiCloudConfig from "./AccessFormHuaweiCloudConfig"; import AccessFormHuaweiCloudConfig from "./AccessFormHuaweiCloudConfig";
import AccessFormJDCloudConfig from "./AccessFormJDCloudConfig"; import AccessFormJDCloudConfig from "./AccessFormJDCloudConfig";
import AccessFormKubernetesConfig from "./AccessFormKubernetesConfig"; import AccessFormKubernetesConfig from "./AccessFormKubernetesConfig";
@ -239,6 +240,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
return <AccessFormGoEdgeConfig {...nestedFormProps} />; return <AccessFormGoEdgeConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.GOOGLETRUSTSERVICES: case ACCESS_PROVIDERS.GOOGLETRUSTSERVICES:
return <AccessFormGoogleTrustServicesConfig {...nestedFormProps} />; return <AccessFormGoogleTrustServicesConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.HETZNER:
return <AccessFormHetznerConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.HUAWEICLOUD: case ACCESS_PROVIDERS.HUAWEICLOUD:
return <AccessFormHuaweiCloudConfig {...nestedFormProps} />; return <AccessFormHuaweiCloudConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.JDCLOUD: case ACCESS_PROVIDERS.JDCLOUD:

View File

@ -0,0 +1,57 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import { type AccessConfigForHetzner } from "@/domain/access";
type AccessFormHetznerConfigFieldValues = Nullish<AccessConfigForHetzner>;
export type AccessFormHetznerConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormHetznerConfigFieldValues;
onValuesChange?: (values: AccessFormHetznerConfigFieldValues) => void;
};
const initFormModel = (): AccessFormHetznerConfigFieldValues => {
return {
apiToken: "",
};
};
const AccessFormHetznerConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormHetznerConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
apiToken: z.string().nonempty(t("access.form.hetzner_api_token.placeholder")).trim(),
});
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="apiToken"
label={t("access.form.hetzner_api_token.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.hetzner_api_token.tooltip") }}></span>}
>
<Input.Password autoComplete="new-password" placeholder={t("access.form.hetzner_api_token.placeholder")} />
</Form.Item>
</Form>
);
};
export default AccessFormHetznerConfig;

View File

@ -36,6 +36,7 @@ export interface AccessModel extends BaseModel {
| AccessConfigForGoDaddy | AccessConfigForGoDaddy
| AccessConfigForGoEdge | AccessConfigForGoEdge
| AccessConfigForGoogleTrustServices | AccessConfigForGoogleTrustServices
| AccessConfigForHetzner
| AccessConfigForHuaweiCloud | AccessConfigForHuaweiCloud
| AccessConfigForJDCloud | AccessConfigForJDCloud
| AccessConfigForKubernetes | AccessConfigForKubernetes
@ -238,6 +239,10 @@ export type AccessConfigForGoogleTrustServices = {
eabHmacKey: string; eabHmacKey: string;
}; };
export type AccessConfigForHetzner = {
apiToken: string;
};
export type AccessConfigForHuaweiCloud = { export type AccessConfigForHuaweiCloud = {
accessKeyId: string; accessKeyId: string;
secretAccessKey: string; secretAccessKey: string;

View File

@ -35,6 +35,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
GODADDY: "godaddy", GODADDY: "godaddy",
GOEDGE: "goedge", GOEDGE: "goedge",
GOOGLETRUSTSERVICES: "googletrustservices", GOOGLETRUSTSERVICES: "googletrustservices",
HETZNER: "hetzner",
HUAWEICLOUD: "huaweicloud", HUAWEICLOUD: "huaweicloud",
JDCLOUD: "jdcloud", JDCLOUD: "jdcloud",
KUBERNETES: "k8s", KUBERNETES: "k8s",
@ -142,6 +143,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
[ACCESS_PROVIDERS.DYNV6, "provider.dynv6", "/imgs/providers/dynv6.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.DYNV6, "provider.dynv6", "/imgs/providers/dynv6.svg", [ACCESS_USAGES.DNS]],
[ACCESS_PROVIDERS.GNAME, "provider.gname", "/imgs/providers/gname.png", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.GNAME, "provider.gname", "/imgs/providers/gname.png", [ACCESS_USAGES.DNS]],
[ACCESS_PROVIDERS.GODADDY, "provider.godaddy", "/imgs/providers/godaddy.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.GODADDY, "provider.godaddy", "/imgs/providers/godaddy.svg", [ACCESS_USAGES.DNS]],
[ACCESS_PROVIDERS.HETZNER, "provider.hetzner", "/imgs/providers/hetzner.svg", [ACCESS_USAGES.DNS]],
[ACCESS_PROVIDERS.NAMECHEAP, "provider.namecheap", "/imgs/providers/namecheap.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.NAMECHEAP, "provider.namecheap", "/imgs/providers/namecheap.svg", [ACCESS_USAGES.DNS]],
[ACCESS_PROVIDERS.NAMEDOTCOM, "provider.namedotcom", "/imgs/providers/namedotcom.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.NAMEDOTCOM, "provider.namedotcom", "/imgs/providers/namedotcom.svg", [ACCESS_USAGES.DNS]],
[ACCESS_PROVIDERS.NAMESILO, "provider.namesilo", "/imgs/providers/namesilo.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.NAMESILO, "provider.namesilo", "/imgs/providers/namesilo.svg", [ACCESS_USAGES.DNS]],
@ -258,6 +260,7 @@ export const ACME_DNS01_PROVIDERS = Object.freeze({
GCORE: `${ACCESS_PROVIDERS.GCORE}`, GCORE: `${ACCESS_PROVIDERS.GCORE}`,
GNAME: `${ACCESS_PROVIDERS.GNAME}`, GNAME: `${ACCESS_PROVIDERS.GNAME}`,
GODADDY: `${ACCESS_PROVIDERS.GODADDY}`, GODADDY: `${ACCESS_PROVIDERS.GODADDY}`,
HETZNER: `${ACCESS_PROVIDERS.HETZNER}`,
HUAWEICLOUD: `${ACCESS_PROVIDERS.HUAWEICLOUD}`, // 兼容旧值,等同于 `HUAWEICLOUD_DNS` HUAWEICLOUD: `${ACCESS_PROVIDERS.HUAWEICLOUD}`, // 兼容旧值,等同于 `HUAWEICLOUD_DNS`
HUAWEICLOUD_DNS: `${ACCESS_PROVIDERS.HUAWEICLOUD}-dns`, HUAWEICLOUD_DNS: `${ACCESS_PROVIDERS.HUAWEICLOUD}-dns`,
JDCLOUD: `${ACCESS_PROVIDERS.JDCLOUD}`, // 兼容旧值,等同于 `JDCLOUD_DNS` JDCLOUD: `${ACCESS_PROVIDERS.JDCLOUD}`, // 兼容旧值,等同于 `JDCLOUD_DNS`
@ -314,6 +317,7 @@ export const acmeDns01ProvidersMap: Map<ACMEDns01Provider["type"] | string, ACME
[ACME_DNS01_PROVIDERS.GCORE, "provider.gcore"], [ACME_DNS01_PROVIDERS.GCORE, "provider.gcore"],
[ACME_DNS01_PROVIDERS.GNAME, "provider.gname"], [ACME_DNS01_PROVIDERS.GNAME, "provider.gname"],
[ACME_DNS01_PROVIDERS.GODADDY, "provider.godaddy"], [ACME_DNS01_PROVIDERS.GODADDY, "provider.godaddy"],
[ACME_DNS01_PROVIDERS.HETZNER, "provider.hetzner"],
[ACME_DNS01_PROVIDERS.NAMECHEAP, "provider.namecheap"], [ACME_DNS01_PROVIDERS.NAMECHEAP, "provider.namecheap"],
[ACME_DNS01_PROVIDERS.NAMEDOTCOM, "provider.namedotcom"], [ACME_DNS01_PROVIDERS.NAMEDOTCOM, "provider.namedotcom"],
[ACME_DNS01_PROVIDERS.NAMESILO, "provider.namesilo"], [ACME_DNS01_PROVIDERS.NAMESILO, "provider.namesilo"],

View File

@ -237,6 +237,9 @@
"access.form.googletrustservices_eab_hmac_key.label": "ACME EAB HMAC key", "access.form.googletrustservices_eab_hmac_key.label": "ACME EAB HMAC key",
"access.form.googletrustservices_eab_hmac_key.placeholder": "Please enter ACME EAB HMAC key", "access.form.googletrustservices_eab_hmac_key.placeholder": "Please enter ACME EAB HMAC key",
"access.form.googletrustservices_eab_hmac_key.tooltip": "For more information, see <a href=\"https://cloud.google.com/certificate-manager/docs/public-ca-tutorial\" target=\"_blank\">https://cloud.google.com/certificate-manager/docs/public-ca-tutorial</a>", "access.form.googletrustservices_eab_hmac_key.tooltip": "For more information, see <a href=\"https://cloud.google.com/certificate-manager/docs/public-ca-tutorial\" target=\"_blank\">https://cloud.google.com/certificate-manager/docs/public-ca-tutorial</a>",
"access.form.hetzner_api_token.label": "Hetzner API token",
"access.form.hetzner_api_token.placeholder": "Please enter Hetzner API token",
"access.form.hetzner_api_token.tooltip": "For more information, see <a href=\"https://docs.hetzner.com/cloud/api/getting-started/generating-api-token\" target=\"_blank\">https://docs.hetzner.com/cloud/api/getting-started/generating-api-token</a>",
"access.form.huaweicloud_access_key_id.label": "Huawei Cloud AccessKeyId", "access.form.huaweicloud_access_key_id.label": "Huawei Cloud AccessKeyId",
"access.form.huaweicloud_access_key_id.placeholder": "Please enter Huawei Cloud AccessKeyId", "access.form.huaweicloud_access_key_id.placeholder": "Please enter Huawei Cloud AccessKeyId",
"access.form.huaweicloud_access_key_id.tooltip": "For more information, see <a href=\"https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html</a>", "access.form.huaweicloud_access_key_id.tooltip": "For more information, see <a href=\"https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html</a>",

View File

@ -74,6 +74,7 @@
"provider.godaddy": "GoDaddy", "provider.godaddy": "GoDaddy",
"provider.goedge": "GoEdge", "provider.goedge": "GoEdge",
"provider.googletrustservices": "Google Trust Services", "provider.googletrustservices": "Google Trust Services",
"provider.hetzner": "Hetzner",
"provider.huaweicloud": "Huawei Cloud", "provider.huaweicloud": "Huawei Cloud",
"provider.huaweicloud.cdn": "Huawei Cloud - CDN (Content Delivery Network)", "provider.huaweicloud.cdn": "Huawei Cloud - CDN (Content Delivery Network)",
"provider.huaweicloud.dns": "Huawei Cloud - DNS (Domain Name Service)", "provider.huaweicloud.dns": "Huawei Cloud - DNS (Domain Name Service)",

View File

@ -231,6 +231,9 @@
"access.form.googletrustservices_eab_hmac_key.label": "ACME EAB HMAC Key", "access.form.googletrustservices_eab_hmac_key.label": "ACME EAB HMAC Key",
"access.form.googletrustservices_eab_hmac_key.placeholder": "请输入 ACME EAB HMAC Key", "access.form.googletrustservices_eab_hmac_key.placeholder": "请输入 ACME EAB HMAC Key",
"access.form.googletrustservices_eab_hmac_key.tooltip": "这是什么?请参阅 <a href=\"https://cloud.google.com/certificate-manager/docs/public-ca-tutorial\" target=\"_blank\">https://cloud.google.com/certificate-manager/docs/public-ca-tutorial</a>", "access.form.googletrustservices_eab_hmac_key.tooltip": "这是什么?请参阅 <a href=\"https://cloud.google.com/certificate-manager/docs/public-ca-tutorial\" target=\"_blank\">https://cloud.google.com/certificate-manager/docs/public-ca-tutorial</a>",
"access.form.hetzner_api_token.label": "Hetzner API Token",
"access.form.hetzner_api_token.placeholder": "请输入 Hetzner API Token",
"access.form.hetzner_api_token.tooltip": "这是什么?请参阅 <a href=\"https://docs.hetzner.com/cloud/api/getting-started/generating-api-token\" target=\"_blank\">https://docs.hetzner.com/cloud/api/getting-started/generating-api-token</a>",
"access.form.huaweicloud_access_key_id.label": "华为云 AccessKeyId", "access.form.huaweicloud_access_key_id.label": "华为云 AccessKeyId",
"access.form.huaweicloud_access_key_id.placeholder": "请输入华为云 AccessKeyId", "access.form.huaweicloud_access_key_id.placeholder": "请输入华为云 AccessKeyId",
"access.form.huaweicloud_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html</a>", "access.form.huaweicloud_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html</a>",

View File

@ -74,6 +74,7 @@
"provider.godaddy": "GoDaddy", "provider.godaddy": "GoDaddy",
"provider.goedge": "GoEdge", "provider.goedge": "GoEdge",
"provider.googletrustservices": "Google Trust Services", "provider.googletrustservices": "Google Trust Services",
"provider.hetzner": "Hetzner",
"provider.huaweicloud": "华为云", "provider.huaweicloud": "华为云",
"provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN", "provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN",
"provider.huaweicloud.dns": "华为云 - 云解析 DNS", "provider.huaweicloud.dns": "华为云 - 云解析 DNS",