From 312c27dd2ee4045e683610dacc4fd4ef0455b762 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 24 Jun 2026 17:31:01 +0800 Subject: [PATCH] feat(provider): new acme dns-01 provider: simplycom --- internal/certacme/certifiers/sp_simplycom.go | 27 ++++++++ internal/domain/access.go | 5 ++ internal/domain/provider.go | 2 + .../challengers/dns01/simplycom/simplycom.go | 40 +++++++++++ ui/public/imgs/providers/simplycom.png | Bin 0 -> 2869 bytes .../forms/AccessConfigFieldsProvider.tsx | 2 + .../AccessConfigFieldsProviderSimplyCom.tsx | 64 ++++++++++++++++++ ui/src/domain/provider.ts | 4 ++ ui/src/i18n/resources/en/nls.access.json | 10 +++ ui/src/i18n/resources/en/nls.provider.json | 1 + ui/src/i18n/resources/zh/nls.access.json | 10 +++ ui/src/i18n/resources/zh/nls.provider.json | 1 + 12 files changed, 166 insertions(+) create mode 100644 internal/certacme/certifiers/sp_simplycom.go create mode 100644 pkg/core/certifier/challengers/dns01/simplycom/simplycom.go create mode 100644 ui/public/imgs/providers/simplycom.png create mode 100644 ui/src/components/access/forms/AccessConfigFieldsProviderSimplyCom.tsx diff --git a/internal/certacme/certifiers/sp_simplycom.go b/internal/certacme/certifiers/sp_simplycom.go new file mode 100644 index 000000000..b693c41bc --- /dev/null +++ b/internal/certacme/certifiers/sp_simplycom.go @@ -0,0 +1,27 @@ +package certifiers + +import ( + "fmt" + + "github.com/certimate-go/certimate/internal/domain" + "github.com/certimate-go/certimate/pkg/core" + chlgimpl "github.com/certimate-go/certimate/pkg/core/certifier/challengers/dns01/simplycom" + xmaps "github.com/certimate-go/certimate/pkg/utils/maps" +) + +func init() { + ACMEDns01Registries.MustRegister(domain.ACMEDns01ProviderTypeSimplyCom, func(options *ProviderFactoryOptions) (core.ACMEChallenger, error) { + credentials := domain.AccessConfigForSimplyCom{} + if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + provider, err := chlgimpl.NewChallenger(&chlgimpl.ChallengerConfig{ + AccountNumber: credentials.AccountNumber, + ApiKey: credentials.ApiKey, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return provider, err + }) +} diff --git a/internal/domain/access.go b/internal/domain/access.go index d21c820ae..0b4011bfb 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -546,6 +546,11 @@ type AccessConfigForSamWAF struct { AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } +type AccessConfigForSimplyCom struct { + AccountNumber string `json:"accountNumber"` + ApiKey string `json:"apiKey"` +} + type AccessConfigForSlackBot struct { BotToken string `json:"botToken"` ChannelId string `json:"channelId,omitempty"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 603d2f8ec..df14a7db5 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -114,6 +114,7 @@ const ( AccessProviderTypeSafeLine = AccessProviderType("safeline") AccessProviderTypeSamWAF = AccessProviderType("samwaf") AccessProviderTypeSectigo = AccessProviderType("sectigo") + AccessProviderTypeSimplyCom = AccessProviderType("simplycom") AccessProviderTypeSlackBot = AccessProviderType("slackbot") AccessProviderTypeSpaceship = AccessProviderType("spaceship") AccessProviderTypeSSH = AccessProviderType("ssh") @@ -256,6 +257,7 @@ const ( ACMEDns01ProviderTypeRegru = ACMEDns01ProviderType(AccessProviderTypeRegru) ACMEDns01ProviderTypeRFC2136 = ACMEDns01ProviderType(AccessProviderTypeRFC2136) ACMEDns01ProviderTypeRuCenter = ACMEDns01ProviderType(AccessProviderTypeRuCenter) + ACMEDns01ProviderTypeSimplyCom = ACMEDns01ProviderType(AccessProviderTypeSimplyCom) ACMEDns01ProviderTypeSpaceship = ACMEDns01ProviderType(AccessProviderTypeSpaceship) ACMEDns01ProviderTypeTechnitiumDNS = ACMEDns01ProviderType(AccessProviderTypeTechnitiumDNS) ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS] diff --git a/pkg/core/certifier/challengers/dns01/simplycom/simplycom.go b/pkg/core/certifier/challengers/dns01/simplycom/simplycom.go new file mode 100644 index 000000000..92ac9bfaf --- /dev/null +++ b/pkg/core/certifier/challengers/dns01/simplycom/simplycom.go @@ -0,0 +1,40 @@ +package gandinet + +import ( + "fmt" + "time" + + "github.com/go-acme/lego/v5/providers/dns/simply" + + "github.com/certimate-go/certimate/pkg/core" +) + +type ChallengerConfig struct { + AccountNumber string `json:"accountNumber"` + ApiKey string `json:"apiKey"` + DnsPropagationTimeout int `json:"dnsPropagationTimeout,omitempty"` + DnsTTL int `json:"dnsTTL,omitempty"` +} + +func NewChallenger(config *ChallengerConfig) (core.ACMEChallenger, error) { + if config == nil { + return nil, fmt.Errorf("the configuration of the acme challenge provider is nil") + } + + providerConfig := simply.NewDefaultConfig() + providerConfig.AccountName = config.AccountNumber + providerConfig.APIKey = config.ApiKey + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = config.DnsTTL + } + + provider, err := simply.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/simplycom.png b/ui/public/imgs/providers/simplycom.png new file mode 100644 index 0000000000000000000000000000000000000000..fca2b21e6b30009d599a3f9f87c12ea16b583b35 GIT binary patch literal 2869 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 e^kX4WK#qUy@z^t7jR$WP!1jWJ^=E|Flm7v { + 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 { + accountNumber: "", + apiKey: "", + }; +}; + +const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType }) => { + const { t: _ } = i18n; + + return z.object({ + accountNumber: z.string().nonempty(), + apiKey: z.string().nonempty(), + }); +}; + +const _default = Object.assign(AccessConfigFormFieldsProviderSimplyCom, { + getInitialValues, + getSchema, +}); + +export default _default; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 155b66a31..0e75c8ea3 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -114,6 +114,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ SAFELINE: "safeline", SAMWAF: "samwaf", SECTIGO: "sectigo", + SIMPLYCOM: "simplycom", SLACKBOT: "slackbot", SPACESHIP: "spaceship", SSH: "ssh", @@ -251,6 +252,7 @@ export const accessProvidersMap: Maphttps://www.sectigo.com/enterprise-solutions/certificate-manager/integrations-acme" }, + "simplycom_account_number": { + "label": "Simply.com account number", + "placeholder": "Please enter Simply.com account number", + "tooltip": "For more information, see https://www.simply.com/en/docs/api/" + }, + "simplycom_api_key": { + "label": "Simply.com API key", + "placeholder": "Please enter Simply.com API key", + "tooltip": "For more information, see https://www.simply.com/en/docs/api/" + }, "slackbot_token": { "label": "Slack bot token", "placeholder": "Please enter Slack bot token", diff --git a/ui/src/i18n/resources/en/nls.provider.json b/ui/src/i18n/resources/en/nls.provider.json index dde11668f..445499f3c 100644 --- a/ui/src/i18n/resources/en/nls.provider.json +++ b/ui/src/i18n/resources/en/nls.provider.json @@ -230,6 +230,7 @@ "safeline": "SafeLine", "samwaf": "SamWAF", "sectigo": "Sectigo", + "simplycom": "Simply.com", "slackbot": "Slack Bot", "spaceship": "Spaceship", "ssh": "Remote host (SSH)", diff --git a/ui/src/i18n/resources/zh/nls.access.json b/ui/src/i18n/resources/zh/nls.access.json index b19723b0c..f3cd1718d 100644 --- a/ui/src/i18n/resources/zh/nls.access.json +++ b/ui/src/i18n/resources/zh/nls.access.json @@ -1237,6 +1237,16 @@ "sectigo_eab": { "guide": "点击下方链接了解如何获取 Sectigo EAB:
https://www.sectigo.com/enterprise-solutions/certificate-manager/integrations-acme" }, + "simplycom_account_number": { + "label": "Simply.com 账号", + "placeholder": "请输入 Simply.com 账号", + "tooltip": "这是什么?请参阅 https://www.simply.com/en/docs/api/" + }, + "simplycom_api_key": { + "label": "Simply.com API Key", + "placeholder": "请输入 Simply.com API Key", + "tooltip": "这是什么?请参阅 https://www.simply.com/en/docs/api/" + }, "slackbot_token": { "label": "Slack 机器人 Token", "placeholder": "请输入 Slack 机器人 Token", diff --git a/ui/src/i18n/resources/zh/nls.provider.json b/ui/src/i18n/resources/zh/nls.provider.json index 593626227..96abf88b2 100644 --- a/ui/src/i18n/resources/zh/nls.provider.json +++ b/ui/src/i18n/resources/zh/nls.provider.json @@ -230,6 +230,7 @@ "safeline": "雷池", "samwaf": "SamWAF", "sectigo": "Sectigo", + "simplycom": "Simply.com", "slackbot": "Slack 机器人", "spaceship": "Spaceship", "ssh": "远程主机(SSH)",