diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go index c54d1fe2..8f9fe89e 100644 --- a/internal/applicant/providers.go +++ b/internal/applicant/providers.go @@ -8,6 +8,7 @@ import ( "github.com/usual2970/certimate/internal/domain" pACMEHttpReq "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq" pAliyun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun" + pAliyunESA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa" pAWSRoute53 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53" pAzureDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns" pBaiduCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud" @@ -79,20 +80,36 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi return applicant, err } - case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS: + case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS, domain.ACMEDns01ProviderTypeAliyunESA: { access := domain.AccessConfigForAliyun{} if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := pAliyun.NewChallengeProvider(&pAliyun.ChallengeProviderConfig{ - AccessKeyId: access.AccessKeyId, - AccessKeySecret: access.AccessKeySecret, - DnsPropagationTimeout: options.DnsPropagationTimeout, - DnsTTL: options.DnsTTL, - }) - return applicant, err + switch options.Provider { + case domain.ACMEDns01ProviderTypeAliyun, domain.ACMEDns01ProviderTypeAliyunDNS: + applicant, err := pAliyun.NewChallengeProvider(&pAliyun.ChallengeProviderConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + + case domain.ACMEDns01ProviderTypeAliyunESA: + applicant, err := pAliyunESA.NewChallengeProvider(&pAliyunESA.ChallengeProviderConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + Region: maputil.GetString(options.ProviderExtendedConfig, "region"), + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + + default: + break + } } case domain.ACMEDns01ProviderTypeAWS, domain.ACMEDns01ProviderTypeAWSRoute53: diff --git a/internal/domain/provider.go b/internal/domain/provider.go index a99b8717..61af784f 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -105,6 +105,7 @@ const ( ACMEDns01ProviderTypeACMEHttpReq = ACMEDns01ProviderType(AccessProviderTypeACMEHttpReq) ACMEDns01ProviderTypeAliyun = ACMEDns01ProviderType(AccessProviderTypeAliyun) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAliyunDNS] ACMEDns01ProviderTypeAliyunDNS = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-dns") + ACMEDns01ProviderTypeAliyunESA = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-esa") ACMEDns01ProviderTypeAWS = ACMEDns01ProviderType(AccessProviderTypeAWS) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAWSRoute53] ACMEDns01ProviderTypeAWSRoute53 = ACMEDns01ProviderType(AccessProviderTypeAWS + "-route53") ACMEDns01ProviderTypeAzure = ACMEDns01ProviderType(AccessProviderTypeAzure) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAzure] diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/aliyun_esa.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/aliyun_esa.go new file mode 100644 index 00000000..bf7026da --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/aliyun_esa.go @@ -0,0 +1,40 @@ +package aliyunesa + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + + internal "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/internal" +) + +type ChallengeProviderConfig struct { + AccessKeyId string `json:"accessKeyId"` + AccessKeySecret string `json:"accessKeySecret"` + Region string `json:"region"` + 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 := internal.NewDefaultConfig() + providerConfig.SecretID = config.AccessKeyId + providerConfig.SecretKey = config.AccessKeySecret + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = config.DnsTTL + } + + provider, err := internal.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/internal/lego.go new file mode 100644 index 00000000..79df4083 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun-esa/internal/lego.go @@ -0,0 +1,266 @@ +package lego_aliyunesa + +import ( + "errors" + "fmt" + "strings" + "sync" + "time" + + aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + aliesa "github.com/alibabacloud-go/esa-20240910/v2/client" + "github.com/alibabacloud-go/tea/tea" + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/challenge/dns01" + "github.com/go-acme/lego/v4/platform/config/env" +) + +const ( + envNamespace = "ALICLOUDESA_" + + EnvAccessKey = envNamespace + "ACCESS_KEY" + EnvSecretKey = envNamespace + "SECRET_KEY" + EnvRegionID = envNamespace + "REGION_ID" + + EnvTTL = envNamespace + "TTL" + EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" + EnvPollingInterval = envNamespace + "POLLING_INTERVAL" + EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT" +) + +var _ challenge.ProviderTimeout = (*DNSProvider)(nil) + +type Config struct { + SecretID string + SecretKey string + RegionID string + + PropagationTimeout time.Duration + PollingInterval time.Duration + TTL int32 + HTTPTimeout time.Duration +} + +type DNSProvider struct { + client *aliesa.Client + config *Config + + siteIDs map[string]int64 + siteIDsMtx sync.Mutex +} + +func NewDefaultConfig() *Config { + return &Config{ + TTL: int32(env.GetOrDefaultInt(EnvTTL, 300)), + PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute), + PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval), + HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), + } +} + +func NewDNSProvider() (*DNSProvider, error) { + values, err := env.Get(EnvAccessKey, EnvSecretKey, EnvRegionID) + if err != nil { + return nil, fmt.Errorf("alicloud-esa: %w", err) + } + + config := NewDefaultConfig() + config.SecretID = values[EnvAccessKey] + config.SecretKey = values[EnvSecretKey] + config.RegionID = values[EnvRegionID] + + return NewDNSProviderConfig(config) +} + +func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { + if config == nil { + return nil, errors.New("alicloud-esa: the configuration of the DNS provider is nil") + } + + client, err := aliesa.NewClient(&aliopen.Config{ + AccessKeyId: tea.String(config.SecretID), + AccessKeySecret: tea.String(config.SecretKey), + Endpoint: tea.String(fmt.Sprintf("esa.%s.aliyuncs.com", config.RegionID)), + }) + if err != nil { + return nil, fmt.Errorf("alicloud-esa: %w", err) + } + + return &DNSProvider{ + client: client, + config: config, + }, nil +} + +func (d *DNSProvider) Present(domain, token, keyAuth string) error { + info := dns01.GetChallengeInfo(domain, keyAuth) + + authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) + if err != nil { + return fmt.Errorf("alicloud-esa: could not find zone for domain %q: %w", domain, err) + } + + siteId, err := d.getSiteId(authZone) + if err != nil { + return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", authZone, err) + } + + if err := d.addOrUpdateDNSRecord(siteId, strings.TrimRight(info.EffectiveFQDN, "."), info.Value); err != nil { + return fmt.Errorf("alicloud-esa: %w", err) + } + + return nil +} + +func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { + info := dns01.GetChallengeInfo(domain, keyAuth) + + authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) + if err != nil { + return fmt.Errorf("alicloud-esa: could not find zone for domain %q: %w", domain, err) + } + + siteId, err := d.getSiteId(authZone) + if err != nil { + return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", authZone, err) + } + + if err := d.removeDNSRecord(siteId, strings.TrimRight(info.EffectiveFQDN, ".")); err != nil { + return fmt.Errorf("alicloud-esa: %w", err) + } + + return nil +} + +func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { + return d.config.PropagationTimeout, d.config.PollingInterval +} + +func (d *DNSProvider) getSiteId(siteName string) (int64, error) { + d.siteIDsMtx.Lock() + siteID, ok := d.siteIDs[siteName] + d.siteIDsMtx.Unlock() + if ok { + return siteID, nil + } + + pageNumber := 1 + pageSize := 500 + for { + request := &aliesa.ListSitesRequest{ + SiteName: tea.String(siteName), + PageNumber: tea.Int32(int32(pageNumber)), + PageSize: tea.Int32(int32(pageNumber)), + AccessType: tea.String("NS"), + } + response, err := d.client.ListSites(request) + if err != nil { + return 0, err + } + + if response.Body == nil { + break + } else { + for _, record := range response.Body.Sites { + if tea.StringValue(record.SiteName) == siteName { + d.siteIDsMtx.Lock() + d.siteIDs[siteName] = *record.SiteId + d.siteIDsMtx.Unlock() + return *record.SiteId, nil + } + } + + if len(response.Body.Sites) < pageSize { + break + } + + pageNumber++ + } + } + + return 0, errors.New("failed to get site id") +} + +func (d *DNSProvider) findDNSRecord(siteId int64, effectiveFQDN string) (*aliesa.ListRecordsResponseBodyRecords, error) { + pageNumber := 1 + pageSize := 500 + for { + request := &aliesa.ListRecordsRequest{ + SiteId: tea.Int64(siteId), + Type: tea.String("TXT"), + RecordName: tea.String(effectiveFQDN), + PageNumber: tea.Int32(int32(pageNumber)), + PageSize: tea.Int32(int32(pageNumber)), + } + response, err := d.client.ListRecords(request) + if err != nil { + return nil, err + } + + if response.Body == nil { + break + } else { + for _, record := range response.Body.Records { + if tea.StringValue(record.RecordName) == effectiveFQDN { + return record, nil + } + } + + if len(response.Body.Records) < pageSize { + break + } + + pageNumber++ + } + } + + return nil, nil +} + +func (d *DNSProvider) addOrUpdateDNSRecord(siteId int64, effectiveFQDN, value string) error { + record, err := d.findDNSRecord(siteId, effectiveFQDN) + if err != nil { + return err + } + + if record == nil { + request := &aliesa.CreateRecordRequest{ + SiteId: tea.Int64(siteId), + Type: tea.String("TXT"), + RecordName: tea.String(effectiveFQDN), + Data: &aliesa.CreateRecordRequestData{ + Value: tea.String(value), + }, + Ttl: tea.Int32(d.config.TTL), + } + _, err := d.client.CreateRecord(request) + return err + } else { + request := &aliesa.UpdateRecordRequest{ + RecordId: record.RecordId, + Ttl: tea.Int32(d.config.TTL), + Data: &aliesa.UpdateRecordRequestData{ + Value: tea.String(value), + }, + } + _, err := d.client.UpdateRecord(request) + return err + } +} + +func (d *DNSProvider) removeDNSRecord(siteId int64, effectiveFQDN string) error { + record, err := d.findDNSRecord(siteId, effectiveFQDN) + if err != nil { + return err + } + + if record == nil { + return nil + } else { + request := &aliesa.DeleteRecordRequest{ + RecordId: record.RecordId, + } + _, err = d.client.DeleteRecord(request) + return err + } +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/internal/lego.go index 0c45f544..f67662b5 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/internal/lego.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/internal/lego.go @@ -128,7 +128,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { return d.config.PropagationTimeout, d.config.PollingInterval } -func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*bcedns.Record, error) { +func (d *DNSProvider) findDNSRecord(zoneName, subDomain string) (*bcedns.Record, error) { pageMarker := "" pageSize := 1000 for { @@ -159,7 +159,7 @@ func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*bcedns.Record, } func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error { - record, err := d.getDNSRecord(zoneName, subDomain) + record, err := d.findDNSRecord(zoneName, subDomain) if err != nil { return err } @@ -186,7 +186,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) er } func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error { - record, err := d.getDNSRecord(zoneName, subDomain) + record, err := d.findDNSRecord(zoneName, subDomain) if err != nil { return err } diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/internal/lego.go index 55404b65..8b33cf9e 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/internal/lego.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/internal/lego.go @@ -115,7 +115,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { return d.config.PropagationTimeout, d.config.PollingInterval } -func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*libdns.Record, error) { +func (d *DNSProvider) findDNSRecord(zoneName, subDomain string) (*libdns.Record, error) { records, err := d.client.GetRecords(context.Background(), zoneName) if err != nil { return nil, err @@ -131,7 +131,7 @@ func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*libdns.Record, } func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error { - record, err := d.getDNSRecord(zoneName, subDomain) + record, err := d.findDNSRecord(zoneName, subDomain) if err != nil { return err } @@ -153,7 +153,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) er } func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error { - record, err := d.getDNSRecord(zoneName, subDomain) + record, err := d.findDNSRecord(zoneName, subDomain) if err != nil { return err } diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go index e4bf221e..7f1f5670 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go @@ -121,7 +121,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { return d.config.PropagationTimeout, d.config.PollingInterval } -func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*gnamesdk.ResolutionRecord, error) { +func (d *DNSProvider) findDNSRecord(zoneName, subDomain string) (*gnamesdk.ResolutionRecord, error) { page := int32(1) pageSize := int32(20) for { @@ -155,7 +155,7 @@ func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*gnamesdk.Resolu } func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error { - record, err := d.getDNSRecord(zoneName, subDomain) + record, err := d.findDNSRecord(zoneName, subDomain) if err != nil { return err } @@ -186,7 +186,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) er } func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error { - record, err := d.getDNSRecord(zoneName, subDomain) + record, err := d.findDNSRecord(zoneName, subDomain) if err != nil { return err } diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/internal/lego.go index 14d86a4d..692c42d3 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/internal/lego.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/internal/lego.go @@ -20,7 +20,7 @@ const ( EnvSecretID = envNamespace + "SECRET_ID" EnvSecretKey = envNamespace + "SECRET_KEY" - EnvZoneId = envNamespace + "ZONE_ID" + EnvZoneID = envNamespace + "ZONE_ID" EnvTTL = envNamespace + "TTL" EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" @@ -33,7 +33,7 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil) type Config struct { SecretID string SecretKey string - ZoneId string + ZoneID string PropagationTimeout time.Duration PollingInterval time.Duration @@ -56,7 +56,7 @@ func NewDefaultConfig() *Config { } func NewDNSProvider() (*DNSProvider, error) { - values, err := env.Get(EnvSecretID, EnvSecretKey, EnvZoneId) + values, err := env.Get(EnvSecretID, EnvSecretKey, EnvZoneID) if err != nil { return nil, fmt.Errorf("tencentcloud-eo: %w", err) } @@ -64,7 +64,7 @@ func NewDNSProvider() (*DNSProvider, error) { config := NewDefaultConfig() config.SecretID = values[EnvSecretID] config.SecretKey = values[EnvSecretKey] - config.ZoneId = values[EnvSecretKey] + config.ZoneID = values[EnvSecretKey] return NewDNSProviderConfig(config) } @@ -112,12 +112,12 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { return d.config.PropagationTimeout, d.config.PollingInterval } -func (d *DNSProvider) getDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error) { +func (d *DNSProvider) findDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error) { pageOffset := 0 pageLimit := 1000 for { request := teo.NewDescribeDnsRecordsRequest() - request.ZoneId = common.StringPtr(d.config.ZoneId) + request.ZoneId = common.StringPtr(d.config.ZoneID) request.Offset = common.Int64Ptr(int64(pageOffset)) request.Limit = common.Int64Ptr(int64(pageLimit)) request.Filters = []*teo.AdvancedFilter{ @@ -141,7 +141,7 @@ func (d *DNSProvider) getDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error) } } - if len(response.Response.DnsRecords) < int(pageLimit) { + if len(response.Response.DnsRecords) < pageLimit { break } @@ -153,14 +153,14 @@ func (d *DNSProvider) getDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error) } func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error { - record, err := d.getDNSRecord(effectiveFQDN) + record, err := d.findDNSRecord(effectiveFQDN) if err != nil { return err } if record == nil { request := teo.NewCreateDnsRecordRequest() - request.ZoneId = common.StringPtr(d.config.ZoneId) + request.ZoneId = common.StringPtr(d.config.ZoneID) request.Name = common.StringPtr(effectiveFQDN) request.Type = common.StringPtr("TXT") request.Content = common.StringPtr(value) @@ -169,8 +169,9 @@ func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error { return err } else { record.Content = common.StringPtr(value) + record.TTL = common.Int64Ptr(int64(d.config.TTL)) request := teo.NewModifyDnsRecordsRequest() - request.ZoneId = common.StringPtr(d.config.ZoneId) + request.ZoneId = common.StringPtr(d.config.ZoneID) request.DnsRecords = []*teo.DnsRecord{record} if _, err := d.client.ModifyDnsRecords(request); err != nil { return err @@ -178,7 +179,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error { if *record.Status == "disable" { request := teo.NewModifyDnsRecordsStatusRequest() - request.ZoneId = common.StringPtr(d.config.ZoneId) + request.ZoneId = common.StringPtr(d.config.ZoneID) request.RecordsToEnable = []*string{record.RecordId} if _, err = d.client.ModifyDnsRecordsStatus(request); err != nil { return err @@ -190,7 +191,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error { } func (d *DNSProvider) removeDNSRecord(effectiveFQDN string) error { - record, err := d.getDNSRecord(effectiveFQDN) + record, err := d.findDNSRecord(effectiveFQDN) if err != nil { return err } @@ -199,7 +200,7 @@ func (d *DNSProvider) removeDNSRecord(effectiveFQDN string) error { return nil } else { request := teo.NewDeleteDnsRecordsRequest() - request.ZoneId = common.StringPtr(d.config.ZoneId) + request.ZoneId = common.StringPtr(d.config.ZoneID) request.RecordIds = []*string{record.RecordId} _, err = d.client.DeleteDnsRecords(request) return err diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/tencentcloud_eo.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/tencentcloud_eo.go index 33552ecf..427c79ea 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/tencentcloud_eo.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo/tencentcloud_eo.go @@ -24,7 +24,7 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, providerConfig := internal.NewDefaultConfig() providerConfig.SecretID = config.SecretId providerConfig.SecretKey = config.SecretKey - providerConfig.ZoneId = config.ZoneId + providerConfig.ZoneID = config.ZoneId if config.DnsPropagationTimeout != 0 { providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second } diff --git a/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx b/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx index 37d7c6a1..57c448e2 100644 --- a/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx @@ -41,6 +41,7 @@ import { useAccessesStore } from "@/stores/access"; import { useContactEmailsStore } from "@/stores/contact"; import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators"; +import ApplyNodeConfigFormAliyunESAConfig from "./ApplyNodeConfigFormAliyunESAConfig"; import ApplyNodeConfigFormAWSRoute53Config from "./ApplyNodeConfigFormAWSRoute53Config"; import ApplyNodeConfigFormHuaweiCloudDNSConfig from "./ApplyNodeConfigFormHuaweiCloudDNSConfig"; import ApplyNodeConfigFormJDCloudDNSConfig from "./ApplyNodeConfigFormJDCloudDNSConfig"; @@ -152,7 +153,7 @@ const ApplyNodeConfigForm = forwardRef { // 通常情况下每个授权信息只对应一个 DNS 提供商,此时无需显示 DNS 提供商字段; - // 如果对应多个(如 AWS 的 Route53、Lightsail,腾讯云的 DNS、EdgeOne 等),则显示。 + // 如果对应多个(如 AWS 的 Route53、Lightsail,阿里云的 DNS、ESA,腾讯云的 DNS、EdgeOne 等),则显示。 if (fieldProviderAccessId) { const access = accesses.find((e) => e.id === fieldProviderAccessId); const providers = Array.from(acmeDns01ProvidersMap.values()).filter((e) => e.provider === access?.provider); @@ -188,6 +189,8 @@ const ApplyNodeConfigForm = forwardRef; case ACME_DNS01_PROVIDERS.AWS: case ACME_DNS01_PROVIDERS.AWS_ROUTE53: return ; diff --git a/ui/src/components/workflow/node/ApplyNodeConfigFormAliyunESAConfig.tsx b/ui/src/components/workflow/node/ApplyNodeConfigFormAliyunESAConfig.tsx new file mode 100644 index 00000000..d429b53d --- /dev/null +++ b/ui/src/components/workflow/node/ApplyNodeConfigFormAliyunESAConfig.tsx @@ -0,0 +1,58 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +type ApplyNodeConfigFormAliyunESAConfigFieldValues = Nullish<{ + region: string; +}>; + +export type ApplyNodeConfigFormAliyunESAConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: ApplyNodeConfigFormAliyunESAConfigFieldValues; + onValuesChange?: (values: ApplyNodeConfigFormAliyunESAConfigFieldValues) => void; +}; + +const initFormModel = (): ApplyNodeConfigFormAliyunESAConfigFieldValues => { + return {}; +}; + +const ApplyNodeConfigFormAliyunESAConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: ApplyNodeConfigFormAliyunESAConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + region: z + .string({ message: t("workflow_node.apply.form.aliyun_esa_region.placeholder") }) + .nonempty(t("workflow_node.apply.form.aliyun_esa_region.placeholder")) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default ApplyNodeConfigFormAliyunESAConfig; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 642a42da..219a2713 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -221,6 +221,7 @@ export const ACME_DNS01_PROVIDERS = Object.freeze({ ACMEHTTPREQ: `${ACCESS_PROVIDERS.ACMEHTTPREQ}`, ALIYUN: `${ACCESS_PROVIDERS.ALIYUN}`, // 兼容旧值,等同于 `ALIYUN_DNS` ALIYUN_DNS: `${ACCESS_PROVIDERS.ALIYUN}-dns`, + ALIYUN_ESA: `${ACCESS_PROVIDERS.ALIYUN}-esa`, AWS: `${ACCESS_PROVIDERS.AWS}`, // 兼容旧值,等同于 `AWS_ROUTE53` AWS_ROUTE53: `${ACCESS_PROVIDERS.AWS}-route53`, AZURE: `${ACCESS_PROVIDERS.AZURE}`, // 兼容旧值,等同于 `AZURE_DNS` @@ -273,6 +274,7 @@ export const acmeDns01ProvidersMap: Maphttps://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-endpoint", "workflow_node.apply.form.aws_route53_region.label": "AWS Route53 Region", "workflow_node.apply.form.aws_route53_region.placeholder": "Please enter AWS Route53 region (e.g. us-east-1)", "workflow_node.apply.form.aws_route53_region.tooltip": "For more information, see https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 44cf3024..2233e93e 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -39,6 +39,9 @@ "workflow_node.apply.form.provider_access.placeholder": "请选择 DNS 提供商授权", "workflow_node.apply.form.provider_access.tooltip": "用于 ACME DNS-01 质询时操作域名解析记录,注意与部署阶段所需的主机提供商相区分。", "workflow_node.apply.form.provider_access.button": "新建", + "workflow_node.apply.form.aliyun_esa_region.label": "阿里云 ESA 服务地域", + "workflow_node.apply.form.aliyun_esa_region.placeholder": "请输入阿里云 ESA 服务地域(例如:cn-hangzhou)", + "workflow_node.apply.form.aliyun_esa_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/edge-security-acceleration/esa/api-esa-2024-09-10-endpoint", "workflow_node.apply.form.aws_route53_region.label": "AWS Route53 服务区域", "workflow_node.apply.form.aws_route53_region.placeholder": "请输入 AWS Route53 服务区域(例如:us-east-1)", "workflow_node.apply.form.aws_route53_region.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints",