From 7210f638840f4f6896276844e91c9991f283bd80 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Tue, 3 Jun 2025 15:54:13 +0800 Subject: [PATCH] feat: new acme dns-01 provider: constellix --- internal/applicant/providers.go | 17 +++++ internal/domain/access.go | 5 ++ internal/domain/provider.go | 2 + .../lego-providers/constellix/constellix.go | 38 ++++++++++ ui/public/imgs/providers/constellix.png | Bin 0 -> 8081 bytes ui/src/components/access/AccessForm.tsx | 3 + .../access/AccessFormConstellixConfig.tsx | 67 ++++++++++++++++++ ui/src/domain/access.ts | 6 ++ ui/src/domain/provider.ts | 4 ++ ui/src/i18n/locales/en/nls.access.json | 6 ++ ui/src/i18n/locales/en/nls.provider.json | 1 + ui/src/i18n/locales/zh/nls.access.json | 6 ++ ui/src/i18n/locales/zh/nls.provider.json | 1 + 13 files changed, 156 insertions(+) create mode 100644 internal/pkg/core/applicant/acme-dns-01/lego-providers/constellix/constellix.go create mode 100644 ui/public/imgs/providers/constellix.png create mode 100644 ui/src/components/access/AccessFormConstellixConfig.tsx diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go index 98561daf..ba4fadef 100644 --- a/internal/applicant/providers.go +++ b/internal/applicant/providers.go @@ -16,6 +16,7 @@ import ( pCloudflare "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare" pClouDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns" pCMCCCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud" + pConstellix "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/constellix" pDeSEC "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/desec" pDigitalOcean "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/digitalocean" pDNSLA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla" @@ -234,6 +235,22 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi return applicant, err } + case domain.ACMEDns01ProviderTypeConstellix: + { + access := domain.AccessConfigForConstellix{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pConstellix.NewChallengeProvider(&pConstellix.ChallengeProviderConfig{ + ApiKey: access.ApiKey, + SecretKey: access.SecretKey, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + case domain.ACMEDns01ProviderTypeDeSEC: { access := domain.AccessConfigForDeSEC{} diff --git a/internal/domain/access.go b/internal/domain/access.go index 0ed9f0ee..274f2fd0 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -109,6 +109,11 @@ type AccessConfigForCMCCCloud struct { AccessKeySecret string `json:"accessKeySecret"` } +type AccessConfigForConstellix struct { + ApiKey string `json:"apiKey"` + SecretKey string `json:"secretKey"` +} + type AccessConfigForDeSEC struct { Token string `json:"token"` } diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 55f8b2af..dd9663f2 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -28,6 +28,7 @@ const ( AccessProviderTypeCloudflare = AccessProviderType("cloudflare") AccessProviderTypeClouDNS = AccessProviderType("cloudns") AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud") + AccessProviderTypeConstellix = AccessProviderType("constellix") AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 天翼云(预留) AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 联通云(预留) AccessProviderTypeDeSEC = AccessProviderType("desec") @@ -131,6 +132,7 @@ const ( ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare) ACMEDns01ProviderTypeClouDNS = ACMEDns01ProviderType(AccessProviderTypeClouDNS) ACMEDns01ProviderTypeCMCCCloud = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud) + ACMEDns01ProviderTypeConstellix = ACMEDns01ProviderType(AccessProviderTypeConstellix) ACMEDns01ProviderTypeDeSEC = ACMEDns01ProviderType(AccessProviderTypeDeSEC) ACMEDns01ProviderTypeDigitalOcean = ACMEDns01ProviderType(AccessProviderTypeDigitalOcean) ACMEDns01ProviderTypeDNSLA = ACMEDns01ProviderType(AccessProviderTypeDNSLA) diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/constellix/constellix.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/constellix/constellix.go new file mode 100644 index 00000000..12e7d615 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/constellix/constellix.go @@ -0,0 +1,38 @@ +package cloudns + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/providers/dns/constellix" +) + +type ChallengeProviderConfig struct { + ApiKey string `json:"apiKey"` + SecretKey string `json:"secretKey"` + 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 := constellix.NewDefaultConfig() + providerConfig.APIKey = config.ApiKey + providerConfig.SecretKey = config.SecretKey + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := constellix.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/constellix.png b/ui/public/imgs/providers/constellix.png new file mode 100644 index 0000000000000000000000000000000000000000..71a8722a33e152add513cbb918b437cbb25c4f5f GIT binary patch literal 8081 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 className, return ; case ACCESS_PROVIDERS.CMCCCLOUD: return ; + case ACCESS_PROVIDERS.CONSTELLIX: + return ; case ACCESS_PROVIDERS.DESEC: return ; case ACCESS_PROVIDERS.DIGITALOCEAN: diff --git a/ui/src/components/access/AccessFormConstellixConfig.tsx b/ui/src/components/access/AccessFormConstellixConfig.tsx new file mode 100644 index 00000000..5966828a --- /dev/null +++ b/ui/src/components/access/AccessFormConstellixConfig.tsx @@ -0,0 +1,67 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; +import { type AccessConfigForConstellix } from "@/domain/access"; + +type AccessFormConstellixConfigFieldValues = Nullish; + +export type AccessFormConstellixConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormConstellixConfigFieldValues; + onValuesChange?: (values: AccessFormConstellixConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormConstellixConfigFieldValues => { + return { + apiKey: "", + secretKey: "", + }; +}; + +const AccessFormConstellixConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange: onValuesChange }: AccessFormConstellixConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiKey: z.string().trim().nonempty(t("access.form.constellix_api_key.placeholder")), + secretKey: z.string().trim().nonempty(t("access.form.constellix_secret_key.placeholder")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormConstellixConfig; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index fe9f12e3..6da7c90b 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -23,6 +23,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForCloudflare | AccessConfigForClouDNS | AccessConfigForCMCCCloud + | AccessConfigForConstellix | AccessConfigForDeSEC | AccessConfigForDigitalOcean | AccessConfigForDingTalkBot @@ -172,6 +173,11 @@ export type AccessConfigForCMCCCloud = { accessKeySecret: string; }; +export type AccessConfigForConstellix = { + apiKey: string; + secretKey: string; +}; + export type AccessConfigForDeSEC = { token: string; }; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index bb550691..5bd1439b 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -22,6 +22,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ CLOUDFLARE: "cloudflare", CLOUDNS: "cloudns", CMCCCLOUD: "cmcccloud", + CONSTELLIX: "constellix", DESEC: "desec", DIGITALOCEAN: "digitalocean", DINGTALKBOT: "dingtalkbot", @@ -144,6 +145,7 @@ export const accessProvidersMap: Maphttps://ecloud.10086.cn/op-help-center/doc/article/49739", + "access.form.constellix_api_key.label": "Constellix API key", + "access.form.constellix_api_key.placeholder": "Please enter Constellix API key", + "access.form.constellix_api_key.tooltip": "For more information, see https://support.constellix.com/hc/en-us/articles/34574197390491-How-to-Generate-an-API-Key", + "access.form.constellix_secret_key.label": "Constellix API secret key", + "access.form.constellix_secret_key.placeholder": "Please enter Constellix API secret key", + "access.form.constellix_secret_key.tooltip": "For more information, see https://support.constellix.com/hc/en-us/articles/34574197390491-How-to-Generate-an-API-Key", "access.form.desec_token.label": "deSEC token", "access.form.desec_token.placeholder": "Please enter deSEC token", "access.form.desec_token.tooltip": "For more information, see https://desec.readthedocs.io/en/latest/auth/tokens.html", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 9e59d9d0..72f5e487 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -55,6 +55,7 @@ "provider.cloudflare": "Cloudflare", "provider.cloudns": "ClouDNS", "provider.cmcccloud": "China Mobile Cloud (ECloud)", + "provider.constellix": "Constellix", "provider.ctcccloud": "China Telecom Cloud (State Cloud)", "provider.cucccloud": "China Unicom Cloud", "provider.desec": "deSEC", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index 66563f32..8af85792 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -146,6 +146,12 @@ "access.form.cmcccloud_access_key_secret.label": "移动云 AccessKeySecret", "access.form.cmcccloud_access_key_secret.placeholder": "请输入移动云 AccessKeySecret", "access.form.cmcccloud_access_key_secret.tooltip": "这是什么?请参阅 https://ecloud.10086.cn/op-help-center/doc/article/49739", + "access.form.constellix_api_key.label": "Constellix API Key", + "access.form.constellix_api_key.placeholder": "请输入 Constellix API Key", + "access.form.constellix_api_key.tooltip": "这是什么?请参阅 https://support.constellix.com/hc/en-us/articles/34574197390491-How-to-Generate-an-API-Key", + "access.form.constellix_secret_key.label": "Constellix Secret Key", + "access.form.constellix_secret_key.placeholder": "请输入 Constellix Secret Key", + "access.form.constellix_secret_key.tooltip": "这是什么?请参阅 https://support.constellix.com/hc/en-us/articles/34574197390491-How-to-Generate-an-API-Key", "access.form.desec_token.label": "deSEC Token", "access.form.desec_token.placeholder": "请输入 deSEC Token", "access.form.desec_token.tooltip": "这是什么?请参阅 https://desec.readthedocs.io/en/latest/auth/tokens.html", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 27aa8d0e..79bba686 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -55,6 +55,7 @@ "provider.cloudflare": "Cloudflare", "provider.cloudns": "ClouDNS", "provider.cmcccloud": "移动云", + "provider.constellix": "Constellix", "provider.ctcccloud": "联通云", "provider.cucccloud": "天翼云", "provider.desec": "deSEC",