From 7a138506151a1a17cd0707adcdec3366129e64ed Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 29 May 2026 23:42:56 +0800 Subject: [PATCH] feat(provider): new acme dns-01 provider: beget --- internal/certacme/certifiers/sp_beget.go | 27 +++++++++ internal/domain/access.go | 5 ++ internal/domain/provider.go | 2 + .../challengers/dns01/beget/beget.go | 40 +++++++++++++ ui/public/imgs/providers/beget.svg | 1 + .../forms/AccessConfigFieldsProvider.tsx | 2 + .../forms/AccessConfigFieldsProviderBeget.tsx | 58 +++++++++++++++++++ ui/src/domain/provider.ts | 4 ++ ui/src/i18n/resources/en/nls.access.json | 9 +++ ui/src/i18n/resources/en/nls.provider.json | 1 + ui/src/i18n/resources/zh/nls.access.json | 9 +++ ui/src/i18n/resources/zh/nls.provider.json | 1 + 12 files changed, 159 insertions(+) create mode 100644 internal/certacme/certifiers/sp_beget.go create mode 100644 pkg/core/certifier/challengers/dns01/beget/beget.go create mode 100644 ui/public/imgs/providers/beget.svg create mode 100644 ui/src/components/access/forms/AccessConfigFieldsProviderBeget.tsx diff --git a/internal/certacme/certifiers/sp_beget.go b/internal/certacme/certifiers/sp_beget.go new file mode 100644 index 000000000..1d0c09e1f --- /dev/null +++ b/internal/certacme/certifiers/sp_beget.go @@ -0,0 +1,27 @@ +package certifiers + +import ( + "fmt" + + "github.com/certimate-go/certimate/internal/domain" + "github.com/certimate-go/certimate/pkg/core" + "github.com/certimate-go/certimate/pkg/core/certifier/challengers/dns01/beget" + xmaps "github.com/certimate-go/certimate/pkg/utils/maps" +) + +func init() { + ACMEDns01Registries.MustRegister(domain.ACMEDns01ProviderTypeBeget, func(options *ProviderFactoryOptions) (core.ACMEChallenger, error) { + credentials := domain.AccessConfigForBeget{} + if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + provider, err := beget.NewChallenger(&beget.ChallengerConfig{ + Username: credentials.Username, + ApiPassword: credentials.ApiPassword, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return provider, err + }) +} diff --git a/internal/domain/access.go b/internal/domain/access.go index 0c6e1f4f2..3fabf6cc9 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -120,6 +120,11 @@ type AccessConfigForBaotaWAF struct { AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"` } +type AccessConfigForBeget struct { + Username string `json:"username"` + ApiPassword string `json:"apiPassword"` +} + type AccessConfigForBookMyName struct { Username string `json:"username"` Password string `json:"password"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index d66ddc25b..d12487008 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -31,6 +31,7 @@ const ( AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel") AccessProviderTypeBaotaPanelGo = AccessProviderType("baotapanelgo") AccessProviderTypeBaotaWAF = AccessProviderType("baotawaf") + AccessProviderTypeBeget = AccessProviderType("beget") AccessProviderTypeBookMyName = AccessProviderType("bookmyname") AccessProviderTypeBunny = AccessProviderType("bunny") AccessProviderTypeBytePlus = AccessProviderType("byteplus") @@ -199,6 +200,7 @@ const ( ACMEDns01ProviderTypeAzureDNS = ACMEDns01ProviderType(AccessProviderTypeAzure + "-dns") ACMEDns01ProviderTypeBaiduCloud = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeBaiduCloudDNS] ACMEDns01ProviderTypeBaiduCloudDNS = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud + "-dns") + ACMEDns01ProviderTypeBeget = ACMEDns01ProviderType(AccessProviderTypeBeget) ACMEDns01ProviderTypeBookMyName = ACMEDns01ProviderType(AccessProviderTypeBookMyName) ACMEDns01ProviderTypeBunny = ACMEDns01ProviderType(AccessProviderTypeBunny) ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare) diff --git a/pkg/core/certifier/challengers/dns01/beget/beget.go b/pkg/core/certifier/challengers/dns01/beget/beget.go new file mode 100644 index 000000000..e2e8dcc47 --- /dev/null +++ b/pkg/core/certifier/challengers/dns01/beget/beget.go @@ -0,0 +1,40 @@ +package beget + +import ( + "fmt" + "time" + + "github.com/go-acme/lego/v5/providers/dns/beget" + + "github.com/certimate-go/certimate/pkg/core/certifier" +) + +type ChallengerConfig struct { + Username string `json:"username"` + ApiPassword string `json:"apiPassword"` + DnsPropagationTimeout int `json:"dnsPropagationTimeout,omitempty"` + DnsTTL int `json:"dnsTTL,omitempty"` +} + +func NewChallenger(config *ChallengerConfig) (certifier.ACMEChallenger, error) { + if config == nil { + return nil, fmt.Errorf("the configuration of the acme challenge provider is nil") + } + + providerConfig := beget.NewDefaultConfig() + providerConfig.Username = config.Username + providerConfig.Password = config.ApiPassword + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = config.DnsTTL + } + + provider, err := beget.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/beget.svg b/ui/public/imgs/providers/beget.svg new file mode 100644 index 000000000..da62177f7 --- /dev/null +++ b/ui/public/imgs/providers/beget.svg @@ -0,0 +1 @@ + diff --git a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx index 9da1b8a0c..6c35ae960 100644 --- a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx +++ b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx @@ -20,6 +20,7 @@ import AccessConfigFieldsProviderBaishan from "./AccessConfigFieldsProviderBaish import AccessConfigFieldsProviderBaotaPanel from "./AccessConfigFieldsProviderBaotaPanel"; import AccessConfigFieldsProviderBaotaPanelGo from "./AccessConfigFieldsProviderBaotaPanelGo"; import AccessConfigFieldsProviderBaotaWAF from "./AccessConfigFieldsProviderBaotaWAF"; +import AccessConfigFieldsProviderBeget from "./AccessConfigFieldsProviderBeget"; import AccessConfigFieldsProviderBookMyName from "./AccessConfigFieldsProviderBookMyName"; import AccessConfigFieldsProviderBunny from "./AccessConfigFieldsProviderBunny"; import AccessConfigFieldsProviderBytePlus from "./AccessConfigFieldsProviderBytePlus"; @@ -141,6 +142,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 { + username: "", + apiPassword: "", + }; +}; + +const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType }) => { + const { t: _ } = i18n; + + return z.object({ + username: z.string().nonempty(), + apiPassword: z.string().nonempty(), + }); +}; + +const _default = Object.assign(AccessConfigFieldsProviderBeget, { + getInitialValues, + getSchema, +}); + +export default _default; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 34b0d863d..3204c2335 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -33,6 +33,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ BAOTAPANEL: "baotapanel", BAOTAPANELGO: "baotapanelgo", BAOTAWAF: "baotawaf", + BEGET: "beget", BOOKMYNAME: "bookmyname", BUNNY: "bunny", BYTEPLUS: "byteplus", @@ -213,6 +214,7 @@ export const accessProvidersMap: Maphttps://github.com/aaPanel/aaWAF/blob/main/API.md" }, + "beget_username": { + "label": "Beget username", + "placeholder": "Please enter Beget username" + }, + "beget_api_password": { + "label": "Beget API password", + "placeholder": "Please enter Beget API password", + "tooltip": "For more information, see https://cp.beget.com/settings/security/api" + }, "bookmyname_username": { "label": "BookMyName username", "placeholder": "Please enter BookMyName username" diff --git a/ui/src/i18n/resources/en/nls.provider.json b/ui/src/i18n/resources/en/nls.provider.json index c21ff6a1b..554eb9724 100644 --- a/ui/src/i18n/resources/en/nls.provider.json +++ b/ui/src/i18n/resources/en/nls.provider.json @@ -84,6 +84,7 @@ "baotawaf": "aaWAF (aka BaotaWAF)", "baotawaf_common": "aaWAF", "baotawaf_console": "aaWAF - Console itself", + "beget": "Бегет (Beget)", "bookmyname": "BookMyName", "bunny": "Bunny", "bunny_cdn": "Bunny - CDN (Content Delivery Network)", diff --git a/ui/src/i18n/resources/zh/nls.access.json b/ui/src/i18n/resources/zh/nls.access.json index b6b5ae90d..4c0ff0767 100644 --- a/ui/src/i18n/resources/zh/nls.access.json +++ b/ui/src/i18n/resources/zh/nls.access.json @@ -302,6 +302,15 @@ "placeholder": "请输入堡塔云 WAF 接口密钥", "tooltip": "这是什么?请参阅 https://github.com/aaPanel/aaWAF/blob/main/API.md" }, + "beget_username": { + "label": "Beget 用户名", + "placeholder": "请输入 Beget 用户名" + }, + "beget_api_password": { + "label": "Beget API 密码", + "placeholder": "请输入 Beget API 密码", + "tooltip": "这是什么?请参阅 https://cp.beget.com/settings/security/api" + }, "bookmyname_username": { "label": "BookMyName 用户名", "placeholder": "请输入 BookMyName 用户名" diff --git a/ui/src/i18n/resources/zh/nls.provider.json b/ui/src/i18n/resources/zh/nls.provider.json index 221bfd80f..ff0be3395 100644 --- a/ui/src/i18n/resources/zh/nls.provider.json +++ b/ui/src/i18n/resources/zh/nls.provider.json @@ -84,6 +84,7 @@ "baotawaf": "堡塔云 WAF(又名:aaWAF)", "baotawaf_common": "堡塔云 WAF", "baotawaf_console": "堡塔云 WAF - 面板自身", + "beget": "Бегет(Beget)", "bookmyname": "BookMyName", "bunny": "Bunny", "bunny_cdn": "Bunny - 内容分发网络 CDN",