diff --git a/internal/certapply/applicators/sp_infomaniak.go b/internal/certapply/applicators/sp_infomaniak.go new file mode 100644 index 000000000..fb59e1976 --- /dev/null +++ b/internal/certapply/applicators/sp_infomaniak.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/infomaniak" + xmaps "github.com/certimate-go/certimate/pkg/utils/maps" +) + +func init() { + if err := ACMEDns01Registries.Register(domain.ACMEDns01ProviderTypeInfomaniak, func(options *ProviderFactoryOptions) (challenge.Provider, error) { + credentials := domain.AccessConfigForInfomaniak{} + if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + provider, err := infomaniak.NewChallengeProvider(&infomaniak.ChallengeProviderConfig{ + AccessToken: credentials.AccessToken, + 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 29f5b6272..20207c419 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -274,6 +274,10 @@ type AccessConfigForHuaweiCloud struct { EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"` } +type AccessConfigForInfomaniak struct { + AccessToken string `json:"accessToken"` +} + type AccessConfigForIONOS struct { ApiKeyPublicPrefix string `json:"apiKeyPublicPrefix"` ApiKeySecret string `json:"apiKeySecret"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 8bab76c08..aa1c63556 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -60,7 +60,7 @@ const ( AccessProviderTypeHostingde = AccessProviderType("hostingde") AccessProviderTypeHostinger = AccessProviderType("hostinger") AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud") - AccessProviderTypeInfomaniak = AccessProviderType("infomaniak") // Infomaniak(预留) + AccessProviderTypeInfomaniak = AccessProviderType("infomaniak") AccessProviderTypeIONOS = AccessProviderType("ionos") AccessProviderTypeJDCloud = AccessProviderType("jdcloud") AccessProviderTypeKong = AccessProviderType("kong") diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/infomaniak/infomaniak.go b/pkg/core/ssl-applicator/acme-dns01/providers/infomaniak/infomaniak.go new file mode 100644 index 000000000..8ae9c5cb9 --- /dev/null +++ b/pkg/core/ssl-applicator/acme-dns01/providers/infomaniak/infomaniak.go @@ -0,0 +1,38 @@ +package infomaniak + +import ( + "errors" + "time" + + "github.com/go-acme/lego/v4/providers/dns/infomaniak" + + "github.com/certimate-go/certimate/pkg/core" +) + +type ChallengeProviderConfig struct { + AccessToken string `json:"accessToken"` + 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 := infomaniak.NewDefaultConfig() + providerConfig.AccessToken = config.AccessToken + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := infomaniak.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/infomaniak.png b/ui/public/imgs/providers/infomaniak.png new file mode 100644 index 000000000..ff9f8931d Binary files /dev/null and b/ui/public/imgs/providers/infomaniak.png differ diff --git a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx index 459286478..2d59bf3a0 100644 --- a/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx +++ b/ui/src/components/access/forms/AccessConfigFieldsProvider.tsx @@ -50,6 +50,7 @@ import AccessConfigFieldsProviderHetzner from "./AccessConfigFieldsProviderHetzn import AccessConfigFieldsProviderHostingde from "./AccessConfigFieldsProviderHostingde"; import AccessConfigFieldsProviderHostinger from "./AccessConfigFieldsProviderHostinger"; import AccessConfigFieldsProviderHuaweiCloud from "./AccessConfigFieldsProviderHuaweiCloud"; +import AccessConfigFieldsProviderInfomaniak from "./AccessConfigFieldsProviderInfomaniak"; import AccessConfigFieldsProviderIONOS from "./AccessConfigFieldsProviderIONOS"; import AccessConfigFieldsProviderJDCloud from "./AccessConfigFieldsProviderJDCloud"; import AccessConfigFieldsProviderKong from "./AccessConfigFieldsProviderKong"; @@ -151,6 +152,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 { + accessToken: "", + }; +}; + +const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType }) => { + const { t } = i18n; + + return z.object({ + accessToken: z.string().nonempty(t("access.form.infomaniak_access_token.placeholder")), + }); +}; + +const _default = Object.assign(AccessConfigFormFieldsProviderInfomaniak, { + getInitialValues, + getSchema, +}); + +export default _default; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 979436964..ddc9904f2 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -193,6 +193,7 @@ export const accessProvidersMap: Maphttps://support.huaweicloud.com/intl/en-us/usermanual-em/em_03_0000.html", + "access.form.infomaniak_access_token.label": "Infomaniak access token", + "access.form.infomaniak_access_token.placeholder": "Please enter Infomaniak access token", + "access.form.infomaniak_access_token.tooltip": "For more information, see https://manager.infomaniak.com/v3/infomaniak-api", "access.form.ionos_api_key_public_prefix.label": "IONOS API key public prefix", "access.form.ionos_api_key_public_prefix.placeholder": "Please enter IONOS API key public prefix", "access.form.ionos_api_key_public_prefix.tooltip": "For more information, see https://developer.hosting.ionos.com/docs/getstarted", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index ffb82b0ba..37f8eb381 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -322,6 +322,9 @@ "access.form.huaweicloud_enterprise_project_id.label": "华为云企业项目 ID(可选)", "access.form.huaweicloud_enterprise_project_id.placeholder": "请输入华为云企业项目 ID", "access.form.huaweicloud_enterprise_project_id.tooltip": "这是什么?请参阅 https://support.huaweicloud.com/usermanual-em/zh-cn_topic_0126101490.html", + "access.form.infomaniak_access_token.label": "Infomaniak AccessToken", + "access.form.infomaniak_access_token.placeholder": "请输入 Infomaniak AccessToken", + "access.form.infomaniak_access_token.tooltip": "这是什么?请参阅 https://manager.infomaniak.com/v3/infomaniak-api", "access.form.ionos_api_key_public_prefix.label": "IONOS API Key Public Prefix", "access.form.ionos_api_key_public_prefix.placeholder": "请输入 IONOS API Key Public Prefix", "access.form.ionos_api_key_public_prefix.tooltip": "这是什么?请参阅 https://developer.hosting.ionos.com/docs/getstarted",