kopia lustrzana https://codeberg.org/Codeberg/pages-server
				
				
				
			mv acme config setup into own func
							rodzic
							
								
									77e39b2213
								
							
						
					
					
						commit
						11fa729686
					
				| 
						 | 
				
			
			@ -102,7 +102,12 @@ func Serve(ctx *cli.Context) error {
 | 
			
		|||
		keyCache, challengeCache, dnsLookupCache, canonicalDomainCache,
 | 
			
		||||
		keyDatabase))
 | 
			
		||||
 | 
			
		||||
	certificates.SetupCertificates(mainDomainSuffix, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer, challengeCache, keyDatabase)
 | 
			
		||||
	acmeConfig, err := certificates.SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, acmeAcceptTerms)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	certificates.SetupCertificates(mainDomainSuffix, dnsProvider, acmeConfig, acmeUseRateLimits, enableHTTPServer, challengeCache, keyDatabase)
 | 
			
		||||
 | 
			
		||||
	if enableHTTPServer {
 | 
			
		||||
		go func() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
package certificates
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-acme/lego/v4/registration"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AcmeAccount struct {
 | 
			
		||||
	Email        string
 | 
			
		||||
	Registration *registration.Resource
 | 
			
		||||
	Key          crypto.PrivateKey `json:"-"`
 | 
			
		||||
	KeyPEM       string            `json:"Key"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// make sure AcmeAccount match User interface
 | 
			
		||||
var _ registration.User = &AcmeAccount{}
 | 
			
		||||
 | 
			
		||||
func (u *AcmeAccount) GetEmail() string {
 | 
			
		||||
	return u.Email
 | 
			
		||||
}
 | 
			
		||||
func (u AcmeAccount) GetRegistration() *registration.Resource {
 | 
			
		||||
	return u.Registration
 | 
			
		||||
}
 | 
			
		||||
func (u *AcmeAccount) GetPrivateKey() crypto.PrivateKey {
 | 
			
		||||
	return u.Key
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ package certificates
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
| 
						 | 
				
			
			@ -12,15 +11,12 @@ import (
 | 
			
		|||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/reugn/equalizer"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-acme/lego/v4/certcrypto"
 | 
			
		||||
	"github.com/go-acme/lego/v4/certificate"
 | 
			
		||||
	"github.com/go-acme/lego/v4/challenge"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +24,8 @@ import (
 | 
			
		|||
	"github.com/go-acme/lego/v4/lego"
 | 
			
		||||
	"github.com/go-acme/lego/v4/providers/dns"
 | 
			
		||||
	"github.com/go-acme/lego/v4/registration"
 | 
			
		||||
	"github.com/reugn/equalizer"
 | 
			
		||||
	"github.com/rs/zerolog/log"
 | 
			
		||||
 | 
			
		||||
	"codeberg.org/codeberg/pages/server/cache"
 | 
			
		||||
	"codeberg.org/codeberg/pages/server/database"
 | 
			
		||||
| 
						 | 
				
			
			@ -147,26 +145,6 @@ func checkUserLimit(user string) error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var myAcmeAccount AcmeAccount
 | 
			
		||||
var myAcmeConfig *lego.Config
 | 
			
		||||
 | 
			
		||||
type AcmeAccount struct {
 | 
			
		||||
	Email        string
 | 
			
		||||
	Registration *registration.Resource
 | 
			
		||||
	Key          crypto.PrivateKey `json:"-"`
 | 
			
		||||
	KeyPEM       string            `json:"Key"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *AcmeAccount) GetEmail() string {
 | 
			
		||||
	return u.Email
 | 
			
		||||
}
 | 
			
		||||
func (u AcmeAccount) GetRegistration() *registration.Resource {
 | 
			
		||||
	return u.Registration
 | 
			
		||||
}
 | 
			
		||||
func (u *AcmeAccount) GetPrivateKey() crypto.PrivateKey {
 | 
			
		||||
	return u.Key
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var acmeClient, mainDomainAcmeClient *lego.Client
 | 
			
		||||
var acmeClientCertificateLimitPerUser = map[string]*equalizer.TokenBucket{}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -331,15 +309,12 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re
 | 
			
		|||
	return tlsCertificate, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID, dnsProvider string, acmeUseRateLimits, acmeAcceptTerms, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) {
 | 
			
		||||
	// getting main cert before ACME account so that we can panic here on database failure without hitting rate limits
 | 
			
		||||
	mainCertBytes, err := keyDatabase.Get(mainDomainSuffix)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// key database is not working
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcceptTerms bool) (*lego.Config, error) {
 | 
			
		||||
	const configFile = "acme-account.json"
 | 
			
		||||
	var myAcmeAccount AcmeAccount
 | 
			
		||||
	var myAcmeConfig *lego.Config
 | 
			
		||||
 | 
			
		||||
	if account, err := ioutil.ReadFile("acme-account.json"); err == nil {
 | 
			
		||||
	if account, err := ioutil.ReadFile(configFile); err == nil {
 | 
			
		||||
		err = json.Unmarshal(account, &myAcmeAccount)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
| 
						 | 
				
			
			@ -351,66 +326,81 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac,
 | 
			
		|||
		myAcmeConfig = lego.NewConfig(&myAcmeAccount)
 | 
			
		||||
		myAcmeConfig.CADirURL = acmeAPI
 | 
			
		||||
		myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
 | 
			
		||||
 | 
			
		||||
		// Validate Config
 | 
			
		||||
		_, err := lego.NewClient(myAcmeConfig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// TODO: should we fail hard instead?
 | 
			
		||||
			log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
	} else if os.IsNotExist(err) {
 | 
			
		||||
		privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		myAcmeAccount = AcmeAccount{
 | 
			
		||||
			Email:  acmeMail,
 | 
			
		||||
			Key:    privateKey,
 | 
			
		||||
			KeyPEM: string(certcrypto.PEMEncode(privateKey)),
 | 
			
		||||
		}
 | 
			
		||||
		myAcmeConfig = lego.NewConfig(&myAcmeAccount)
 | 
			
		||||
		myAcmeConfig.CADirURL = acmeAPI
 | 
			
		||||
		myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
 | 
			
		||||
		tempClient, err := lego.NewClient(myAcmeConfig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 | 
			
		||||
		} else {
 | 
			
		||||
			// accept terms & log in to EAB
 | 
			
		||||
			if acmeEabKID == "" || acmeEabHmac == "" {
 | 
			
		||||
				reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: acmeAcceptTerms})
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
 | 
			
		||||
				} else {
 | 
			
		||||
					myAcmeAccount.Registration = reg
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
 | 
			
		||||
					TermsOfServiceAgreed: acmeAcceptTerms,
 | 
			
		||||
					Kid:                  acmeEabKID,
 | 
			
		||||
					HmacEncoded:          acmeEabHmac,
 | 
			
		||||
				})
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
 | 
			
		||||
				} else {
 | 
			
		||||
					myAcmeAccount.Registration = reg
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		return myAcmeConfig, nil
 | 
			
		||||
	} else if !os.IsNotExist(err) {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
			if myAcmeAccount.Registration != nil {
 | 
			
		||||
				acmeAccountJson, err := json.Marshal(myAcmeAccount)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Printf("[FAIL] Error during json.Marshal(myAcmeAccount), waiting for manual restart to avoid rate limits: %s", err)
 | 
			
		||||
					select {}
 | 
			
		||||
				}
 | 
			
		||||
				err = ioutil.WriteFile("acme-account.json", acmeAccountJson, 0600)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Printf("[FAIL] Error during ioutil.WriteFile(\"acme-account.json\"), waiting for manual restart to avoid rate limits: %s", err)
 | 
			
		||||
					select {}
 | 
			
		||||
				}
 | 
			
		||||
	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	myAcmeAccount = AcmeAccount{
 | 
			
		||||
		Email:  acmeMail,
 | 
			
		||||
		Key:    privateKey,
 | 
			
		||||
		KeyPEM: string(certcrypto.PEMEncode(privateKey)),
 | 
			
		||||
	}
 | 
			
		||||
	myAcmeConfig = lego.NewConfig(&myAcmeAccount)
 | 
			
		||||
	myAcmeConfig.CADirURL = acmeAPI
 | 
			
		||||
	myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
 | 
			
		||||
	tempClient, err := lego.NewClient(myAcmeConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 | 
			
		||||
	} else {
 | 
			
		||||
		// accept terms & log in to EAB
 | 
			
		||||
		if acmeEabKID == "" || acmeEabHmac == "" {
 | 
			
		||||
			reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: acmeAcceptTerms})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				myAcmeAccount.Registration = reg
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
 | 
			
		||||
				TermsOfServiceAgreed: acmeAcceptTerms,
 | 
			
		||||
				Kid:                  acmeEabKID,
 | 
			
		||||
				HmacEncoded:          acmeEabHmac,
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				myAcmeAccount.Registration = reg
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
 | 
			
		||||
		if myAcmeAccount.Registration != nil {
 | 
			
		||||
			acmeAccountJson, err := json.Marshal(myAcmeAccount)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Printf("[FAIL] Error during json.Marshal(myAcmeAccount), waiting for manual restart to avoid rate limits: %s", err)
 | 
			
		||||
				select {}
 | 
			
		||||
			}
 | 
			
		||||
			err = ioutil.WriteFile(configFile, acmeAccountJson, 0600)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Printf("[FAIL] Error during ioutil.WriteFile(\"acme-account.json\"), waiting for manual restart to avoid rate limits: %s", err)
 | 
			
		||||
				select {}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return myAcmeConfig, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig *lego.Config, acmeUseRateLimits, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) {
 | 
			
		||||
	// getting main cert before ACME account so that we can panic here on database failure without hitting rate limits
 | 
			
		||||
	mainCertBytes, err := keyDatabase.Get(mainDomainSuffix)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// key database is not working
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	acmeClient, err = lego.NewClient(myAcmeConfig)
 | 
			
		||||
	acmeClient, err = lego.NewClient(acmeConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -426,7 +416,7 @@ func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail, acmeEabHmac,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mainDomainAcmeClient, err = lego.NewClient(myAcmeConfig)
 | 
			
		||||
	mainDomainAcmeClient, err = lego.NewClient(acmeConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err)
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue