From cd93a2d72c8c18ba4a393291216bdaffaf85c044 Mon Sep 17 00:00:00 2001 From: Fu Diwei <fudiwei@sina.com> Date: Thu, 15 May 2025 21:48:30 +0800 Subject: [PATCH] feat: new acme dns-01 provider: netcup --- internal/applicant/providers.go | 18 ++++ internal/domain/access.go | 6 ++ internal/domain/provider.go | 2 + .../lego-providers/netcup/netcup.go | 40 +++++++++ ui/public/imgs/providers/netcup.png | Bin 0 -> 4093 bytes ui/src/components/access/AccessForm.tsx | 3 + .../access/AccessFormNetcupConfig.tsx | 79 ++++++++++++++++++ .../node/DeployNodeConfigFormSSHConfig.tsx | 1 - ui/src/domain/access.ts | 7 ++ ui/src/domain/provider.ts | 4 + ui/src/i18n/locales/en/nls.access.json | 9 ++ ui/src/i18n/locales/en/nls.provider.json | 1 + ui/src/i18n/locales/zh/nls.access.json | 9 ++ ui/src/i18n/locales/zh/nls.provider.json | 1 + .../i18n/locales/zh/nls.workflow.nodes.json | 2 +- 15 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 internal/pkg/core/applicant/acme-dns-01/lego-providers/netcup/netcup.go create mode 100644 ui/public/imgs/providers/netcup.png create mode 100644 ui/src/components/access/AccessFormNetcupConfig.tsx diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go index 454f9376..d4d630c4 100644 --- a/internal/applicant/providers.go +++ b/internal/applicant/providers.go @@ -27,6 +27,7 @@ import ( pNamecheap "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap" pNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom" pNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo" + pNetcup "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/netcup" pNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1" pPorkbun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/porkbun" pPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns" @@ -402,6 +403,23 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi return applicant, err } + case domain.ACMEDns01ProviderTypeNetcup: + { + access := domain.AccessConfigForNetcup{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pNetcup.NewChallengeProvider(&pNetcup.ChallengeProviderConfig{ + CustomerNumber: access.CustomerNumber, + ApiKey: access.ApiKey, + ApiPassword: access.ApiPassword, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + case domain.ACMEDns01ProviderTypeNS1: { access := domain.AccessConfigForNS1{} diff --git a/internal/domain/access.go b/internal/domain/access.go index b2ff5e94..c18f846e 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -199,6 +199,12 @@ type AccessConfigForNameSilo struct { ApiKey string `json:"apiKey"` } +type AccessConfigForNetcup struct { + CustomerNumber string `json:"customerNumber"` + ApiKey string `json:"apiKey"` + ApiPassword string `json:"apiPassword"` +} + type AccessConfigForNS1 struct { ApiKey string `json:"apiKey"` } diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 728f89b6..4de70cd3 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -52,6 +52,7 @@ const ( AccessProviderTypeNamecheap = AccessProviderType("namecheap") AccessProviderTypeNameDotCom = AccessProviderType("namedotcom") AccessProviderTypeNameSilo = AccessProviderType("namesilo") + AccessProviderTypeNetcup = AccessProviderType("netcup") AccessProviderTypeNS1 = AccessProviderType("ns1") AccessProviderTypePorkbun = AccessProviderType("porkbun") AccessProviderTypePowerDNS = AccessProviderType("powerdns") @@ -130,6 +131,7 @@ const ( ACMEDns01ProviderTypeNamecheap = ACMEDns01ProviderType(AccessProviderTypeNamecheap) ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom) ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo) + ACMEDns01ProviderTypeNetcup = ACMEDns01ProviderType(AccessProviderTypeNetcup) ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1) ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun) ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS) diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/netcup/netcup.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/netcup/netcup.go new file mode 100644 index 00000000..43d7a694 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/netcup/netcup.go @@ -0,0 +1,40 @@ +package netcup + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/providers/dns/netcup" +) + +type ChallengeProviderConfig struct { + CustomerNumber string `json:"customerNumber"` + ApiKey string `json:"apiKey"` + ApiPassword string `json:"apiPassword"` + 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 := netcup.NewDefaultConfig() + providerConfig.Customer = config.CustomerNumber + providerConfig.Key = config.ApiKey + providerConfig.Password = config.ApiPassword + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := netcup.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/ui/public/imgs/providers/netcup.png b/ui/public/imgs/providers/netcup.png new file mode 100644 index 0000000000000000000000000000000000000000..2f56ce118c3868be85c1eba20bf2592c673f04a0 GIT binary patch literal 4093 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 literal 0 HcmV?d00001 diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 02a71854..b7d374d3 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -46,6 +46,7 @@ import AccessFormMattermostConfig from "./AccessFormMattermostConfig"; import AccessFormNamecheapConfig from "./AccessFormNamecheapConfig"; import AccessFormNameDotComConfig from "./AccessFormNameDotComConfig"; import AccessFormNameSiloConfig from "./AccessFormNameSiloConfig"; +import AccessFormNetcupConfig from "./AccessFormNetcupConfig"; import AccessFormNS1Config from "./AccessFormNS1Config"; import AccessFormPorkbunConfig from "./AccessFormPorkbunConfig"; import AccessFormPowerDNSConfig from "./AccessFormPowerDNSConfig"; @@ -242,6 +243,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className, return <AccessFormNameDotComConfig {...nestedFormProps} />; case ACCESS_PROVIDERS.NAMESILO: return <AccessFormNameSiloConfig {...nestedFormProps} />; + case ACCESS_PROVIDERS.NETCUP: + return <AccessFormNetcupConfig {...nestedFormProps} />; case ACCESS_PROVIDERS.NS1: return <AccessFormNS1Config {...nestedFormProps} />; case ACCESS_PROVIDERS.PORKBUN: diff --git a/ui/src/components/access/AccessFormNetcupConfig.tsx b/ui/src/components/access/AccessFormNetcupConfig.tsx new file mode 100644 index 00000000..c5d4bfc6 --- /dev/null +++ b/ui/src/components/access/AccessFormNetcupConfig.tsx @@ -0,0 +1,79 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForNetcup } from "@/domain/access"; + +type AccessFormNetcupConfigFieldValues = Nullish<AccessConfigForNetcup>; + +export type AccessFormNetcupConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormNetcupConfigFieldValues; + onValuesChange?: (values: AccessFormNetcupConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormNetcupConfigFieldValues => { + return { + customerNumber: "", + apiKey: "", + apiPassword: "", + }; +}; + +const AccessFormNetcupConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormNetcupConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + customerNumber: z.string().nonempty(t("access.form.netcup_customer_number.placeholder")).trim(), + apiKey: z.string().nonempty(t("access.form.netcup_api_key.placeholder")).trim(), + apiPassword: z.string().nonempty(t("access.form.netcup_api_password.placeholder")).trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => { + onValuesChange?.(values); + }; + + return ( + <Form + form={formInst} + disabled={disabled} + initialValues={initialValues ?? initFormModel()} + layout="vertical" + name={formName} + onValuesChange={handleFormChange} + > + <Form.Item + name="customerNumber" + label={t("access.form.netcup_customer_number.label")} + rules={[formRule]} + tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.netcup_customer_number.tooltip") }}></span>} + > + <Input autoComplete="new-password" placeholder={t("access.form.netcup_customer_number.placeholder")} /> + </Form.Item> + + <Form.Item + name="apiKey" + label={t("access.form.netcup_api_key.label")} + rules={[formRule]} + tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.netcup_api_key.tooltip") }}></span>} + > + <Input.Password autoComplete="new-password" placeholder={t("access.form.netcup_api_key.placeholder")} /> + </Form.Item> + + <Form.Item + name="apiPassword" + label={t("access.form.netcup_api_password.label")} + rules={[formRule]} + tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.netcup_api_password.tooltip") }}></span>} + > + <Input.Password autoComplete="new-password" placeholder={t("access.form.netcup_api_password.placeholder")} /> + </Form.Item> + </Form> + ); +}; + +export default AccessFormNetcupConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx index 0f3f3082..e99a2431 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx @@ -131,7 +131,6 @@ info "Completed" return `# *** 需要 root 权限 *** # 脚本参考 https://github.com/lfgyx/fnos_certificate_update/blob/main/src/update_cert.sh - # 请将以下变量替换为实际值 # 飞牛证书实际存放路径请在 \`/usr/trim/etc/network_cert_all.conf\` 中查看,注意不要修改文件名 $tmpFullchainPath = "${params?.certPath || "<your-fullchain-cert-path>"}" # 证书文件路径(与表单中保持一致) diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index b3ba29ca..e0cce59d 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -41,6 +41,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForNamecheap | AccessConfigForNameDotCom | AccessConfigForNameSilo + | AccessConfigForNetcup | AccessConfigForPorkbun | AccessConfigForPowerDNS | AccessConfigForProxmoxVE @@ -249,6 +250,12 @@ export type AccessConfigForNameSilo = { apiKey: string; }; +export type AccessConfigForNetcup = { + customerNumber: string; + apiKey: string; + apiPassword: string; +}; + export type AccessConfigForNS1 = { apiKey: string; }; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 6fc29ad4..5cc50534 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -43,6 +43,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ NAMECHEAP: "namecheap", NAMEDOTCOM: "namedotcom", NAMESILO: "namesilo", + NETCUP: "netcup", NS1: "ns1", PORKBUN: "porkbun", POWERDNS: "powerdns", @@ -132,6 +133,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv [ACCESS_PROVIDERS.GODADDY, "provider.godaddy", "/imgs/providers/godaddy.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.NAMECHEAP, "provider.namecheap", "/imgs/providers/namecheap.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.NAMEDOTCOM, "provider.namedotcom", "/imgs/providers/namedotcom.svg", [ACCESS_USAGES.DNS]], + [ACCESS_PROVIDERS.NETCUP, "provider.netcup", "/imgs/providers/netcup.png", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.NAMESILO, "provider.namesilo", "/imgs/providers/namesilo.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.NS1, "provider.ns1", "/imgs/providers/ns1.svg", [ACCESS_USAGES.DNS]], [ACCESS_PROVIDERS.PORKBUN, "provider.porkbun", "/imgs/providers/porkbun.svg", [ACCESS_USAGES.DNS]], @@ -249,6 +251,7 @@ export const ACME_DNS01_PROVIDERS = Object.freeze({ NAMECHEAP: `${ACCESS_PROVIDERS.NAMECHEAP}`, NAMEDOTCOM: `${ACCESS_PROVIDERS.NAMEDOTCOM}`, NAMESILO: `${ACCESS_PROVIDERS.NAMESILO}`, + NETCUP: `${ACCESS_PROVIDERS.NETCUP}`, NS1: `${ACCESS_PROVIDERS.NS1}`, PORKBUN: `${ACCESS_PROVIDERS.PORKBUN}`, POWERDNS: `${ACCESS_PROVIDERS.POWERDNS}`, @@ -299,6 +302,7 @@ export const acmeDns01ProvidersMap: Map<ACMEDns01Provider["type"] | string, ACME [ACME_DNS01_PROVIDERS.NAMECHEAP, "provider.namecheap"], [ACME_DNS01_PROVIDERS.NAMEDOTCOM, "provider.namedotcom"], [ACME_DNS01_PROVIDERS.NAMESILO, "provider.namesilo"], + [ACME_DNS01_PROVIDERS.NETCUP, "provider.netcup"], [ACME_DNS01_PROVIDERS.NS1, "provider.ns1"], [ACME_DNS01_PROVIDERS.PORKBUN, "provider.porkbun"], [ACME_DNS01_PROVIDERS.VERCEL, "provider.vercel"], diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index 2a4897c5..910e7a04 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -262,6 +262,15 @@ "access.form.namesilo_api_key.label": "NameSilo API key", "access.form.namesilo_api_key.placeholder": "Please enter NameSilo API key", "access.form.namesilo_api_key.tooltip": "For more information, see <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>", + "access.form.netcup_customer_number.label": "netcup customer number", + "access.form.netcup_customer_number.placeholder": "Please enter netcup customer number", + "access.form.netcup_customer_number.tooltip": "For more information, see <a href=\"https://helpcenter.netcup.com/en/wiki/general/ccp-login/\" target=\"_blank\">https://helpcenter.netcup.com/en/wiki/general/ccp-login/</a>", + "access.form.netcup_api_key.label": "netcup API key", + "access.form.netcup_api_key.placeholder": "Please enter netcup API key", + "access.form.netcup_api_key.tooltip": "For more information, see <a href=\"https://helpcenter.netcup.com/en/wiki/general/our-api/\" target=\"_blank\">https://helpcenter.netcup.com/en/wiki/general/our-api/</a>", + "access.form.netcup_api_password.label": "netcup API password", + "access.form.netcup_api_password.placeholder": "Please enter netcup API password", + "access.form.netcup_api_password.tooltip": "For more information, see <a href=\"https://helpcenter.netcup.com/en/wiki/general/our-api/\" target=\"_blank\">https://helpcenter.netcup.com/en/wiki/general/our-api/</a>", "access.form.ns1_api_key.label": "NS1 API key", "access.form.ns1_api_key.placeholder": "Please enter NS1 API key", "access.form.ns1_api_key.tooltip": "For more information, see <a href=\"https://www.ibm.com/docs/en/ns1-connect?topic=introduction-using-api\" target=\"_blank\">https://www.ibm.com/docs/en/ns1-connect?topic=introduction-using-api</a>", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 0c140684..1f7e5589 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -90,6 +90,7 @@ "provider.namecheap": "Namecheap", "provider.namedotcom": "Name.com", "provider.namesilo": "NameSilo", + "provider.netcup": "netcup", "provider.ns1": "NS1 (IBM NS1 Connect)", "provider.porkbun": "Porkbun", "provider.powerdns": "PowerDNS", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index 4839d6ad..fd993178 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -256,6 +256,15 @@ "access.form.namesilo_api_key.label": "NameSilo API Key", "access.form.namesilo_api_key.placeholder": "请输入 NameSilo API Key", "access.form.namesilo_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>", + "access.form.netcup_customer_number.label": "netcup 客户编号", + "access.form.netcup_customer_number.placeholder": "请输入 netcup 客户编号", + "access.form.netcup_customer_number.tooltip": "这是什么?请参阅 <a href=\"https://helpcenter.netcup.com/en/wiki/general/ccp-login/\" target=\"_blank\">https://helpcenter.netcup.com/en/wiki/general/ccp-login/</a>", + "access.form.netcup_api_key.label": "netcup API Key", + "access.form.netcup_api_key.placeholder": "请输入 netcup API Key", + "access.form.netcup_api_key.tooltip": "这是什么?请参阅 <a href=\"https://helpcenter.netcup.com/en/wiki/general/our-api/\" target=\"_blank\">https://helpcenter.netcup.com/en/wiki/general/our-api/</a>", + "access.form.netcup_api_password.label": "netcup API Key 密码", + "access.form.netcup_api_password.placeholder": "请输入 netcup API Key 密码", + "access.form.netcup_api_password.tooltip": "这是什么?请参阅 <a href=\"https://helpcenter.netcup.com/en/wiki/general/our-api/\" target=\"_blank\">https://helpcenter.netcup.com/en/wiki/general/our-api/</a>", "access.form.ns1_api_key.label": "NS1 API Key", "access.form.ns1_api_key.placeholder": "请输入 NS1 API Key", "access.form.ns1_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.ibm.com/docs/zh/ns1-connect?topic=introduction-using-api\" target=\"_blank\">https://www.ibm.com/docs/zh/ns1-connect?topic=introduction-using-api</a>", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 5626426e..739fcebf 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -90,6 +90,7 @@ "provider.namecheap": "Namecheap", "provider.namedotcom": "Name.com", "provider.namesilo": "NameSilo", + "provider.netcup": "netcup", "provider.ns1": "NS1 (IBM NS1 Connect)", "provider.porkbun": "Porkbun", "provider.powerdns": "PowerDNS", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 378cff37..d1829698 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -549,7 +549,7 @@ "workflow_node.deploy.form.ssh_preset_scripts.option.ps_backup_files.label": "PowerShell - 备份原证书文件", "workflow_node.deploy.form.ssh_preset_scripts.option.sh_reload_nginx.label": "POSIX Bash - 重启 nginx 进程", "workflow_node.deploy.form.ssh_preset_scripts.option.sh_replace_synologydsm_ssl.label": "POSIX Bash - 替换群晖 DSM 证书", - "workflow_node.deploy.form.ssh_preset_scripts.option.sh_replace_fnos_ssl.label": "POSIX Bash - 替换飞牛 OS 证书", + "workflow_node.deploy.form.ssh_preset_scripts.option.sh_replace_fnos_ssl.label": "POSIX Bash - 替换飞牛 fnOS 证书", "workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_iis.label": "PowerShell - 导入并绑定到 IIS", "workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_netsh.label": "PowerShell - 导入并绑定到 netsh", "workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_rdp.label": "PowerShell - 导入并绑定到 RDP",