From e6b2d458f702656cb11f2bf40767f1f8bf218275 Mon Sep 17 00:00:00 2001 From: sickjuicy Date: Tue, 26 Nov 2024 23:30:24 +0100 Subject: [PATCH] Added Custom Name Server Option --- src/mod/acme/acme.go | 50 +++++++++++++++++++++------------------ src/mod/acme/autorenew.go | 13 ++++++---- src/web/snippet/acme.html | 36 +++++++++++----------------- 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/mod/acme/acme.go b/src/mod/acme/acme.go index d380856..9c3c0d7 100644 --- a/src/mod/acme/acme.go +++ b/src/mod/acme/acme.go @@ -21,6 +21,7 @@ import ( "github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/certificate" + "github.com/go-acme/lego/v4/challenge/dns01" "github.com/go-acme/lego/v4/challenge/http01" "github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/registration" @@ -30,11 +31,12 @@ import ( ) type CertificateInfoJSON struct { - AcmeName string `json:"acme_name"` //ACME provider name - AcmeUrl string `json:"acme_url"` //Custom ACME URL (if any) - SkipTLS bool `json:"skip_tls"` //Skip TLS verification of upstream - UseDNS bool `json:"dns"` //Use DNS challenge - PropTimeout int `json:"prop_time"` //Propagation timeout + AcmeName string `json:"acme_name"` //ACME provider name + AcmeUrl string `json:"acme_url"` //Custom ACME URL (if any) + SkipTLS bool `json:"skip_tls"` //Skip TLS verification of upstream + UseDNS bool `json:"dns"` //Use DNS challenge + PropTimeout int `json:"prop_time"` //Propagation timeout + DNSServers []string `json:"dnsServers"` // DNS servers } // ACMEUser represents a user in the ACME system. @@ -94,7 +96,7 @@ func (a *ACMEHandler) Close() error { } // ObtainCert obtains a certificate for the specified domains. -func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email string, caName string, caUrl string, skipTLS bool, useDNS bool, propagationTimeout int) (bool, error) { +func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email string, caName string, caUrl string, skipTLS bool, useDNS bool, propagationTimeout int, dnsServers []string) (bool, error) { a.Logf("Obtaining certificate for: "+strings.Join(domains, ", "), nil) // generate private key @@ -114,7 +116,6 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email config := lego.NewConfig(&adminUser) // skip TLS verify if need - // Ref: https://github.com/go-acme/lego/blob/6af2c756ac73a9cb401621afca722d0f4112b1b8/lego/client_config.go#L74 if skipTLS { a.Logf("Ignoring TLS/SSL Verification Error for ACME Server", nil) config.HTTPClient.Transport = &http.Transport{ @@ -150,7 +151,6 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email config.CADirURL = caLinkOverwrite a.Logf("Using "+caLinkOverwrite+" for CA Directory URL", nil) } else { - // (caName == "" || caUrl == "") will use default acme config.CADirURL = a.DefaultAcmeServer a.Logf("Using Default ACME "+a.DefaultAcmeServer+" for CA Directory URL", nil) } @@ -168,11 +168,11 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email if useDNS { if !a.Database.TableExists("acme") { a.Database.NewTable("acme") - return false, errors.New("DNS Provider and DNS Credenital configuration required for ACME Provider (Error -1)") + return false, errors.New("DNS Provider and DNS Credential configuration required for ACME Provider (Error -1)") } if !a.Database.KeyExists("acme", certificateName+"_dns_provider") || !a.Database.KeyExists("acme", certificateName+"_dns_credentials") { - return false, errors.New("DNS Provider and DNS Credenital configuration required for ACME Provider (Error -2)") + return false, errors.New("DNS Provider and DNS Credential configuration required for ACME Provider (Error -2)") } var dnsCredentials string @@ -195,7 +195,11 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email return false, err } - err = client.Challenge.SetDNS01Provider(provider) + if len(dnsServers) > 0 { + err = client.Challenge.SetDNS01Provider(provider, dns01.AddRecursiveNameservers(dnsServers)) + } else { + err = client.Challenge.SetDNS01Provider(provider) + } if err != nil { a.Logf("Failed to resolve DNS01 Provider", err) return false, err @@ -209,19 +213,9 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email } // New users will need to register - /* - reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) - if err != nil { - log.Println(err) - return false, err - } - */ var reg *registration.Resource - // New users will need to register if client.GetExternalAccountRequired() { a.Logf("External Account Required for this ACME Provider", nil) - // IF KID and HmacEncoded is overidden - if !a.Database.TableExists("acme") { a.Database.NewTable("acme") return false, errors.New("kid and HmacEncoded configuration required for ACME Provider (Error -1)") @@ -257,7 +251,6 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email a.Logf("Register with external account binder failed", err) return false, err } - //return false, errors.New("External Account Required for this ACME Provider.") } else { reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) if err != nil { @@ -298,6 +291,7 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email SkipTLS: skipTLS, UseDNS: useDNS, PropTimeout: propagationTimeout, + DNSServers: dnsServers, } certInfoBytes, err := json.Marshal(certInfo) @@ -479,12 +473,22 @@ func (a *ACMEHandler) HandleRenewCertificate(w http.ResponseWriter, r *http.Requ } } + // Extract DNS servers from the request + var dnsServers []string + dnsServersPara, err := utils.PostPara(r, "dnsServers") + if err == nil && dnsServersPara != "" { + dnsServers = strings.Split(dnsServersPara, ",") + for i := range dnsServers { + dnsServers[i] = strings.TrimSpace(dnsServers[i]) + } + } + //Clean spaces in front or behind each domain cleanedDomains := []string{} for _, domain := range domains { cleanedDomains = append(cleanedDomains, strings.TrimSpace(domain)) } - result, err := a.ObtainCert(cleanedDomains, filename, email, ca, caUrl, skipTLS, dns, propagationTimeout) + result, err := a.ObtainCert(cleanedDomains, filename, email, ca, caUrl, skipTLS, dns, propagationTimeout, dnsServers) if err != nil { utils.SendErrorResponse(w, jsonEscape(err.Error())) return diff --git a/src/mod/acme/autorenew.go b/src/mod/acme/autorenew.go index b470da6..3d08b2b 100644 --- a/src/mod/acme/autorenew.go +++ b/src/mod/acme/autorenew.go @@ -354,7 +354,6 @@ func (a *AutoRenewer) CheckAndRenewCertificates() ([]string, error) { return a.renewExpiredDomains(expiredCertList) } -// Close the auto renewer func (a *AutoRenewer) Close() { if a.TickerstopChan != nil { a.TickerstopChan <- true @@ -384,13 +383,19 @@ func (a *AutoRenewer) renewExpiredDomains(certs []*ExpiredCerts) ([]string, erro } } - //For upgrading config from older version of Zoraxy which don't have timeout + // For upgrading config from older version of Zoraxy which don't have timeout if certInfo.PropTimeout == 0 { - //Set default timeout + // Set default timeout certInfo.PropTimeout = 300 } - _, err = a.AcmeHandler.ObtainCert(expiredCert.Domains, certName, a.RenewerConfig.Email, certInfo.AcmeName, certInfo.AcmeUrl, certInfo.SkipTLS, certInfo.UseDNS, certInfo.PropTimeout) + // Extract DNS servers from the certificate info if available + var dnsServers []string + if certInfo.DNSServers != nil { + dnsServers = certInfo.DNSServers + } + + _, err = a.AcmeHandler.ObtainCert(expiredCert.Domains, certName, a.RenewerConfig.Email, certInfo.AcmeName, certInfo.AcmeUrl, certInfo.SkipTLS, certInfo.UseDNS, certInfo.PropTimeout, dnsServers) if err != nil { a.Logf("Renew "+fileName+"("+strings.Join(expiredCert.Domains, ",")+") failed", err) } else { diff --git a/src/web/snippet/acme.html b/src/web/snippet/acme.html index ac4f03f..a070b3b 100644 --- a/src/web/snippet/acme.html +++ b/src/web/snippet/acme.html @@ -25,8 +25,6 @@ - -
@@ -52,7 +50,7 @@

ACME Email

If you don't want to share your private email address, you can also fill in an email address that point to a mailbox not exists on your domain.
-
+
@@ -137,6 +135,13 @@

Generate New Certificate

+
+
+ + + If you have more than one DNS server, enter them separated by commas (e.g. ns1.example.com,ns2.example.com) + +