feat: Potentially handle renewing certificates

This commit is contained in:
PapaTutuWawa 2024-01-01 14:47:13 +01:00
parent 3af3f6bb7e
commit d0a24a60ed
5 changed files with 57 additions and 20 deletions

6
.gitignore vendored
View File

@ -1 +1,5 @@
./rio # Artificats
rio
# Testing stuff
*.json

View File

@ -18,6 +18,35 @@ import (
"github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/lego"
) )
func RenewCertificate(old *CertificateWrapper, acmeClient *lego.Client) (CertificateWrapper, error) {
pk, _ := base64.StdEncoding.DecodeString(old.PrivateKeyEncoded)
res := certificate.Resource{
PrivateKey: pk,
Certificate: old.Certificate,
CSR: old.CSR,
}
new, err := acmeClient.Certificate.Renew(res, true, false, "")
if err != nil {
return CertificateWrapper{}, err
}
// Convert the new certificate into a wrapper struct
tlsCert, err := tls.X509KeyPair(new.Certificate, new.PrivateKey)
if err != nil {
return CertificateWrapper{}, err
}
wrapper := CertificateWrapper{
TlsCertificate: &tlsCert,
Domain: old.Domain,
NotAfter: time.Now().Add(time.Hour * 24 * 60),
PrivateKeyEncoded: base64.StdEncoding.EncodeToString(new.PrivateKey),
Certificate: new.Certificate,
CSR: new.CSR,
}
return wrapper, nil
}
func ObtainNewCertificate(domains []string, acmeClient *lego.Client) (CertificateWrapper, error) { func ObtainNewCertificate(domains []string, acmeClient *lego.Client) (CertificateWrapper, error) {
req := certificate.ObtainRequest{ req := certificate.ObtainRequest{
Domains: domains, Domains: domains,
@ -40,8 +69,7 @@ func ObtainNewCertificate(domains []string, acmeClient *lego.Client) (Certificat
NotAfter: time.Now().Add(time.Hour * 24 * 60), NotAfter: time.Now().Add(time.Hour * 24 * 60),
PrivateKeyEncoded: base64.StdEncoding.EncodeToString(cert.PrivateKey), PrivateKeyEncoded: base64.StdEncoding.EncodeToString(cert.PrivateKey),
Certificate: cert.Certificate, Certificate: cert.Certificate,
IssuerCertificate: cert.IssuerCertificate, CSR: cert.CSR,
CertificateUrl: cert.CertURL,
} }
return wrapper, nil return wrapper, nil
} }
@ -103,7 +131,6 @@ func MakeFallbackCertificate(pagesDomain string) (*CertificateWrapper, error) {
NotAfter: notAfter, NotAfter: notAfter,
PrivateKeyEncoded: base64.StdEncoding.EncodeToString(certcrypto.PEMEncode(key)), PrivateKeyEncoded: base64.StdEncoding.EncodeToString(certcrypto.PEMEncode(key)),
Certificate: outBytes, Certificate: outBytes,
IssuerCertificate: outBytes, CSR: []byte{},
CertificateUrl: "localhost",
}, nil }, nil
} }

View File

@ -19,8 +19,7 @@ type CertificateWrapper struct {
NotAfter time.Time `json:"not_after"` NotAfter time.Time `json:"not_after"`
PrivateKeyEncoded string `json:"private_key"` PrivateKeyEncoded string `json:"private_key"`
Certificate []byte `json:"certificate"` Certificate []byte `json:"certificate"`
IssuerCertificate []byte `json:"issuer_certificate"` CSR []byte `json:"csr"`
CertificateUrl string `json:"certificate_url"`
} }
// A structure to store all the certificates we know of in. // A structure to store all the certificates we know of in.

View File

@ -15,30 +15,30 @@ import (
var ( var (
// To access requestingDomains, first acquire the lock. // To access requestingDomains, first acquire the lock.
requestingLock = sync.Mutex{} domainsLock = sync.Mutex{}
// Domain -> _. Check if domain is a key here to see if we're already requeting // Domain -> _. Check if domain is a key here to see if we're already requesting
// a certificate for it. // or renewing a certificate for that domain.
requestingDomains = make(map[string]bool) workingDomains = make(map[string]bool)
) )
func lockIfUnlockedDomain(domain string) bool { func lockIfUnlockedDomain(domain string) bool {
requestingLock.Lock() domainsLock.Lock()
defer requestingLock.Unlock() defer domainsLock.Unlock()
_, found := requestingDomains[domain] _, found := workingDomains[domain]
if !found { if !found {
requestingDomains[domain] = true workingDomains[domain] = true
} }
return found return found
} }
func unlockDomain(domain string) { func unlockDomain(domain string) {
requestingLock.Lock() domainsLock.Lock()
defer requestingLock.Unlock() defer domainsLock.Unlock()
delete(requestingDomains, domain) delete(workingDomains, domain)
} }
func MakeTlsConfig(pagesDomain, cachePath string, cache *certificates.CertificatesCache, acmeClient *lego.Client) *tls.Config { func MakeTlsConfig(pagesDomain, cachePath string, cache *certificates.CertificatesCache, acmeClient *lego.Client) *tls.Config {
@ -76,8 +76,15 @@ func MakeTlsConfig(pagesDomain, cachePath string, cache *certificates.Certificat
} }
defer unlockDomain(domain) defer unlockDomain(domain)
// TODO: Renew // Renew
log.Debugf("Certificate for %s expired, renewing", domain) log.Debugf("Certificate for %s expired, renewing", domain)
newCert, err := certificates.RenewCertificate(&cert, acmeClient)
if err != nil {
log.Errorf("Failed to renew certificate for %s: %v", domain, err)
return cert.TlsCertificate, nil
}
cache.AddCert(newCert, cachePath)
return newCert.TlsCertificate, nil
} }
} else { } else {
// Don't request if we're already requesting. // Don't request if we're already requesting.

BIN
rio

Binary file not shown.