diff --git a/internal/certapply/applicators/sp_technitiumdns.go b/internal/certapply/applicators/sp_technitiumdns.go
new file mode 100644
index 00000000..c1e90816
--- /dev/null
+++ b/internal/certapply/applicators/sp_technitiumdns.go
@@ -0,0 +1,31 @@
+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/technitiumdns"
+ xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
+)
+
+func init() {
+ if err := ACMEDns01Registries.Register(domain.ACMEDns01ProviderTypeTechnitiumDNS, func(options *ProviderFactoryOptions) (challenge.Provider, error) {
+ credentials := domain.AccessConfigForTechnitiumDNS{}
+ if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ provider, err := technitiumdns.NewChallengeProvider(&technitiumdns.ChallengeProviderConfig{
+ ServerUrl: credentials.ServerUrl,
+ ApiToken: credentials.ApiToken,
+ AllowInsecureConnections: credentials.AllowInsecureConnections,
+ 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 2578f9f0..f40834f8 100644
--- a/internal/domain/access.go
+++ b/internal/domain/access.go
@@ -379,6 +379,12 @@ type AccessConfigForSSLCom struct {
AccessConfigForACMEExternalAccountBinding
}
+type AccessConfigForTechnitiumDNS struct {
+ ServerUrl string `json:"serverUrl"`
+ ApiToken string `json:"apiToken"`
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+}
+
type AccessConfigForTelegramBot struct {
BotToken string `json:"botToken"`
ChatId int64 `json:"chatId,omitempty"`
diff --git a/internal/domain/provider.go b/internal/domain/provider.go
index 8b088cbc..0937d998 100644
--- a/internal/domain/provider.go
+++ b/internal/domain/provider.go
@@ -23,8 +23,9 @@ const (
AccessProviderTypeBaishan = AccessProviderType("baishan")
AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel")
AccessProviderTypeBaotaWAF = AccessProviderType("baotawaf")
- AccessProviderTypeBytePlus = AccessProviderType("byteplus")
+ AccessProviderTypeBookMyName = AccessProviderType("bookmyname") // BookMyName(预留)
AccessProviderTypeBunny = AccessProviderType("bunny")
+ AccessProviderTypeBytePlus = AccessProviderType("byteplus")
AccessProviderTypeCacheFly = AccessProviderType("cachefly")
AccessProviderTypeCdnfly = AccessProviderType("cdnfly")
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
@@ -52,14 +53,17 @@ const (
AccessProviderTypeGlobalSignAtlas = AccessProviderType("globalsignatlas")
AccessProviderTypeGoogleTrustServices = AccessProviderType("googletrustservices")
AccessProviderTypeHetzner = AccessProviderType("hetzner")
+ AccessProviderTypeHostinger = AccessProviderType("hostinger") // Hostinger(预留)
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
AccessProviderTypeKong = AccessProviderType("kong")
+ AccessProviderTypeKsyun = AccessProviderType("ksyun") // 金山云(预留)
AccessProviderTypeKubernetes = AccessProviderType("k8s")
AccessProviderTypeLarkBot = AccessProviderType("larkbot")
AccessProviderTypeLetsEncrypt = AccessProviderType("letsencrypt")
AccessProviderTypeLetsEncryptStaging = AccessProviderType("letsencryptstaging")
AccessProviderTypeLeCDN = AccessProviderType("lecdn")
+ AccessProviderTypeLinode = AccessProviderType("linode") // Linode(预留)
AccessProviderTypeLocal = AccessProviderType("local")
AccessProviderTypeMattermost = AccessProviderType("mattermost")
AccessProviderTypeNamecheap = AccessProviderType("namecheap")
@@ -75,12 +79,14 @@ const (
AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留)
AccessProviderTypeRainYun = AccessProviderType("rainyun")
AccessProviderTypeRatPanel = AccessProviderType("ratpanel")
+ AccessProviderTypeRFC2136 = AccessProviderType("rfc2136") // RFC2136(预留)
AccessProviderTypeSafeLine = AccessProviderType("safeline")
AccessProviderTypeSectigo = AccessProviderType("sectigo")
AccessProviderTypeSlackBot = AccessProviderType("slackbot")
AccessProviderTypeSpaceship = AccessProviderType("spaceship")
AccessProviderTypeSSH = AccessProviderType("ssh")
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
+ AccessProviderTypeTechnitiumDNS = AccessProviderType("technitiumdns")
AccessProviderTypeTelegramBot = AccessProviderType("telegrambot")
AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud")
AccessProviderTypeUCloud = AccessProviderType("ucloud")
@@ -169,6 +175,7 @@ const (
ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS)
ACMEDns01ProviderTypeRainYun = ACMEDns01ProviderType(AccessProviderTypeRainYun)
ACMEDns01ProviderTypeSpaceship = ACMEDns01ProviderType(AccessProviderTypeSpaceship)
+ ACMEDns01ProviderTypeTechnitiumDNS = ACMEDns01ProviderType(AccessProviderTypeTechnitiumDNS)
ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS]
ACMEDns01ProviderTypeTencentCloudDNS = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-dns")
ACMEDns01ProviderTypeTencentCloudEO = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-eo")
diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/powerdns/powerdns.go b/pkg/core/ssl-applicator/acme-dns01/providers/powerdns/powerdns.go
index abb38dba..45dc432c 100644
--- a/pkg/core/ssl-applicator/acme-dns01/providers/powerdns/powerdns.go
+++ b/pkg/core/ssl-applicator/acme-dns01/providers/powerdns/powerdns.go
@@ -3,13 +3,13 @@ package powerdns
import (
"crypto/tls"
"errors"
- "net/http"
"net/url"
"time"
"github.com/go-acme/lego/v4/providers/dns/pdns"
"github.com/certimate-go/certimate/pkg/core"
+ xhttp "github.com/certimate-go/certimate/pkg/utils/http"
)
type ChallengeProviderConfig struct {
@@ -30,12 +30,9 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (core.ACMEChallenger,
providerConfig.Host = serverUrl
providerConfig.APIKey = config.ApiKey
if config.AllowInsecureConnections {
- providerConfig.HTTPClient.Transport = &http.Transport{
- Proxy: http.ProxyFromEnvironment,
- TLSClientConfig: &tls.Config{
- InsecureSkipVerify: true,
- },
- }
+ transport := xhttp.NewDefaultTransport()
+ transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
+ providerConfig.HTTPClient.Transport = transport
}
if config.DnsPropagationTimeout != 0 {
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/technitiumdns/technitiumdns.go b/pkg/core/ssl-applicator/acme-dns01/providers/technitiumdns/technitiumdns.go
new file mode 100644
index 00000000..f3390d48
--- /dev/null
+++ b/pkg/core/ssl-applicator/acme-dns01/providers/technitiumdns/technitiumdns.go
@@ -0,0 +1,48 @@
+package technitiumdns
+
+import (
+ "crypto/tls"
+ "errors"
+ "time"
+
+ "github.com/go-acme/lego/v4/providers/dns/technitium"
+
+ "github.com/certimate-go/certimate/pkg/core"
+ xhttp "github.com/certimate-go/certimate/pkg/utils/http"
+)
+
+type ChallengeProviderConfig struct {
+ ServerUrl string `json:"serverUrl"`
+ ApiToken string `json:"apiToken"`
+ AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
+ 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 := technitium.NewDefaultConfig()
+ providerConfig.BaseURL = config.ServerUrl
+ providerConfig.APIToken = config.ApiToken
+ if config.AllowInsecureConnections {
+ transport := xhttp.NewDefaultTransport()
+ transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
+ providerConfig.HTTPClient.Transport = transport
+ }
+ if config.DnsPropagationTimeout != 0 {
+ providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
+ }
+ if config.DnsTTL != 0 {
+ providerConfig.TTL = int(config.DnsTTL)
+ }
+
+ provider, err := technitium.NewDNSProviderConfig(providerConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ return provider, nil
+}
diff --git a/ui/public/imgs/providers/technitiumdns.png b/ui/public/imgs/providers/technitiumdns.png
new file mode 100644
index 00000000..09d325f7
Binary files /dev/null and b/ui/public/imgs/providers/technitiumdns.png differ
diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx
index c97f9bd3..383351d9 100644
--- a/ui/src/components/access/AccessForm.tsx
+++ b/ui/src/components/access/AccessForm.tsx
@@ -76,6 +76,7 @@ import AccessConfigFieldsProviderSlackBot from "./forms/AccessConfigFieldsProvid
import AccessConfigFieldsProviderSpaceship from "./forms/AccessConfigFieldsProviderSpaceship";
import AccessConfigFieldsProviderSSH from "./forms/AccessConfigFieldsProviderSSH";
import AccessConfigFieldsProviderSSLCom from "./forms/AccessConfigFieldsProviderSSLCom";
+import AccessConfigFieldsProviderTechnitiumDNS from "./forms/AccessConfigFieldsProviderTechnitiumDNS";
import AccessConfigFieldsProviderTelegramBot from "./forms/AccessConfigFieldsProviderTelegramBot";
import AccessConfigFieldsProviderTencentCloud from "./forms/AccessConfigFieldsProviderTencentCloud";
import AccessConfigFieldsProviderUCloud from "./forms/AccessConfigFieldsProviderUCloud";
@@ -322,15 +323,18 @@ const AccessForm = ({ className, style, disabled, initialValues, mode, usage, on
case ACCESS_PROVIDERS.SPACESHIP: {
return