From 73c0ea08965a6ec93a799af4723f9aeaaf7526ae Mon Sep 17 00:00:00 2001 From: Linard Schwendener Date: Thu, 2 May 2024 21:39:34 +0200 Subject: [PATCH] POC DNS Challenge with Dynu --- src/acme.go | 35 ++++++++++++++++++--------------- src/mod/acme/acme.go | 41 +++++++++++++++++++++++++++++++++------ src/mod/acme/autorenew.go | 2 +- src/web/snippet/acme.html | 4 ++-- 4 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/acme.go b/src/acme.go index 4dd7cd4..0001199 100644 --- a/src/acme.go +++ b/src/acme.go @@ -85,23 +85,26 @@ func acmeRegisterSpecialRoutingRule() { // This function check if the renew setup is satisfied. If not, toggle them automatically func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request) { isForceHttpsRedirectEnabledOriginally := false - if dynamicProxyRouter.Option.Port == 443 { - //Enable port 80 to 443 redirect - if !dynamicProxyRouter.Option.ForceHttpsRedirect { - SystemWideLogger.Println("Temporary enabling HTTP to HTTPS redirect for ACME certificate renew requests") - dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true) + dnsPara, _ := utils.PostPara(r, "dns") + if dnsPara == "false" { + if dynamicProxyRouter.Option.Port == 443 { + //Enable port 80 to 443 redirect + if !dynamicProxyRouter.Option.ForceHttpsRedirect { + SystemWideLogger.Println("Temporary enabling HTTP to HTTPS redirect for ACME certificate renew requests") + dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true) + } else { + //Set this to true, so after renew, do not turn it off + isForceHttpsRedirectEnabledOriginally = true + } + + } else if dynamicProxyRouter.Option.Port == 80 { + //Go ahead + } else { - //Set this to true, so after renew, do not turn it off - isForceHttpsRedirectEnabledOriginally = true + //This port do not support ACME + utils.SendErrorResponse(w, "ACME renew only support web server listening on port 80 (http) or 443 (https)") + return } - - } else if dynamicProxyRouter.Option.Port == 80 { - //Go ahead - - } else { - //This port do not support ACME - utils.SendErrorResponse(w, "ACME renew only support web server listening on port 80 (http) or 443 (https)") - return } //Add a 3 second delay to make sure everything is settle down @@ -114,7 +117,7 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request) tlsCertManager.UpdateLoadedCertList() //Restore original settings - if dynamicProxyRouter.Option.Port == 443 { + if dynamicProxyRouter.Option.Port == 443 && dnsPara == "false" { if !isForceHttpsRedirectEnabledOriginally { //Default is off. Turn the redirection off SystemWideLogger.PrintAndLog("ACME", "Restoring HTTP to HTTPS redirect settings", nil) diff --git a/src/mod/acme/acme.go b/src/mod/acme/acme.go index a06e392..210ee92 100644 --- a/src/mod/acme/acme.go +++ b/src/mod/acme/acme.go @@ -24,6 +24,7 @@ import ( "github.com/go-acme/lego/v4/certificate" "github.com/go-acme/lego/v4/challenge/http01" "github.com/go-acme/lego/v4/lego" + "github.com/go-acme/lego/v4/providers/dns/dynu" "github.com/go-acme/lego/v4/registration" "imuslab.com/zoraxy/mod/database" "imuslab.com/zoraxy/mod/utils" @@ -33,6 +34,7 @@ type CertificateInfoJSON struct { AcmeName string `json:"acme_name"` AcmeUrl string `json:"acme_url"` SkipTLS bool `json:"skip_tls"` + DNS bool `json:"dns"` } // ACMEUser represents a user in the ACME system. @@ -79,7 +81,7 @@ func NewACME(acmeServer string, port string, database *database.Database) *ACMEH } // ObtainCert obtains a certificate for the specified domains. -func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email string, caName string, caUrl string, skipTLS bool) (bool, error) { +func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email string, caName string, caUrl string, skipTLS bool, dns bool) (bool, error) { log.Println("[ACME] Obtaining certificate...") // generate private key @@ -145,10 +147,26 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email } // setup how to receive challenge - err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", a.Port)) - if err != nil { - log.Println(err) - return false, err + if dns { + dynuConfig := dynu.NewDefaultConfig() + dynuConfig.APIKey = "yourApiKey" + + provider, err := dynu.NewDNSProviderConfig(dynuConfig) + if err != nil { + log.Fatal(err) + } + + err = client.Challenge.SetDNS01Provider(provider) + if err != nil { + log.Println(err) + return false, err + } + } else { + err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", a.Port)) + if err != nil { + log.Println(err) + return false, err + } } // New users will need to register @@ -241,6 +259,7 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email AcmeName: caName, AcmeUrl: caUrl, SkipTLS: skipTLS, + DNS: dns, } certInfoBytes, err := json.Marshal(certInfo) @@ -391,8 +410,18 @@ func (a *ACMEHandler) HandleRenewCertificate(w http.ResponseWriter, r *http.Requ skipTLS = true } + var dns bool + + if dnsString, err := utils.PostPara(r, "dns"); err != nil { + dns = false + } else if dnsString != "true" { + dns = false + } else { + dns = true + } + domains := strings.Split(domainPara, ",") - result, err := a.ObtainCert(domains, filename, email, ca, caUrl, skipTLS) + result, err := a.ObtainCert(domains, filename, email, ca, caUrl, skipTLS, dns) 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 24d2371..3ff2a69 100644 --- a/src/mod/acme/autorenew.go +++ b/src/mod/acme/autorenew.go @@ -356,7 +356,7 @@ func (a *AutoRenewer) renewExpiredDomains(certs []*ExpiredCerts) ([]string, erro } } - _, err = a.AcmeHandler.ObtainCert(expiredCert.Domains, certName, a.RenewerConfig.Email, certInfo.AcmeName, certInfo.AcmeUrl, certInfo.SkipTLS) + _, err = a.AcmeHandler.ObtainCert(expiredCert.Domains, certName, a.RenewerConfig.Email, certInfo.AcmeName, certInfo.AcmeUrl, certInfo.SkipTLS, certInfo.DNS) if err != nil { log.Println("Renew " + fileName + "(" + strings.Join(expiredCert.Domains, ",") + ") failed: " + err.Error()) } else { diff --git a/src/web/snippet/acme.html b/src/web/snippet/acme.html index 051e996..1f169ae 100644 --- a/src/web/snippet/acme.html +++ b/src/web/snippet/acme.html @@ -463,6 +463,8 @@ var dnsProvider = ""; var dnsCredentials = ""; if (dns) { + //Filename cannot contain wildcards, and wildcards are possible with DNS challenges + filename = filename.replace("*", "_"); dnsProvider = $("#dnsProvider").dropdown("get value"); dnsCredentials = $("#dnsCredentials").val(); } @@ -480,8 +482,6 @@ caURL: caURL, skipTLS: skipTLSValue, dns: dns, - dnsProvider: dnsProvider, - dnsCredentials: dnsCredentials, }, success: function(response) { $("#obtainButton").removeClass("loading").removeClass("disabled");