diff --git a/.gitignore b/.gitignore index 4afd2f1..a3ffedb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -./rio \ No newline at end of file +# Artificats +rio + +# Testing stuff +*.json \ No newline at end of file diff --git a/internal/certificates/certificate.go b/internal/certificates/certificate.go index 67d3f22..13de687 100644 --- a/internal/certificates/certificate.go +++ b/internal/certificates/certificate.go @@ -18,6 +18,35 @@ import ( "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) { req := certificate.ObtainRequest{ Domains: domains, @@ -36,12 +65,11 @@ func ObtainNewCertificate(domains []string, acmeClient *lego.Client) (Certificat wrapper := CertificateWrapper{ TlsCertificate: &tlsCert, Domain: cert.Domain, - //NotAfter: tlsCert.Leaf.NotAfter, + //NotAfter: tlsCert.Leaf.NotAfter, NotAfter: time.Now().Add(time.Hour * 24 * 60), PrivateKeyEncoded: base64.StdEncoding.EncodeToString(cert.PrivateKey), Certificate: cert.Certificate, - IssuerCertificate: cert.IssuerCertificate, - CertificateUrl: cert.CertURL, + CSR: cert.CSR, } return wrapper, nil } @@ -103,7 +131,6 @@ func MakeFallbackCertificate(pagesDomain string) (*CertificateWrapper, error) { NotAfter: notAfter, PrivateKeyEncoded: base64.StdEncoding.EncodeToString(certcrypto.PEMEncode(key)), Certificate: outBytes, - IssuerCertificate: outBytes, - CertificateUrl: "localhost", + CSR: []byte{}, }, nil } diff --git a/internal/certificates/store.go b/internal/certificates/store.go index 640b729..465b4ce 100644 --- a/internal/certificates/store.go +++ b/internal/certificates/store.go @@ -19,8 +19,7 @@ type CertificateWrapper struct { NotAfter time.Time `json:"not_after"` PrivateKeyEncoded string `json:"private_key"` Certificate []byte `json:"certificate"` - IssuerCertificate []byte `json:"issuer_certificate"` - CertificateUrl string `json:"certificate_url"` + CSR []byte `json:"csr"` } // A structure to store all the certificates we know of in. diff --git a/internal/server/tls.go b/internal/server/tls.go index 0ea9d6d..b73ee9d 100644 --- a/internal/server/tls.go +++ b/internal/server/tls.go @@ -15,30 +15,30 @@ import ( var ( // 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 - // a certificate for it. - requestingDomains = make(map[string]bool) + // Domain -> _. Check if domain is a key here to see if we're already requesting + // or renewing a certificate for that domain. + workingDomains = make(map[string]bool) ) func lockIfUnlockedDomain(domain string) bool { - requestingLock.Lock() - defer requestingLock.Unlock() + domainsLock.Lock() + defer domainsLock.Unlock() - _, found := requestingDomains[domain] + _, found := workingDomains[domain] if !found { - requestingDomains[domain] = true + workingDomains[domain] = true } return found } func unlockDomain(domain string) { - requestingLock.Lock() - defer requestingLock.Unlock() + domainsLock.Lock() + defer domainsLock.Unlock() - delete(requestingDomains, domain) + delete(workingDomains, domain) } 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) - // TODO: Renew + // Renew 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 { // Don't request if we're already requesting. diff --git a/rio b/rio deleted file mode 100755 index c3d97c4..0000000 Binary files a/rio and /dev/null differ