修复AnyTLS无法配置证书的错误
This commit is contained in:
@@ -17,6 +17,8 @@ import (
|
||||
"github.com/libdns/acmedns"
|
||||
"github.com/libdns/alidns"
|
||||
"github.com/libdns/cloudflare"
|
||||
"github.com/libdns/dnspod"
|
||||
"github.com/libdns/tencentcloud"
|
||||
"github.com/mholt/acmez/v3/acme"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
@@ -81,7 +83,7 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound
|
||||
}
|
||||
if dnsOptions := options.DNS01Challenge; dnsOptions != nil && dnsOptions.Provider != "" {
|
||||
var solver certmagic.DNS01Solver
|
||||
switch dnsOptions.Provider {
|
||||
switch C.NormalizeACMEDNSProvider(dnsOptions.Provider) {
|
||||
case C.DNSProviderAliDNS:
|
||||
solver.DNSProvider = &alidns.Provider{
|
||||
CredentialInfo: alidns.CredentialInfo{
|
||||
@@ -96,6 +98,17 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound
|
||||
APIToken: dnsOptions.CloudflareOptions.APIToken,
|
||||
ZoneToken: dnsOptions.CloudflareOptions.ZoneToken,
|
||||
}
|
||||
case C.DNSProviderTencentCloud:
|
||||
solver.DNSProvider = &tencentcloud.Provider{
|
||||
SecretId: dnsOptions.TencentCloudOptions.SecretID,
|
||||
SecretKey: dnsOptions.TencentCloudOptions.SecretKey,
|
||||
SessionToken: dnsOptions.TencentCloudOptions.SessionToken,
|
||||
Region: dnsOptions.TencentCloudOptions.Region,
|
||||
}
|
||||
case C.DNSProviderDNSPod:
|
||||
solver.DNSProvider = &dnspod.Provider{
|
||||
APIToken: dnsOptions.DNSPodOptions.APIToken,
|
||||
}
|
||||
case C.DNSProviderACMEDNS:
|
||||
solver.DNSProvider = &acmedns.Provider{
|
||||
Username: dnsOptions.ACMEDNSOptions.Username,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package constant
|
||||
|
||||
import "strings"
|
||||
|
||||
const (
|
||||
DefaultDNSTTL = 600
|
||||
)
|
||||
@@ -33,4 +35,25 @@ const (
|
||||
DNSProviderAliDNS = "alidns"
|
||||
DNSProviderCloudflare = "cloudflare"
|
||||
DNSProviderACMEDNS = "acmedns"
|
||||
DNSProviderTencentCloud = "tencentcloud"
|
||||
DNSProviderDNSPod = "dnspod"
|
||||
)
|
||||
|
||||
func NormalizeACMEDNSProvider(provider string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(provider)) {
|
||||
case "", DNSProviderAliDNS, DNSProviderCloudflare, DNSProviderACMEDNS:
|
||||
return strings.ToLower(strings.TrimSpace(provider))
|
||||
case "aliyun":
|
||||
return DNSProviderAliDNS
|
||||
case "cf":
|
||||
return DNSProviderCloudflare
|
||||
case "acme-dns":
|
||||
return DNSProviderACMEDNS
|
||||
case "tencent", "tencentcloud", "dnspod-tencentcloud", "qcloud":
|
||||
return DNSProviderTencentCloud
|
||||
case "dnspod":
|
||||
return DNSProviderDNSPod
|
||||
default:
|
||||
return strings.ToLower(strings.TrimSpace(provider))
|
||||
}
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -20,7 +20,9 @@ require (
|
||||
github.com/libdns/acmedns v0.5.0
|
||||
github.com/libdns/alidns v1.0.6
|
||||
github.com/libdns/cloudflare v0.2.2
|
||||
github.com/libdns/dnspod v0.0.3
|
||||
github.com/libdns/libdns v1.1.1
|
||||
github.com/libdns/tencentcloud v1.4.3
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mdlayher/netlink v1.9.0
|
||||
github.com/metacubex/utls v1.8.4
|
||||
|
||||
@@ -28,34 +28,43 @@ type ACMECertificateProviderOptions struct {
|
||||
}
|
||||
|
||||
type _ACMEProviderDNS01ChallengeOptions struct {
|
||||
TTL badoption.Duration `json:"ttl,omitempty"`
|
||||
PropagationDelay badoption.Duration `json:"propagation_delay,omitempty"`
|
||||
PropagationTimeout badoption.Duration `json:"propagation_timeout,omitempty"`
|
||||
Resolvers badoption.Listable[string] `json:"resolvers,omitempty"`
|
||||
OverrideDomain string `json:"override_domain,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
AliDNSOptions ACMEDNS01AliDNSOptions `json:"-"`
|
||||
CloudflareOptions ACMEDNS01CloudflareOptions `json:"-"`
|
||||
ACMEDNSOptions ACMEDNS01ACMEDNSOptions `json:"-"`
|
||||
TTL badoption.Duration `json:"ttl,omitempty"`
|
||||
PropagationDelay badoption.Duration `json:"propagation_delay,omitempty"`
|
||||
PropagationTimeout badoption.Duration `json:"propagation_timeout,omitempty"`
|
||||
Resolvers badoption.Listable[string] `json:"resolvers,omitempty"`
|
||||
OverrideDomain string `json:"override_domain,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
AliDNSOptions ACMEDNS01AliDNSOptions `json:"-"`
|
||||
CloudflareOptions ACMEDNS01CloudflareOptions `json:"-"`
|
||||
ACMEDNSOptions ACMEDNS01ACMEDNSOptions `json:"-"`
|
||||
TencentCloudOptions ACMEDNS01TencentCloudOptions `json:"-"`
|
||||
DNSPodOptions ACMEDNS01DNSPodOptions `json:"-"`
|
||||
}
|
||||
|
||||
type ACMEProviderDNS01ChallengeOptions _ACMEProviderDNS01ChallengeOptions
|
||||
|
||||
func (o ACMEProviderDNS01ChallengeOptions) MarshalJSON() ([]byte, error) {
|
||||
provider := C.NormalizeACMEDNSProvider(o.Provider)
|
||||
var v any
|
||||
switch o.Provider {
|
||||
switch provider {
|
||||
case C.DNSProviderAliDNS:
|
||||
v = o.AliDNSOptions
|
||||
case C.DNSProviderCloudflare:
|
||||
v = o.CloudflareOptions
|
||||
case C.DNSProviderACMEDNS:
|
||||
v = o.ACMEDNSOptions
|
||||
case C.DNSProviderTencentCloud:
|
||||
v = o.TencentCloudOptions
|
||||
case C.DNSProviderDNSPod:
|
||||
v = o.DNSPodOptions
|
||||
case "":
|
||||
return nil, E.New("missing provider type")
|
||||
default:
|
||||
return nil, E.New("unknown provider type: ", o.Provider)
|
||||
}
|
||||
return badjson.MarshallObjects((_ACMEProviderDNS01ChallengeOptions)(o), v)
|
||||
copyValue := (_ACMEProviderDNS01ChallengeOptions)(o)
|
||||
copyValue.Provider = provider
|
||||
return badjson.MarshallObjects(copyValue, v)
|
||||
}
|
||||
|
||||
func (o *ACMEProviderDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||
@@ -63,6 +72,7 @@ func (o *ACMEProviderDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Provider = C.NormalizeACMEDNSProvider(o.Provider)
|
||||
var v any
|
||||
switch o.Provider {
|
||||
case C.DNSProviderAliDNS:
|
||||
@@ -71,6 +81,10 @@ func (o *ACMEProviderDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||
v = &o.CloudflareOptions
|
||||
case C.DNSProviderACMEDNS:
|
||||
v = &o.ACMEDNSOptions
|
||||
case C.DNSProviderTencentCloud:
|
||||
v = &o.TencentCloudOptions
|
||||
case C.DNSProviderDNSPod:
|
||||
v = &o.DNSPodOptions
|
||||
case "":
|
||||
return E.New("missing provider type")
|
||||
default:
|
||||
|
||||
@@ -28,29 +28,38 @@ type ACMEExternalAccountOptions struct {
|
||||
}
|
||||
|
||||
type _ACMEDNS01ChallengeOptions struct {
|
||||
Provider string `json:"provider,omitempty"`
|
||||
AliDNSOptions ACMEDNS01AliDNSOptions `json:"-"`
|
||||
CloudflareOptions ACMEDNS01CloudflareOptions `json:"-"`
|
||||
ACMEDNSOptions ACMEDNS01ACMEDNSOptions `json:"-"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
AliDNSOptions ACMEDNS01AliDNSOptions `json:"-"`
|
||||
CloudflareOptions ACMEDNS01CloudflareOptions `json:"-"`
|
||||
ACMEDNSOptions ACMEDNS01ACMEDNSOptions `json:"-"`
|
||||
TencentCloudOptions ACMEDNS01TencentCloudOptions `json:"-"`
|
||||
DNSPodOptions ACMEDNS01DNSPodOptions `json:"-"`
|
||||
}
|
||||
|
||||
type ACMEDNS01ChallengeOptions _ACMEDNS01ChallengeOptions
|
||||
|
||||
func (o ACMEDNS01ChallengeOptions) MarshalJSON() ([]byte, error) {
|
||||
provider := C.NormalizeACMEDNSProvider(o.Provider)
|
||||
var v any
|
||||
switch o.Provider {
|
||||
switch provider {
|
||||
case C.DNSProviderAliDNS:
|
||||
v = o.AliDNSOptions
|
||||
case C.DNSProviderCloudflare:
|
||||
v = o.CloudflareOptions
|
||||
case C.DNSProviderACMEDNS:
|
||||
v = o.ACMEDNSOptions
|
||||
case C.DNSProviderTencentCloud:
|
||||
v = o.TencentCloudOptions
|
||||
case C.DNSProviderDNSPod:
|
||||
v = o.DNSPodOptions
|
||||
case "":
|
||||
return nil, E.New("missing provider type")
|
||||
default:
|
||||
return nil, E.New("unknown provider type: " + o.Provider)
|
||||
}
|
||||
return badjson.MarshallObjects((_ACMEDNS01ChallengeOptions)(o), v)
|
||||
copyValue := (_ACMEDNS01ChallengeOptions)(o)
|
||||
copyValue.Provider = provider
|
||||
return badjson.MarshallObjects(copyValue, v)
|
||||
}
|
||||
|
||||
func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||
@@ -58,6 +67,7 @@ func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Provider = C.NormalizeACMEDNSProvider(o.Provider)
|
||||
var v any
|
||||
switch o.Provider {
|
||||
case C.DNSProviderAliDNS:
|
||||
@@ -66,6 +76,10 @@ func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||
v = &o.CloudflareOptions
|
||||
case C.DNSProviderACMEDNS:
|
||||
v = &o.ACMEDNSOptions
|
||||
case C.DNSProviderTencentCloud:
|
||||
v = &o.TencentCloudOptions
|
||||
case C.DNSProviderDNSPod:
|
||||
v = &o.DNSPodOptions
|
||||
default:
|
||||
return E.New("unknown provider type: " + o.Provider)
|
||||
}
|
||||
@@ -94,3 +108,14 @@ type ACMEDNS01ACMEDNSOptions struct {
|
||||
Subdomain string `json:"subdomain,omitempty"`
|
||||
ServerURL string `json:"server_url,omitempty"`
|
||||
}
|
||||
|
||||
type ACMEDNS01TencentCloudOptions struct {
|
||||
SecretID string `json:"secret_id,omitempty"`
|
||||
SecretKey string `json:"secret_key,omitempty"`
|
||||
SessionToken string `json:"session_token,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
}
|
||||
|
||||
type ACMEDNS01DNSPodOptions struct {
|
||||
APIToken string `json:"api_token,omitempty"`
|
||||
}
|
||||
|
||||
@@ -30,7 +30,9 @@ import (
|
||||
"github.com/caddyserver/zerossl"
|
||||
"github.com/libdns/alidns"
|
||||
"github.com/libdns/cloudflare"
|
||||
"github.com/libdns/dnspod"
|
||||
"github.com/libdns/libdns"
|
||||
"github.com/libdns/tencentcloud"
|
||||
"github.com/mholt/acmez/v3/acme"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
@@ -224,7 +226,7 @@ func newDNSSolver(dnsOptions *option.ACMEProviderDNS01ChallengeOptions, logger *
|
||||
Logger: logger.Named("dns_manager"),
|
||||
},
|
||||
}
|
||||
switch dnsOptions.Provider {
|
||||
switch C.NormalizeACMEDNSProvider(dnsOptions.Provider) {
|
||||
case C.DNSProviderAliDNS:
|
||||
solver.DNSProvider = &alidns.Provider{
|
||||
CredentialInfo: alidns.CredentialInfo{
|
||||
@@ -240,6 +242,17 @@ func newDNSSolver(dnsOptions *option.ACMEProviderDNS01ChallengeOptions, logger *
|
||||
ZoneToken: dnsOptions.CloudflareOptions.ZoneToken,
|
||||
HTTPClient: httpClient,
|
||||
}
|
||||
case C.DNSProviderTencentCloud:
|
||||
solver.DNSProvider = &tencentcloud.Provider{
|
||||
SecretId: dnsOptions.TencentCloudOptions.SecretID,
|
||||
SecretKey: dnsOptions.TencentCloudOptions.SecretKey,
|
||||
SessionToken: dnsOptions.TencentCloudOptions.SessionToken,
|
||||
Region: dnsOptions.TencentCloudOptions.Region,
|
||||
}
|
||||
case C.DNSProviderDNSPod:
|
||||
solver.DNSProvider = &dnspod.Provider{
|
||||
APIToken: dnsOptions.DNSPodOptions.APIToken,
|
||||
}
|
||||
case C.DNSProviderACMEDNS:
|
||||
solver.DNSProvider = &acmeDNSProvider{
|
||||
username: dnsOptions.ACMEDNSOptions.Username,
|
||||
|
||||
@@ -467,9 +467,9 @@ func hasUsableServerTLS(tlsOptions option.InboundTLSOptions) bool {
|
||||
(len(tlsOptions.Certificate) > 0 && len(tlsOptions.Key) > 0)
|
||||
}
|
||||
|
||||
func applyACMEConfig(tlsOptions *option.InboundTLSOptions, certConfig *XCertConfig, autoTLS bool, domain string, listenPort int) bool {
|
||||
func applyACMEConfigDetailed(tlsOptions *option.InboundTLSOptions, certConfig *XCertConfig, autoTLS bool, domain string, listenPort int) (bool, string) {
|
||||
if !autoTLS && certConfig == nil {
|
||||
return false
|
||||
return false, "acme disabled: no auto_tls and no cert_config"
|
||||
}
|
||||
mode := ""
|
||||
if certConfig != nil {
|
||||
@@ -479,54 +479,98 @@ func applyACMEConfig(tlsOptions *option.InboundTLSOptions, certConfig *XCertConf
|
||||
mode = "http"
|
||||
}
|
||||
if mode != "http" && mode != "dns" {
|
||||
return false
|
||||
return false, "unsupported cert_mode: " + mode
|
||||
}
|
||||
domain = strings.TrimSpace(domain)
|
||||
if domain == "" {
|
||||
return false
|
||||
return false, "missing domain/server_name for ACME"
|
||||
}
|
||||
|
||||
acmeOptions := &option.InboundACMEOptions{
|
||||
Domain: badoption.Listable[string]{domain},
|
||||
DataDirectory: "acme",
|
||||
DefaultServerName: domain,
|
||||
DisableHTTPChallenge: true,
|
||||
Domain: badoption.Listable[string]{domain},
|
||||
DataDirectory: "acme",
|
||||
DefaultServerName: domain,
|
||||
}
|
||||
if certConfig != nil {
|
||||
acmeOptions.Email = strings.TrimSpace(certConfig.Email)
|
||||
}
|
||||
if listenPort > 0 && listenPort != 443 {
|
||||
acmeOptions.AlternativeTLSPort = uint16(listenPort)
|
||||
}
|
||||
if mode == "dns" && certConfig != nil {
|
||||
dnsProvider := strings.ToLower(strings.TrimSpace(certConfig.DNSProvider))
|
||||
if dnsProvider == "" {
|
||||
return false
|
||||
switch mode {
|
||||
case "http":
|
||||
acmeOptions.DisableHTTPChallenge = false
|
||||
acmeOptions.DisableTLSALPNChallenge = true
|
||||
if certConfig != nil && certConfig.HTTPPort > 0 && certConfig.HTTPPort != 80 {
|
||||
acmeOptions.AlternativeHTTPPort = uint16(certConfig.HTTPPort)
|
||||
}
|
||||
case "dns":
|
||||
acmeOptions.DisableHTTPChallenge = true
|
||||
acmeOptions.DisableTLSALPNChallenge = true
|
||||
if listenPort > 0 && listenPort != 443 {
|
||||
acmeOptions.AlternativeTLSPort = uint16(listenPort)
|
||||
}
|
||||
}
|
||||
if mode == "dns" && certConfig != nil {
|
||||
dnsProvider := C.NormalizeACMEDNSProvider(certConfig.DNSProvider)
|
||||
if dnsProvider == "" {
|
||||
return false, "missing dns_provider for cert_mode=dns"
|
||||
}
|
||||
dns01 := &option.ACMEDNS01ChallengeOptions{Provider: dnsProvider}
|
||||
switch dnsProvider {
|
||||
case C.DNSProviderCloudflare:
|
||||
dns01.CloudflareOptions.APIToken = firstNonEmpty(certConfig.DNSEnv["CF_API_TOKEN"], certConfig.DNSEnv["CLOUDFLARE_API_TOKEN"])
|
||||
dns01.CloudflareOptions.ZoneToken = firstNonEmpty(certConfig.DNSEnv["CF_ZONE_TOKEN"], certConfig.DNSEnv["CLOUDFLARE_ZONE_TOKEN"])
|
||||
if dns01.CloudflareOptions.APIToken == "" && dns01.CloudflareOptions.ZoneToken == "" {
|
||||
return false, "cloudflare dns challenge requires CF_API_TOKEN/CLOUDFLARE_API_TOKEN or CF_ZONE_TOKEN/CLOUDFLARE_ZONE_TOKEN"
|
||||
}
|
||||
case C.DNSProviderAliDNS:
|
||||
dns01.AliDNSOptions.AccessKeyID = firstNonEmpty(certConfig.DNSEnv["ALICLOUD_ACCESS_KEY_ID"], certConfig.DNSEnv["ALI_ACCESS_KEY_ID"])
|
||||
dns01.AliDNSOptions.AccessKeySecret = firstNonEmpty(certConfig.DNSEnv["ALICLOUD_ACCESS_KEY_SECRET"], certConfig.DNSEnv["ALI_ACCESS_KEY_SECRET"])
|
||||
dns01.AliDNSOptions.RegionID = firstNonEmpty(certConfig.DNSEnv["ALICLOUD_REGION_ID"], certConfig.DNSEnv["ALI_REGION_ID"])
|
||||
dns01.AliDNSOptions.SecurityToken = firstNonEmpty(certConfig.DNSEnv["ALICLOUD_SECURITY_TOKEN"], certConfig.DNSEnv["ALI_SECURITY_TOKEN"])
|
||||
if dns01.AliDNSOptions.AccessKeyID == "" || dns01.AliDNSOptions.AccessKeySecret == "" {
|
||||
return false, "alidns dns challenge requires ALICLOUD_ACCESS_KEY_ID and ALICLOUD_ACCESS_KEY_SECRET"
|
||||
}
|
||||
case C.DNSProviderTencentCloud:
|
||||
dns01.TencentCloudOptions.SecretID = firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_SECRET_ID"], certConfig.DNSEnv["TENCENT_SECRET_ID"], certConfig.DNSEnv["SECRET_ID"])
|
||||
dns01.TencentCloudOptions.SecretKey = firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_SECRET_KEY"], certConfig.DNSEnv["TENCENT_SECRET_KEY"], certConfig.DNSEnv["SECRET_KEY"])
|
||||
dns01.TencentCloudOptions.SessionToken = firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_SESSION_TOKEN"], certConfig.DNSEnv["TENCENT_SESSION_TOKEN"], certConfig.DNSEnv["SESSION_TOKEN"])
|
||||
dns01.TencentCloudOptions.Region = firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_REGION"], certConfig.DNSEnv["TENCENT_REGION"], certConfig.DNSEnv["REGION"])
|
||||
if dns01.TencentCloudOptions.SecretID == "" || dns01.TencentCloudOptions.SecretKey == "" {
|
||||
return false, "tencentcloud dns challenge requires TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY"
|
||||
}
|
||||
case C.DNSProviderDNSPod:
|
||||
dns01.DNSPodOptions.APIToken = firstNonEmpty(certConfig.DNSEnv["DNSPOD_TOKEN"], certConfig.DNSEnv["API_TOKEN"])
|
||||
if dns01.DNSPodOptions.APIToken == "" {
|
||||
tencentSecretID := firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_SECRET_ID"], certConfig.DNSEnv["TENCENT_SECRET_ID"], certConfig.DNSEnv["SECRET_ID"])
|
||||
tencentSecretKey := firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_SECRET_KEY"], certConfig.DNSEnv["TENCENT_SECRET_KEY"], certConfig.DNSEnv["SECRET_KEY"])
|
||||
if tencentSecretID == "" || tencentSecretKey == "" {
|
||||
return false, "dnspod dns challenge requires DNSPOD_TOKEN or TencentCloud SecretID/SecretKey"
|
||||
}
|
||||
dns01.Provider = C.DNSProviderTencentCloud
|
||||
dns01.TencentCloudOptions.SecretID = tencentSecretID
|
||||
dns01.TencentCloudOptions.SecretKey = tencentSecretKey
|
||||
dns01.TencentCloudOptions.SessionToken = firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_SESSION_TOKEN"], certConfig.DNSEnv["TENCENT_SESSION_TOKEN"], certConfig.DNSEnv["SESSION_TOKEN"])
|
||||
dns01.TencentCloudOptions.Region = firstNonEmpty(certConfig.DNSEnv["TENCENTCLOUD_REGION"], certConfig.DNSEnv["TENCENT_REGION"], certConfig.DNSEnv["REGION"])
|
||||
}
|
||||
case C.DNSProviderACMEDNS:
|
||||
dns01.ACMEDNSOptions.Username = certConfig.DNSEnv["ACMEDNS_USERNAME"]
|
||||
dns01.ACMEDNSOptions.Password = certConfig.DNSEnv["ACMEDNS_PASSWORD"]
|
||||
dns01.ACMEDNSOptions.Subdomain = certConfig.DNSEnv["ACMEDNS_SUBDOMAIN"]
|
||||
dns01.ACMEDNSOptions.ServerURL = certConfig.DNSEnv["ACMEDNS_SERVER_URL"]
|
||||
if dns01.ACMEDNSOptions.Username == "" || dns01.ACMEDNSOptions.Password == "" || dns01.ACMEDNSOptions.Subdomain == "" || dns01.ACMEDNSOptions.ServerURL == "" {
|
||||
return false, "acmedns dns challenge requires username, password, subdomain and server_url"
|
||||
}
|
||||
default:
|
||||
return false
|
||||
return false, "unsupported dns_provider: " + dnsProvider
|
||||
}
|
||||
acmeOptions.DNS01Challenge = dns01
|
||||
}
|
||||
tlsOptions.ACME = acmeOptions
|
||||
return true
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func applyACMEConfig(tlsOptions *option.InboundTLSOptions, certConfig *XCertConfig, autoTLS bool, domain string, listenPort int) bool {
|
||||
ok, _ := applyACMEConfigDetailed(tlsOptions, certConfig, autoTLS, domain, listenPort)
|
||||
return ok
|
||||
}
|
||||
|
||||
func mergedTLSSettings(inner XInnerConfig, config *XNodeConfig) *XTLSSettings {
|
||||
@@ -1067,11 +1111,12 @@ func (s *Service) setupNode() error {
|
||||
autoTLSDomain = tlsSettings.ServerName
|
||||
}
|
||||
hasACME := false
|
||||
acmeReason := ""
|
||||
if !hasCertificate {
|
||||
hasACME = applyACMEConfig(&tlsOptions, certConfig, inner.AutoTLS || configAutoTLS, autoTLSDomain, inner.Port)
|
||||
hasACME, acmeReason = applyACMEConfigDetailed(&tlsOptions, certConfig, inner.AutoTLS || configAutoTLS, autoTLSDomain, inner.Port)
|
||||
}
|
||||
if certConfig != nil && !hasCertificate && !hasACME && certConfig.CertMode != "" && certConfig.CertMode != "none" {
|
||||
s.logger.Warn("Xboard cert_config present but unsupported or incomplete for local TLS. cert_mode=", certConfig.CertMode)
|
||||
s.logger.Warn("Xboard cert_config present but unsupported or incomplete for local TLS. cert_mode=", certConfig.CertMode, ", reason=", acmeReason)
|
||||
}
|
||||
if hasACME {
|
||||
s.logger.Info("Xboard ACME configured for domain ", autoTLSDomain)
|
||||
|
||||
@@ -3,6 +3,7 @@ package xboard
|
||||
import (
|
||||
"testing"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
)
|
||||
@@ -158,11 +159,11 @@ func TestApplyACMEConfigFromAutoTLS(t *testing.T) {
|
||||
if len(tlsOptions.ACME.Domain) != 1 || tlsOptions.ACME.Domain[0] != "example.com" {
|
||||
t.Fatalf("ACME domains = %+v", tlsOptions.ACME.Domain)
|
||||
}
|
||||
if tlsOptions.ACME.AlternativeTLSPort != 8443 {
|
||||
t.Fatalf("AlternativeTLSPort = %d, want 8443", tlsOptions.ACME.AlternativeTLSPort)
|
||||
if tlsOptions.ACME.DisableHTTPChallenge {
|
||||
t.Fatal("DisableHTTPChallenge should be false for auto_tls/http mode")
|
||||
}
|
||||
if !tlsOptions.ACME.DisableHTTPChallenge {
|
||||
t.Fatal("DisableHTTPChallenge should be true for inline ACME")
|
||||
if !tlsOptions.ACME.DisableTLSALPNChallenge {
|
||||
t.Fatal("DisableTLSALPNChallenge should be true for auto_tls/http mode")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +194,71 @@ func TestApplyACMEConfigFromDNSCertMode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyACMEConfigFromTencentCloudDNSCertMode(t *testing.T) {
|
||||
var tlsOptions option.InboundTLSOptions
|
||||
ok := applyACMEConfig(&tlsOptions, &XCertConfig{
|
||||
CertMode: "dns",
|
||||
Domain: "code.littlediary.cn",
|
||||
DNSProvider: "tencentcloud",
|
||||
DNSEnv: map[string]string{
|
||||
"TENCENTCLOUD_SECRET_ID": "sid",
|
||||
"TENCENTCLOUD_SECRET_KEY": "skey",
|
||||
},
|
||||
}, false, "code.littlediary.cn", 45365)
|
||||
if !ok {
|
||||
t.Fatal("applyACMEConfig() returned false")
|
||||
}
|
||||
if tlsOptions.ACME == nil || tlsOptions.ACME.DNS01Challenge == nil {
|
||||
t.Fatal("DNS01Challenge not configured")
|
||||
}
|
||||
if tlsOptions.ACME.DNS01Challenge.Provider != C.DNSProviderTencentCloud {
|
||||
t.Fatalf("DNS provider = %q", tlsOptions.ACME.DNS01Challenge.Provider)
|
||||
}
|
||||
if tlsOptions.ACME.DNS01Challenge.TencentCloudOptions.SecretID != "sid" {
|
||||
t.Fatalf("TencentCloud SecretID = %q", tlsOptions.ACME.DNS01Challenge.TencentCloudOptions.SecretID)
|
||||
}
|
||||
if tlsOptions.ACME.DNS01Challenge.TencentCloudOptions.SecretKey != "skey" {
|
||||
t.Fatalf("TencentCloud SecretKey = %q", tlsOptions.ACME.DNS01Challenge.TencentCloudOptions.SecretKey)
|
||||
}
|
||||
if tlsOptions.ACME.AlternativeTLSPort != 45365 {
|
||||
t.Fatalf("AlternativeTLSPort = %d, want 45365", tlsOptions.ACME.AlternativeTLSPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyACMEConfigFromDNSPodAliasWithTencentCredentials(t *testing.T) {
|
||||
var tlsOptions option.InboundTLSOptions
|
||||
ok := applyACMEConfig(&tlsOptions, &XCertConfig{
|
||||
CertMode: "dns",
|
||||
Domain: "code.littlediary.cn",
|
||||
DNSProvider: "dnspod",
|
||||
DNSEnv: map[string]string{
|
||||
"TENCENTCLOUD_SECRET_ID": "sid",
|
||||
"TENCENTCLOUD_SECRET_KEY": "skey",
|
||||
},
|
||||
}, false, "code.littlediary.cn", 443)
|
||||
if !ok {
|
||||
t.Fatal("applyACMEConfig() returned false")
|
||||
}
|
||||
if tlsOptions.ACME == nil || tlsOptions.ACME.DNS01Challenge == nil {
|
||||
t.Fatal("DNS01Challenge not configured")
|
||||
}
|
||||
if tlsOptions.ACME.DNS01Challenge.Provider != C.DNSProviderTencentCloud {
|
||||
t.Fatalf("DNS provider = %q, want %q", tlsOptions.ACME.DNS01Challenge.Provider, C.DNSProviderTencentCloud)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergedTLSSettingsUsesTopLevelServerName(t *testing.T) {
|
||||
tlsSettings := mergedTLSSettings(XInnerConfig{}, &XNodeConfig{
|
||||
ServerName: "code.littlediary.cn",
|
||||
})
|
||||
if tlsSettings == nil {
|
||||
t.Fatal("mergedTLSSettings() returned nil")
|
||||
}
|
||||
if tlsSettings.ServerName != "code.littlediary.cn" {
|
||||
t.Fatalf("ServerName = %q, want %q", tlsSettings.ServerName, "code.littlediary.cn")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasUsableServerTLS(t *testing.T) {
|
||||
if hasUsableServerTLS(option.InboundTLSOptions{}) {
|
||||
t.Fatal("empty TLS options should not be usable")
|
||||
|
||||
Reference in New Issue
Block a user