Skip to content

Commit

Permalink
Fixed #353 and #327
Browse files Browse the repository at this point in the history
- Added user defined polling and propagation timeout option in ACME
- Updated lego and added a few new DNS challenge providers
- Updated code gen to support new parameters
  • Loading branch information
tobychui committed Oct 27, 2024
1 parent 9a371f5 commit 5f64b62
Show file tree
Hide file tree
Showing 10 changed files with 1,547 additions and 1,197 deletions.
188 changes: 95 additions & 93 deletions src/go.mod

Large diffs are not rendered by default.

556 changes: 275 additions & 281 deletions src/go.sum

Large diffs are not rendered by default.

42 changes: 31 additions & 11 deletions src/mod/acme/acme.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ import (
)

type CertificateInfoJSON struct {
AcmeName string `json:"acme_name"`
AcmeUrl string `json:"acme_url"`
SkipTLS bool `json:"skip_tls"`
UseDNS bool `json:"dns"`
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
}

// ACMEUser represents a user in the ACME system.
Expand Down Expand Up @@ -86,7 +87,7 @@ func (a *ACMEHandler) Logf(message string, err 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) (bool, error) {
func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email string, caName string, caUrl string, skipTLS bool, useDNS bool, propagationTimeout int) (bool, error) {
a.Logf("Obtaining certificate for: "+strings.Join(domains, ", "), nil)

// generate private key
Expand Down Expand Up @@ -181,7 +182,7 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
return false, err
}

provider, err := GetDnsChallengeProviderByName(dnsProvider, dnsCredentials)
provider, err := GetDnsChallengeProviderByName(dnsProvider, dnsCredentials, propagationTimeout)
if err != nil {
a.Logf("Unable to resolve DNS challenge provider", err)
return false, err
Expand Down Expand Up @@ -285,10 +286,11 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email

// Save certificate's ACME info for renew usage
certInfo := &CertificateInfoJSON{
AcmeName: caName,
AcmeUrl: caUrl,
SkipTLS: skipTLS,
UseDNS: useDNS,
AcmeName: caName,
AcmeUrl: caUrl,
SkipTLS: skipTLS,
UseDNS: useDNS,
PropTimeout: propagationTimeout,
}

certInfoBytes, err := json.Marshal(certInfo)
Expand Down Expand Up @@ -452,12 +454,30 @@ func (a *ACMEHandler) HandleRenewCertificate(w http.ResponseWriter, r *http.Requ
}

domains := strings.Split(domainPara, ",")

// Default propagation timeout is 300 seconds
propagationTimeout := 300
if dns {
ppgTimeout, err := utils.PostPara(r, "ppgTimeout")
if err == nil {
propagationTimeout, err = strconv.Atoi(ppgTimeout)
if err != nil {
utils.SendErrorResponse(w, "Invalid propagation timeout value")
return
}
if propagationTimeout < 60 {
//Minimum propagation timeout is 60 seconds
propagationTimeout = 60
}
}
}

//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)
result, err := a.ObtainCert(cleanedDomains, filename, email, ca, caUrl, skipTLS, dns, propagationTimeout)
if err != nil {
utils.SendErrorResponse(w, jsonEscape(err.Error()))
return
Expand Down
90 changes: 38 additions & 52 deletions src/mod/acme/acme_dns.go
Original file line number Diff line number Diff line change
@@ -1,70 +1,56 @@
package acme

import (
"encoding/json"
"strconv"

"github.com/go-acme/lego/v4/challenge"
"imuslab.com/zoraxy/mod/acme/acmedns"
)

func GetDnsChallengeProviderByName(dnsProvider string, dnsCredentials string) (challenge.Provider, error) {

//Original Implementation
/*credentials, err := extractDnsCredentials(dnsCredentials)
// Preprocessor function to get DNS challenge provider by name
func GetDnsChallengeProviderByName(dnsProvider string, dnsCredentials string, ppgTimeout int) (challenge.Provider, error) {
//Unpack the dnsCredentials (json string) to map
var dnsCredentialsMap map[string]interface{}
err := json.Unmarshal([]byte(dnsCredentials), &dnsCredentialsMap)
if err != nil {
return nil, err
}
setCredentialsIntoEnvironmentVariables(credentials)
provider, err := dns.NewDNSChallengeProviderByName(dnsProvider)
*/

//New implementation using acmedns CICD pipeline generated datatype
return acmedns.GetDNSProviderByJsonConfig(dnsProvider, dnsCredentials)
}

/*
Original implementation of DNS ACME using OS.Env as payload
*/
/*
func setCredentialsIntoEnvironmentVariables(credentials map[string]string) {
for key, value := range credentials {
err := os.Setenv(key, value)
if err != nil {
log.Println("[ERR] Failed to set environment variable %s: %v", key, err)
} else {
log.Println("[INFO] Environment variable %s set successfully", key)
//Clear the PollingInterval and PropagationTimeout field and conert to int
userDefinedPollingInterval := 30
if dnsCredentialsMap["PollingInterval"] != nil {
userDefinedPollingIntervalRaw := dnsCredentialsMap["PollingInterval"].(string)
delete(dnsCredentialsMap, "PollingInterval")
convertedPollingInterval, err := strconv.Atoi(userDefinedPollingIntervalRaw)
if err == nil {
userDefinedPollingInterval = convertedPollingInterval
}
}
}
func extractDnsCredentials(input string) (map[string]string, error) {
result := make(map[string]string)

// Split the input string by newline character
lines := strings.Split(input, "\n")
// Iterate over each line
for _, line := range lines {
// Split the line by "=" character
//use SpliyN to make sure not to split the value if the value is base64
parts := strings.SplitN(line, "=", 1)
// Check if the line is in the correct format
if len(parts) == 2 {
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
// Add the key-value pair to the map
result[key] = value
if value == "" || key == "" {
//invalid config
return result, errors.New("DNS credential extract failed")
}
userDefinedPropagationTimeout := ppgTimeout
if dnsCredentialsMap["PropagationTimeout"] != nil {
userDefinedPropagationTimeoutRaw := dnsCredentialsMap["PropagationTimeout"].(string)
delete(dnsCredentialsMap, "PropagationTimeout")
convertedPropagationTimeout, err := strconv.Atoi(userDefinedPropagationTimeoutRaw)
if err == nil {
//Overwrite the default propagation timeout if it is requeted from UI
userDefinedPropagationTimeout = convertedPropagationTimeout
}
}

return result, nil
//Restructure dnsCredentials string from map
dnsCredentialsBytes, err := json.Marshal(dnsCredentialsMap)
if err != nil {
return nil, err
}
dnsCredentials = string(dnsCredentialsBytes)

//Using acmedns CICD pipeline generated datatype to optain the DNS provider
return acmedns.GetDNSProviderByJsonConfig(
dnsProvider,
dnsCredentials,
int64(userDefinedPropagationTimeout),
int64(userDefinedPollingInterval),
)
}
*/
Loading

0 comments on commit 5f64b62

Please sign in to comment.