From 70bd2f05818a13fd7f99be8a480bb6114ad66cc3 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 15 May 2025 22:22:18 +0800 Subject: [PATCH] feat: new acme dns-01 provider: netlify --- internal/applicant/providers.go | 16 +++++ internal/domain/access.go | 4 ++ internal/domain/provider.go | 2 + .../lego-providers/netlify/netlify.go | 36 +++++++++++ ui/public/imgs/providers/netlify.png | Bin 0 -> 16699 bytes ui/src/components/access/AccessForm.tsx | 3 + .../access/AccessFormNetlifyConfig.tsx | 57 ++++++++++++++++++ ui/src/domain/access.ts | 5 ++ ui/src/domain/provider.ts | 6 +- ui/src/i18n/locales/en/nls.access.json | 3 + ui/src/i18n/locales/en/nls.provider.json | 1 + ui/src/i18n/locales/zh/nls.access.json | 3 + ui/src/i18n/locales/zh/nls.provider.json | 1 + 13 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 internal/pkg/core/applicant/acme-dns-01/lego-providers/netlify/netlify.go create mode 100644 ui/public/imgs/providers/netlify.png create mode 100644 ui/src/components/access/AccessFormNetlifyConfig.tsx diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go index d4d630c4..90a3cf72 100644 --- a/internal/applicant/providers.go +++ b/internal/applicant/providers.go @@ -28,6 +28,7 @@ import ( pNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom" pNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo" pNetcup "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/netcup" + pNetlify "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/netlify" pNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1" pPorkbun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/porkbun" pPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns" @@ -420,6 +421,21 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi return applicant, err } + case domain.ACMEDns01ProviderTypeNetlify: + { + access := domain.AccessConfigForNetlify{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pNetlify.NewChallengeProvider(&pNetlify.ChallengeProviderConfig{ + ApiToken: access.ApiToken, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + case domain.ACMEDns01ProviderTypeNS1: { access := domain.AccessConfigForNS1{} diff --git a/internal/domain/access.go b/internal/domain/access.go index c18f846e..35dd9b0a 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -205,6 +205,10 @@ type AccessConfigForNetcup struct { ApiPassword string `json:"apiPassword"` } +type AccessConfigForNetlify struct { + ApiToken string `json:"apiToken"` +} + type AccessConfigForNS1 struct { ApiKey string `json:"apiKey"` } diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 4de70cd3..2c80f6cb 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -53,6 +53,7 @@ const ( AccessProviderTypeNameDotCom = AccessProviderType("namedotcom") AccessProviderTypeNameSilo = AccessProviderType("namesilo") AccessProviderTypeNetcup = AccessProviderType("netcup") + AccessProviderTypeNetlify = AccessProviderType("netlify") AccessProviderTypeNS1 = AccessProviderType("ns1") AccessProviderTypePorkbun = AccessProviderType("porkbun") AccessProviderTypePowerDNS = AccessProviderType("powerdns") @@ -132,6 +133,7 @@ const ( ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom) ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo) ACMEDns01ProviderTypeNetcup = ACMEDns01ProviderType(AccessProviderTypeNetcup) + ACMEDns01ProviderTypeNetlify = ACMEDns01ProviderType(AccessProviderTypeNetlify) ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1) ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun) ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS) diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/netlify/netlify.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/netlify/netlify.go new file mode 100644 index 00000000..f590372b --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/netlify/netlify.go @@ -0,0 +1,36 @@ +package netcup + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/providers/dns/netlify" +) + +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 := netlify.NewDefaultConfig() + providerConfig.Token = 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 := netlify.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/netlify.png b/ui/public/imgs/providers/netlify.png new file mode 100644 index 0000000000000000000000000000000000000000..a04eeeba9e9dd2c7bdc16550c428e32ba796b943 GIT binary patch literal 16699 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 className, return ; case ACCESS_PROVIDERS.NETCUP: return ; + case ACCESS_PROVIDERS.NETLIFY: + return ; case ACCESS_PROVIDERS.NS1: return ; case ACCESS_PROVIDERS.PORKBUN: diff --git a/ui/src/components/access/AccessFormNetlifyConfig.tsx b/ui/src/components/access/AccessFormNetlifyConfig.tsx new file mode 100644 index 00000000..7fa4c8ae --- /dev/null +++ b/ui/src/components/access/AccessFormNetlifyConfig.tsx @@ -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 AccessConfigForNetlify } from "@/domain/access"; + +type AccessFormNetlifyConfigFieldValues = Nullish; + +export type AccessFormNetlifyConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormNetlifyConfigFieldValues; + onValuesChange?: (values: AccessFormNetlifyConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormNetlifyConfigFieldValues => { + return { + apiToken: "", + }; +}; + +const AccessFormNetlifyConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormNetlifyConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiToken: z.string().nonempty(t("access.form.netlify_api_token.placeholder")).trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default AccessFormNetlifyConfig; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index e0cce59d..0d516385 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -42,6 +42,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForNameDotCom | AccessConfigForNameSilo | AccessConfigForNetcup + | AccessConfigForNetlify | AccessConfigForPorkbun | AccessConfigForPowerDNS | AccessConfigForProxmoxVE @@ -256,6 +257,10 @@ export type AccessConfigForNetcup = { apiPassword: string; }; +export type AccessConfigForNetlify = { + apiToken: string; +}; + export type AccessConfigForNS1 = { apiKey: string; }; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 5cc50534..12afaa85 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -44,6 +44,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ NAMEDOTCOM: "namedotcom", NAMESILO: "namesilo", NETCUP: "netcup", + NETLIFY: "netlify", NS1: "ns1", PORKBUN: "porkbun", POWERDNS: "powerdns", @@ -133,8 +134,9 @@ export const accessProvidersMap: Maphttps://www.namesilo.com/support/v2/articles/account-options/api-manager", + "access.form.netlify_api_token.label": "netlify API token", + "access.form.netlify_api_token.placeholder": "Please enter netlify API token", + "access.form.netlify_api_token.tooltip": "For more information, see https://docs.netlify.com/api/get-started/#authentication", "access.form.netcup_customer_number.label": "netcup customer number", "access.form.netcup_customer_number.placeholder": "Please enter netcup customer number", "access.form.netcup_customer_number.tooltip": "For more information, see https://helpcenter.netcup.com/en/wiki/general/ccp-login/", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 1f7e5589..30c818dd 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -91,6 +91,7 @@ "provider.namedotcom": "Name.com", "provider.namesilo": "NameSilo", "provider.netcup": "netcup", + "provider.netlify": "netlify", "provider.ns1": "NS1 (IBM NS1 Connect)", "provider.porkbun": "Porkbun", "provider.powerdns": "PowerDNS", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index fd993178..f73065ea 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -256,6 +256,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": "这是什么?请参阅 https://www.namesilo.com/support/v2/articles/account-options/api-manager", + "access.form.netlify_api_token.label": "netlify API Token", + "access.form.netlify_api_token.placeholder": "请输入 netlify API Token", + "access.form.netlify_api_token.tooltip": "这是什么?请参阅 https://docs.netlify.com/api/get-started/#authentication", "access.form.netcup_customer_number.label": "netcup 客户编号", "access.form.netcup_customer_number.placeholder": "请输入 netcup 客户编号", "access.form.netcup_customer_number.tooltip": "这是什么?请参阅 https://helpcenter.netcup.com/en/wiki/general/ccp-login/", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 739fcebf..bf9470d0 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -91,6 +91,7 @@ "provider.namedotcom": "Name.com", "provider.namesilo": "NameSilo", "provider.netcup": "netcup", + "provider.netlify": "netlify", "provider.ns1": "NS1 (IBM NS1 Connect)", "provider.porkbun": "Porkbun", "provider.powerdns": "PowerDNS",