diff --git a/internal/certapply/applicators/sp_dnsmadeeasy.go b/internal/certapply/applicators/sp_dnsmadeeasy.go new file mode 100644 index 000000000..32919f2d4 --- /dev/null +++ b/internal/certapply/applicators/sp_dnsmadeeasy.go @@ -0,0 +1,30 @@ +package applicators + +import ( + "fmt" + + "github.com/go-acme/lego/v4/challenge" + + "github.com/certimate-go/certimate/internal/domain" + "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/dnsmadeeasy" + xmaps "github.com/certimate-go/certimate/pkg/utils/maps" +) + +func init() { + if err := ACMEDns01Registries.Register(domain.ACMEDns01ProviderTypeDNSMadeEasy, func(options *ProviderFactoryOptions) (challenge.Provider, error) { + credentials := domain.AccessConfigForDNSMadeEasy{} + if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + provider, err := dnsmadeeasy.NewChallengeProvider(&dnsmadeeasy.ChallengeProviderConfig{ + ApiKey: credentials.ApiKey, + ApiSecret: credentials.ApiSecret, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return provider, err + }); err != nil { + panic(err) + } +} diff --git a/internal/domain/access.go b/internal/domain/access.go index 0a3cb9985..43d6d952a 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -176,6 +176,11 @@ type AccessConfigForDNSLA struct { ApiSecret string `json:"apiSecret"` } +type AccessConfigForDNSMadeEasy struct { + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` +} + type AccessConfigForDogeCloud struct { AccessKey string `json:"accessKey"` SecretKey string `json:"secretKey"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index c8e215ab5..0076e2965 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -41,7 +41,7 @@ const ( AccessProviderTypeDingTalkBot = AccessProviderType("dingtalkbot") AccessProviderTypeDiscordBot = AccessProviderType("discordbot") AccessProviderTypeDNSLA = AccessProviderType("dnsla") - AccessProviderTypeDNSMadeEasy = AccessProviderType("dnsmadeeasy") // DNS Made Easy(预留) + AccessProviderTypeDNSMadeEasy = AccessProviderType("dnsmadeeasy") AccessProviderTypeDogeCloud = AccessProviderType("dogecloud") AccessProviderTypeDuckDNS = AccessProviderType("duckdns") AccessProviderTypeDynu = AccessProviderType("dynu") // Dynu(预留) diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/dnsmadeeasy/dnsmadeeasy.go b/pkg/core/ssl-applicator/acme-dns01/providers/dnsmadeeasy/dnsmadeeasy.go new file mode 100644 index 000000000..a8bef47ce --- /dev/null +++ b/pkg/core/ssl-applicator/acme-dns01/providers/dnsmadeeasy/dnsmadeeasy.go @@ -0,0 +1,40 @@ +package dnsmadeeasy + +import ( + "errors" + "time" + + "github.com/go-acme/lego/v4/providers/dns/dnsmadeeasy" + + "github.com/certimate-go/certimate/pkg/core" +) + +type ChallengeProviderConfig struct { + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` + DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` + DnsTTL int32 `json:"dnsTTL,omitempty"` +} + +func NewChallengeProvider(config *ChallengeProviderConfig) (core.ACMEChallenger, error) { + if config == nil { + return nil, errors.New("the configuration of the acme challenge provider is nil") + } + + providerConfig := dnsmadeeasy.NewDefaultConfig() + providerConfig.APIKey = config.ApiKey + providerConfig.APISecret = config.ApiSecret + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := dnsmadeeasy.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/dnsmadeeasy.png b/ui/public/imgs/providers/dnsmadeeasy.png new file mode 100644 index 000000000..b7f15edb1 Binary files /dev/null and b/ui/public/imgs/providers/dnsmadeeasy.png differ diff --git a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx index 7afcb7fb1..0309e4f4c 100644 --- a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx +++ b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx @@ -32,6 +32,7 @@ import AccessConfigFieldsProviderDigitalOcean from "./AccessConfigFieldsProvider import AccessConfigFieldsProviderDingTalkBot from "./AccessConfigFieldsProviderDingTalkBot"; import AccessConfigFieldsProviderDiscordBot from "./AccessConfigFieldsProviderDiscordBot"; import AccessConfigFieldsProviderDNSLA from "./AccessConfigFieldsProviderDNSLA"; +import AccessConfigFieldsProviderDNSMadeEasy from "./AccessConfigFieldsProviderDNSMadeEasy"; import AccessConfigFieldsProviderDogeCloud from "./AccessConfigFieldsProviderDogeCloud"; import AccessConfigFieldsProviderDuckDNS from "./AccessConfigFieldsProviderDuckDNS"; import AccessConfigFieldsProviderDynv6 from "./AccessConfigFieldsProviderDynv6"; @@ -125,6 +126,7 @@ const providerComponentMap: Partial { + const { i18n, t } = useTranslation(); + + const { parentNamePath } = useFormNestedFieldsContext(); + const formSchema = z.object({ + [parentNamePath]: getSchema({ i18n }), + }); + const formRule = createSchemaFieldRule(formSchema); + const initialValues = getInitialValues(); + + return ( + <> + } + > + + + + } + > + + + + ); +}; + +const getInitialValues = (): Nullish>> => { + return { + apiKey: "", + apiSecret: "", + }; +}; + +const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType }) => { + const { t } = i18n; + + return z.object({ + apiKey: z.string().nonempty(t("access.form.dnsmadeeasy_api_key.placeholder")), + apiSecret: z.string().nonempty(t("access.form.dnsmadeeasy_api_secret.placeholder")), + }); +}; + +const _default = Object.assign(AccessConfigFormFieldsProviderDNSMadeEasy, { + getInitialValues, + getSchema, +}); + +export default _default; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 5a3a38623..b068f13c8 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -183,6 +183,7 @@ export const accessProvidersMap: Maphttps://www.dns.la/docs/ApiDoc", + "access.form.dnsmadeeasy_api_key.label": "DNS Made Easy API key", + "access.form.dnsmadeeasy_api_key.placeholder": "Please enter DNS Made Easy API key", + "access.form.dnsmadeeasy_api_key.tooltip": "For more information, see https://api-docs.dnsmadeeasy.com/#Authentication", + "access.form.dnsmadeeasy_api_secret.label": "DNS Made Easy API secret", + "access.form.dnsmadeeasy_api_secret.placeholder": "Please enter DNS Made Easy API secret", + "access.form.dnsmadeeasy_api_secret.tooltip": "For more information, see https://api-docs.dnsmadeeasy.com/#Authentication", "access.form.dogecloud_access_key.label": "Doge Cloud AccessKey", "access.form.dogecloud_access_key.placeholder": "Please enter Doge Cloud AccessKey", "access.form.dogecloud_access_key.tooltip": "For more information, see https://console.dogecloud.com/", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index ca95e968b..babc6115f 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -217,6 +217,12 @@ "access.form.discordbot_channel_id.placeholder": "请输入默认的 Discord 频道 ID", "access.form.discordbot_channel_id.help": "提示:可在工作流中覆盖此设置。", "access.form.discordbot_channel_id.tooltip": "这是什么?请参阅 https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID", + "access.form.dnsmadeeasy_api_key.label": "DNS Made Easy API Key", + "access.form.dnsmadeeasy_api_key.placeholder": "请输入 DNS Made Easy API Key", + "access.form.dnsmadeeasy_api_key.tooltip": "这是什么?请参阅 https://api-docs.dnsmadeeasy.com/#Authentication", + "access.form.dnsmadeeasy_api_secret.label": "DNS Made Easy API Secret", + "access.form.dnsmadeeasy_api_secret.placeholder": "请输入 DNS Made Easy API Secret", + "access.form.dnsmadeeasy_api_secret.tooltip": "这是什么?请参阅 https://api-docs.dnsmadeeasy.com/#Authentication", "access.form.dnsla_api_id.label": "DNS.LA API ID", "access.form.dnsla_api_id.placeholder": "请输入 DNS.LA API ID", "access.form.dnsla_api_id.tooltip": "这是什么?请参阅 https://www.dns.la/docs/ApiDoc",