feat: add ns1 applicant

This commit is contained in:
Fu Diwei 2025-01-15 14:24:51 +08:00
parent e264d71048
commit dd236b925d
17 changed files with 174 additions and 34 deletions

View File

@ -86,20 +86,21 @@ make local.run
<summary>[展开查看]</summary>
| 提供商 | 备注 |
| :--------------------------------------------- | :-------------------------------------- |
| [阿里云](https://www.aliyun.com/) | |
| [腾讯云](https://cloud.tencent.com/) | |
| [华为云](https://www.huaweicloud.com/) | |
| [火山引擎](https://www.volcengine.com/) | |
| [AWS Route53](https://aws.amazon.com/route53/) | |
| [Azure](https://azure.microsoft.com/) | |
| [CloudFlare](https://www.cloudflare.com/) | |
| [GoDaddy](https://www.godaddy.com/) | |
| [Name.com](https://www.name.com/) | |
| [NameSilo](https://www.namesilo.com/) | |
| [PowerDNS](https://www.powerdns.com/) | |
| ACME 代理 HTTP 请求 | 可申请允许通过 HTTP 请求修改 DNS 的域名 |
| 提供商 | 备注 |
| :----------------------------------------------------------------- | :-------------------------------------- |
| [阿里云](https://www.aliyun.com/) | |
| [腾讯云](https://cloud.tencent.com/) | |
| [华为云](https://www.huaweicloud.com/) | |
| [火山引擎](https://www.volcengine.com/) | |
| [AWS Route53](https://aws.amazon.com/route53/) | |
| [Azure](https://azure.microsoft.com/) | |
| [CloudFlare](https://www.cloudflare.com/) | |
| [GoDaddy](https://www.godaddy.com/) | |
| [Name.com](https://www.name.com/) | |
| [NameSilo](https://www.namesilo.com/) | |
| [IBM NS1 Connect](https://www.ibm.com/cn-zh/products/ns1-connect/) | |
| [PowerDNS](https://www.powerdns.com/) | |
| ACME 代理 HTTP 请求 | 可申请允许通过 HTTP 请求修改 DNS 的域名 |
</details>

View File

@ -85,20 +85,21 @@ The following DNS providers are supported:
<summary>[Fold/Unfold to view ...]</summary>
| Provider | Remarks |
| :--------------------------------------------- | :------------------------------------ |
| [Alibaba Cloud](https://www.alibabacloud.com/) | |
| [Tencent Cloud](https://www.tencentcloud.com/) | |
| [Huawei Cloud](https://www.huaweicloud.com/) | |
| [Volcengine](https://www.volcengine.com/) | |
| [AWS Route53](https://aws.amazon.com/route53/) | |
| [Azure DNS](https://azure.microsoft.com/) | |
| [CloudFlare](https://www.cloudflare.com/) | |
| [GoDaddy](https://www.godaddy.com/) | |
| [Name.com](https://www.name.com/) | |
| [NameSilo](https://www.namesilo.com/) | |
| [PowerDNS](https://www.powerdns.com/) | |
| ACME Proxy HTTP Request | Supports managing DNS by HTTP request |
| Provider | Remarks |
| :----------------------------------------------------------- | :------------------------------------ |
| [Alibaba Cloud](https://www.alibabacloud.com/) | |
| [Tencent Cloud](https://www.tencentcloud.com/) | |
| [Huawei Cloud](https://www.huaweicloud.com/) | |
| [Volcengine](https://www.volcengine.com/) | |
| [AWS Route53](https://aws.amazon.com/route53/) | |
| [Azure DNS](https://azure.microsoft.com/) | |
| [CloudFlare](https://www.cloudflare.com/) | |
| [GoDaddy](https://www.godaddy.com/) | |
| [Name.com](https://www.name.com/) | |
| [NameSilo](https://www.namesilo.com/) | |
| [IBM NS1 Connect](https://www.ibm.com/products/ns1-connect/) | |
| [PowerDNS](https://www.powerdns.com/) | |
| ACME Proxy HTTP Request | Supports managing DNS by HTTP request |
</details>

1
go.mod
View File

@ -87,6 +87,7 @@ require (
go.mongodb.org/mongo-driver v1.12.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ns1/ns1-go.v2 v2.13.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect

2
go.sum
View File

@ -1369,6 +1369,8 @@ gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/ns1/ns1-go.v2 v2.13.0 h1:I5NNqI9Bi1SGK92TVkOvLTwux5LNrix/99H2datVh48=
gopkg.in/ns1/ns1-go.v2 v2.13.0/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -15,6 +15,7 @@ import (
providerHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud"
providerNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom"
providerNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo"
providerNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1"
providerPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns"
providerTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud"
providerVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine"
@ -167,6 +168,20 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) {
return applicant, err
}
case domain.ApplyDNSProviderTypeNS1:
{
access := domain.AccessConfigForNS1{}
if err := maps.Decode(options.ProviderAccessConfig, &access); err != nil {
return nil, fmt.Errorf("failed to decode provider access config: %w", err)
}
applicant, err := providerNS1.NewChallengeProvider(&providerNS1.NS1ApplicantConfig{
ApiKey: access.ApiKey,
PropagationTimeout: options.PropagationTimeout,
})
return applicant, err
}
case domain.ApplyDNSProviderTypePowerDNS:
{
access := domain.AccessConfigForPowerDNS{}

View File

@ -91,6 +91,10 @@ type AccessConfigForNameSilo struct {
ApiKey string `json:"apiKey"`
}
type AccessConfigForNS1 struct {
ApiKey string `json:"apiKey"`
}
type AccessConfigForPowerDNS struct {
ApiUrl string `json:"apiUrl"`
ApiKey string `json:"apiKey"`

View File

@ -23,6 +23,7 @@ const (
AccessProviderTypeLocal = AccessProviderType("local")
AccessProviderTypeNameDotCom = AccessProviderType("namedotcom")
AccessProviderTypeNameSilo = AccessProviderType("namesilo")
AccessProviderTypeNS1 = AccessProviderType("ns1")
AccessProviderTypePowerDNS = AccessProviderType("powerdns")
AccessProviderTypeQiniu = AccessProviderType("qiniu")
AccessProviderTypeSSH = AccessProviderType("ssh")
@ -54,6 +55,7 @@ const (
ApplyDNSProviderTypeHuaweiCloudDNS = ApplyDNSProviderType("huaweicloud-dns")
ApplyDNSProviderTypeNameDotCom = ApplyDNSProviderType("namedotcom")
ApplyDNSProviderTypeNameSilo = ApplyDNSProviderType("namesilo")
ApplyDNSProviderTypeNS1 = ApplyDNSProviderType("ns1")
ApplyDNSProviderTypePowerDNS = ApplyDNSProviderType("powerdns")
ApplyDNSProviderTypeTencentCloud = ApplyDNSProviderType("tencentcloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeTencentCloudDNS]
ApplyDNSProviderTypeTencentCloudDNS = ApplyDNSProviderType("tencentcloud-dns")

View File

@ -0,0 +1,33 @@
package ns1
import (
"errors"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/ns1"
)
type NS1ApplicantConfig struct {
ApiKey string `json:"apiKey"`
PropagationTimeout int32 `json:"propagationTimeout,omitempty"`
}
func NewChallengeProvider(config *NS1ApplicantConfig) (challenge.Provider, error) {
if config == nil {
return nil, errors.New("config is nil")
}
providerConfig := ns1.NewDefaultConfig()
providerConfig.APIKey = config.ApiKey
if config.PropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.PropagationTimeout) * time.Second
}
provider, err := ns1.NewDNSProviderConfig(providerConfig)
if err != nil {
return nil, err
}
return provider, nil
}

View File

@ -0,0 +1 @@
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 390 390"><g fill="#231F20FD" stroke="#231F20FD"><path d="M 51.963 131.224 C 51.886 131.803 51.845 243.686 51.921 247.250 L 52.000 251.000 63.566 251.000 L 75.132 251.000 74.816 206.999 C 74.642 182.799 74.742 162.999 75.039 162.999 C 75.335 163.000 77.312 167.388 79.432 172.750 C 83.399 182.788 90.389 197.123 107.833 231.000 L 117.874 250.500 132.937 250.776 L 148.000 251.052 148.000 190.994 L 148.000 130.937 136.250 131.218 L 124.500 131.500 124.500 173.500 L 124.500 215.500 120.750 207.625 C 118.688 203.294 117.000 199.596 117.000 199.407 C 117.000 198.519 89.835 145.115 83.984 134.500 L 82.331 131.500 67.165 131.224 C 58.824 131.072 51.983 131.072 51.963 131.224 "/></g><g fill="#231F20FD" stroke="#231F20FD"><path d="M 198.000 132.031 C 186.222 134.506 175.076 142.919 170.355 152.899 C 166.812 160.387 166.653 172.157 169.999 179.275 C 173.108 185.888 182.377 194.106 191.729 198.540 C 214.885 209.518 217.990 211.199 220.403 214.067 C 225.383 219.986 222.954 228.450 215.364 231.621 C 205.909 235.572 189.337 230.763 178.483 220.919 C 176.495 219.115 176.374 219.224 169.983 228.525 C 166.417 233.714 163.500 238.750 163.500 239.716 C 163.500 243.321 178.319 250.974 189.353 253.067 C 195.907 254.310 210.272 254.251 217.295 252.953 C 233.791 249.904 246.375 238.021 248.563 223.425 C 250.000 213.849 245.659 202.627 237.670 195.264 C 232.765 190.743 229.887 189.103 213.403 181.443 C 200.793 175.583 196.411 172.667 194.403 168.800 C 192.158 164.479 192.698 161.300 196.355 157.310 C 199.384 154.005 200.311 153.605 205.890 153.202 C 213.355 152.662 219.518 154.710 225.794 159.818 C 228.193 161.771 230.428 162.913 230.859 162.406 C 231.283 161.908 234.301 158.350 237.565 154.500 C 240.829 150.650 243.838 147.350 244.250 147.167 C 248.483 145.285 237.577 136.985 226.119 133.367 C 220.358 131.549 203.998 130.771 198.000 132.031 "/></g><g fill="#231F20FD" stroke="#231F20FD"><path d="M 272.000 138.618 C 258.179 148.122 258.897 146.529 263.910 156.550 C 266.273 161.276 268.771 165.359 269.460 165.623 C 270.149 165.887 273.365 164.338 276.606 162.179 L 282.500 158.254 282.760 204.627 L 283.020 251.000 295.010 251.000 L 307.000 251.000 307.000 191.500 L 307.000 132.000 294.250 132.043 L 281.500 132.086 272.000 138.618 "/></g><g fill="#F30270FE" stroke="#F30270FE"><path d="M 325.071 225.703 C 315.164 230.894 314.604 243.488 324.000 249.818 C 334.022 256.571 347.264 246.120 344.007 234.027 C 341.944 226.364 332.083 222.030 325.071 225.703 "/></g></svg>

View File

@ -21,6 +21,7 @@ import AccessFormGoDaddyConfig from "./AccessFormGoDaddyConfig";
import AccessFormHuaweiCloudConfig from "./AccessFormHuaweiCloudConfig";
import AccessFormKubernetesConfig from "./AccessFormKubernetesConfig";
import AccessFormLocalConfig from "./AccessFormLocalConfig";
import AccessFormNS1Config from "./AccessFormNS1Config";
import AccessFormNameDotComConfig from "./AccessFormNameDotComConfig";
import AccessFormNameSiloConfig from "./AccessFormNameSiloConfig";
import AccessFormPowerDNSConfig from "./AccessFormPowerDNSConfig";
@ -111,6 +112,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
return <AccessFormNameDotComConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.NAMESILO:
return <AccessFormNameSiloConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.NS1:
return <AccessFormNS1Config {...nestedFormProps} />;
case ACCESS_PROVIDERS.POWERDNS:
return <AccessFormPowerDNSConfig {...nestedFormProps} />;
case ACCESS_PROVIDERS.QINIU:

View File

@ -0,0 +1,61 @@
import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import { type AccessConfigForNS1 } from "@/domain/access";
type AccessFormNS1ConfigFieldValues = Nullish<AccessConfigForNS1>;
export type AccessFormNS1ConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
initialValues?: AccessFormNS1ConfigFieldValues;
onValuesChange?: (values: AccessFormNS1ConfigFieldValues) => void;
};
const initFormModel = (): AccessFormNS1ConfigFieldValues => {
return {
apiKey: "",
};
};
const AccessFormNS1Config = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormNS1ConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
apiKey: z
.string()
.min(1, t("access.form.ns1_api_key.placeholder"))
.max(64, t("common.errmsg.string_max", { max: 64 }))
.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="apiKey"
label={t("access.form.ns1_api_key.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ns1_api_key.tooltip") }}></span>}
>
<Input.Password autoComplete="new-password" placeholder={t("access.form.ns1_api_key.placeholder")} />
</Form.Item>
</Form>
);
};
export default AccessFormNS1Config;

View File

@ -102,6 +102,10 @@ export type AccessConfigForNameSilo = {
apiKey: string;
};
export type AccessConfigForNS1 = {
apiKey: string;
};
export type AccessConfigForPowerDNS = {
apiUrl: string;
apiKey: string;

View File

@ -18,6 +18,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
LOCAL: "local",
NAMEDOTCOM: "namedotcom",
NAMESILO: "namesilo",
NS1: "ns1",
POWERDNS: "powerdns",
QINIU: "qiniu",
SSH: "ssh",
@ -68,6 +69,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
[ACCESS_PROVIDERS.CLOUDFLARE, "common.provider.cloudflare", "/imgs/providers/cloudflare.svg", ACCESS_USAGES.APPLY],
[ACCESS_PROVIDERS.NAMEDOTCOM, "common.provider.namedotcom", "/imgs/providers/namedotcom.svg", ACCESS_USAGES.APPLY],
[ACCESS_PROVIDERS.NAMESILO, "common.provider.namesilo", "/imgs/providers/namesilo.svg", ACCESS_USAGES.APPLY],
[ACCESS_PROVIDERS.NS1, "common.provider.ns1", "/imgs/providers/ns1.svg", ACCESS_USAGES.APPLY],
[ACCESS_PROVIDERS.GODADDY, "common.provider.godaddy", "/imgs/providers/godaddy.svg", ACCESS_USAGES.APPLY],
[ACCESS_PROVIDERS.POWERDNS, "common.provider.powerdns", "/imgs/providers/powerdns.svg", ACCESS_USAGES.APPLY],
[ACCESS_PROVIDERS.ACMEHTTPREQ, "common.provider.acmehttpreq", "/imgs/providers/acmehttpreq.svg", ACCESS_USAGES.APPLY],
@ -101,6 +103,7 @@ export const APPLY_DNS_PROVIDERS = Object.freeze({
HUAWEICLOUD_DNS: `${ACCESS_PROVIDERS.HUAWEICLOUD}-dns`,
NAMEDOTCOM: `${ACCESS_PROVIDERS.NAMEDOTCOM}`,
NAMESILO: `${ACCESS_PROVIDERS.NAMESILO}`,
NS1: `${ACCESS_PROVIDERS.NS1}`,
POWERDNS: `${ACCESS_PROVIDERS.POWERDNS}`,
TENCENTCLOUD: `${ACCESS_PROVIDERS.TENCENTCLOUD}`, // 兼容旧值,等同于 `TENCENTCLOUD_DNS`
TENCENTCLOUD_DNS: `${ACCESS_PROVIDERS.TENCENTCLOUD}-dns`,
@ -133,6 +136,7 @@ export const applyDNSProvidersMap: Map<ApplyDNSProvider["type"] | string, ApplyD
[APPLY_DNS_PROVIDERS.GODADDY, "common.provider.godaddy"],
[APPLY_DNS_PROVIDERS.NAMEDOTCOM, "common.provider.namedotcom"],
[APPLY_DNS_PROVIDERS.NAMESILO, "common.provider.namesilo"],
[APPLY_DNS_PROVIDERS.NS1, "common.provider.ns1"],
[APPLY_DNS_PROVIDERS.POWERDNS, "common.provider.powerdns"],
[APPLY_DNS_PROVIDERS.ACMEHTTPREQ, "common.provider.acmehttpreq"],
].map(([type, name]) => [

View File

@ -103,6 +103,9 @@
"access.form.namesilo_api_key.label": "NameSilo API key",
"access.form.namesilo_api_key.placeholder": "Please enter NameSilo API key",
"access.form.namesilo_api_key.tooltip": "For more information, see <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>",
"access.form.ns1_api_key.label": "NS1 API key",
"access.form.ns1_api_key.placeholder": "Please enter NS1 API key",
"access.form.ns1_api_key.tooltip": "For more information, see <a href=\"https://www.ibm.com/docs/en/ns1-connect?topic=introduction-using-api\" target=\"_blank\">https://www.ibm.com/docs/en/ns1-connect?topic=introduction-using-api</a>",
"access.form.powerdns_api_url.label": "PowerDNS API URL",
"access.form.powerdns_api_url.placeholder": "Please enter PowerDNS API URL",
"access.form.powerdns_api_url.tooltip": "For more information, see <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api</a>",

View File

@ -66,6 +66,7 @@
"common.provider.local": "Local deployment",
"common.provider.namedotcom": "Name.com",
"common.provider.namesilo": "NameSilo",
"common.provider.ns1": "NS1 (IBM NS1 Connect)",
"common.provider.powerdns": "PowerDNS",
"common.provider.qiniu": "Qiniu",
"common.provider.qiniu.cdn": "Qiniu - Content Delivery Network (CDN)",

View File

@ -45,14 +45,14 @@
"access.form.aws_secret_access_key.label": "AWS SecretAccessKey",
"access.form.aws_secret_access_key.placeholder": "请输入 AWS SecretAccessKey",
"access.form.aws_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html</a>",
"access.form.azure_tenant_id.label": "Azure TenantId",
"access.form.azure_tenant_id.placeholder": "请输入 Azure TenantId",
"access.form.azure_tenant_id.label": "Azure 租户 ID",
"access.form.azure_tenant_id.placeholder": "请输入 Azure 租户 ID",
"access.form.azure_tenant_id.tooltip": "这是什么?请参阅 <a href=\"https://learn.microsoft.com/zh-cn/azure/azure-portal/get-subscription-tenant-id\" target=\"_blank\">https://learn.microsoft.com/zh-cn/azure/azure-portal/get-subscription-tenant-id</a>",
"access.form.azure_client_id.label": "Azure ClientId",
"access.form.azure_client_id.placeholder": "请输入 Azure ClientId",
"access.form.azure_client_id.label": "Azure 客户端 ID",
"access.form.azure_client_id.placeholder": "请输入 Azure 客户端 ID",
"access.form.azure_client_id.tooltip": "这是什么?请参阅 <a href=\"https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token\" target=\"_blank\">https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token</a>",
"access.form.azure_client_secret.label": "Azure ClientSecret",
"access.form.azure_client_secret.placeholder": "请输入 Azure ClientSecret",
"access.form.azure_client_secret.label": "Azure 客户端密码",
"access.form.azure_client_secret.placeholder": "请输入 Azure 客户端密码",
"access.form.azure_client_secret.tooltip": "这是什么?请参阅 <a href=\"https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token\" target=\"_blank\">https://learn.microsoft.com/zh-cn/azure/azure-monitor/logs/api/register-app-for-token</a>",
"access.form.azure_cloud_name.label": "Azure 主权云环境(可选)",
"access.form.azure_cloud_name.placeholder": "请输入 Azure 主权云环境例如public",
@ -103,6 +103,9 @@
"access.form.namesilo_api_key.label": "NameSilo API Key",
"access.form.namesilo_api_key.placeholder": "请输入 NameSilo API Key",
"access.form.namesilo_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>",
"access.form.ns1_api_key.label": "NS1 API Key",
"access.form.ns1_api_key.placeholder": "请输入 NS1 API Key",
"access.form.ns1_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.ibm.com/docs/zh/ns1-connect?topic=introduction-using-api\" target=\"_blank\">https://www.ibm.com/docs/zh/ns1-connect?topic=introduction-using-api</a>",
"access.form.powerdns_api_url.label": "PowerDNS API URL",
"access.form.powerdns_api_url.placeholder": "请输入 PowerDNS API URL",
"access.form.powerdns_api_url.tooltip": "这是什么?请参阅 <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api</a>",

View File

@ -66,6 +66,7 @@
"common.provider.local": "本地部署",
"common.provider.namedotcom": "Name.com",
"common.provider.namesilo": "NameSilo",
"common.provider.ns1": "NS1IBM NS1 Connect",
"common.provider.powerdns": "PowerDNS",
"common.provider.qiniu": "七牛云",
"common.provider.qiniu.cdn": "七牛云 - 内容分发网络 CDN",