diff --git a/internal/certapply/applicators/sp_dynu.go b/internal/certapply/applicators/sp_dynu.go new file mode 100644 index 00000000..9a5a1af5 --- /dev/null +++ b/internal/certapply/applicators/sp_dynu.go @@ -0,0 +1,29 @@ +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/dynu" + xmaps "github.com/certimate-go/certimate/pkg/utils/maps" +) + +func init() { + if err := ACMEDns01Registries.Register(domain.ACMEDns01ProviderTypeDynu, func(options *ProviderFactoryOptions) (challenge.Provider, error) { + credentials := domain.AccessConfigForDynu{} + if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + provider, err := dynu.NewChallengeProvider(&dynu.ChallengeProviderConfig{ + ApiKey: credentials.ApiKey, + 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 43d6d952..29f5b627 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -190,6 +190,10 @@ type AccessConfigForDuckDNS struct { Token string `json:"token"` } +type AccessConfigForDynu struct { + ApiKey string `json:"apiKey"` +} + type AccessConfigForDynv6 struct { HttpToken string `json:"httpToken"` } diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 0076e296..8bab76c0 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -44,7 +44,7 @@ const ( AccessProviderTypeDNSMadeEasy = AccessProviderType("dnsmadeeasy") AccessProviderTypeDogeCloud = AccessProviderType("dogecloud") AccessProviderTypeDuckDNS = AccessProviderType("duckdns") - AccessProviderTypeDynu = AccessProviderType("dynu") // Dynu(预留) + AccessProviderTypeDynu = AccessProviderType("dynu") AccessProviderTypeDynv6 = AccessProviderType("dynv6") AccessProviderTypeEmail = AccessProviderType("email") AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留) diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/dynu/dynu.go b/pkg/core/ssl-applicator/acme-dns01/providers/dynu/dynu.go new file mode 100644 index 00000000..3bdfa41f --- /dev/null +++ b/pkg/core/ssl-applicator/acme-dns01/providers/dynu/dynu.go @@ -0,0 +1,38 @@ +package dynu + +import ( + "errors" + "time" + + "github.com/go-acme/lego/v4/providers/dns/dynu" + + "github.com/certimate-go/certimate/pkg/core" +) + +type ChallengeProviderConfig struct { + ApiKey string `json:"apiKey"` + 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 := dynu.NewDefaultConfig() + providerConfig.APIKey = config.ApiKey + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := dynu.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/dynu.png b/ui/public/imgs/providers/dynu.png new file mode 100644 index 00000000..8b44ea1b Binary files /dev/null and b/ui/public/imgs/providers/dynu.png differ diff --git a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx index 0309e4f4..45928647 100644 --- a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx +++ b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx @@ -35,6 +35,7 @@ import AccessConfigFieldsProviderDNSLA from "./AccessConfigFieldsProviderDNSLA"; import AccessConfigFieldsProviderDNSMadeEasy from "./AccessConfigFieldsProviderDNSMadeEasy"; import AccessConfigFieldsProviderDogeCloud from "./AccessConfigFieldsProviderDogeCloud"; import AccessConfigFieldsProviderDuckDNS from "./AccessConfigFieldsProviderDuckDNS"; +import AccessConfigFieldsProviderDynu from "./AccessConfigFieldsProviderDynu"; import AccessConfigFieldsProviderDynv6 from "./AccessConfigFieldsProviderDynv6"; import AccessConfigFieldsProviderEmail from "./AccessConfigFieldsProviderEmail"; import AccessConfigFieldsProviderFlexCDN from "./AccessConfigFieldsProviderFlexCDN"; @@ -129,6 +130,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: "", + }; +}; + +const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType }) => { + const { t } = i18n; + + return z.object({ + apiKey: z.string().nonempty(t("access.form.dynu_api_key.placeholder")), + }); +}; + +const _default = Object.assign(AccessConfigFormFieldsProviderDynu, { + getInitialValues, + getSchema, +}); + +export default _default; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index b068f13c..97943696 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -185,6 +185,7 @@ export const accessProvidersMap: Maphttps://www.duckdns.org/spec.jsp", + "access.form.dynu_api_key.label": "Dynu API key", + "access.form.dynu_api_key.placeholder": "Please enter Dynu API key", + "access.form.dynu_api_key.tooltip": "For more information, see https://www.dynu.com/Support/API#Authentication", "access.form.dynv6_http_token.label": "dynv6 HTTP token", "access.form.dynv6_http_token.placeholder": "Please enter dynv6 HTTP token", "access.form.dynv6_http_token.tooltip": "For more information, see https://dynv6.com/keys", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index babc6115..ffb82b0b 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -238,6 +238,9 @@ "access.form.duckdns_token.label": "DuckDNS Token", "access.form.duckdns_token.placeholder": "请输入 DuckDNS Token", "access.form.duckdns_token.tooltip": "这是什么?请参阅 https://www.duckdns.org/spec.jsp", + "access.form.dynu_api_key.label": "Dynu API Key", + "access.form.dynu_api_key.placeholder": "请输入 Dynu API Key", + "access.form.dynu_api_key.tooltip": "这是什么?请参阅 https://www.dynu.com/Support/API#Authentication", "access.form.dynv6_http_token.label": "dynv6 HTTP Token", "access.form.dynv6_http_token.placeholder": "请输入 dynv6 HTTP Token", "access.form.dynv6_http_token.tooltip": "这是什么?请参阅 https://dynv6.com/keys",