mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2024-11-23 06:18:59 +00:00
Document more flags & make http port customizable (#183)
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/183
This commit is contained in:
parent
46316f9e2f
commit
9a3d1c36dc
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@ build/
|
|||||||
vendor/
|
vendor/
|
||||||
pages
|
pages
|
||||||
certs.sqlite
|
certs.sqlite
|
||||||
|
.bash_history
|
||||||
|
3
Justfile
3
Justfile
@ -50,3 +50,6 @@ integration:
|
|||||||
|
|
||||||
integration-run TEST:
|
integration-run TEST:
|
||||||
go test -race -tags 'integration {{TAGS}}' -run "^{{TEST}}$" codeberg.org/codeberg/pages/integration/...
|
go test -race -tags 'integration {{TAGS}}' -run "^{{TEST}}$" codeberg.org/codeberg/pages/integration/...
|
||||||
|
|
||||||
|
docker:
|
||||||
|
docker run --rm -it --user $(id -u) -v $(pwd):/work --workdir /work -e HOME=/work codeberg.org/6543/docker-images/golang_just
|
||||||
|
34
cmd/flags.go
34
cmd/flags.go
@ -8,11 +8,13 @@ var (
|
|||||||
CertStorageFlags = []cli.Flag{
|
CertStorageFlags = []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "db-type",
|
Name: "db-type",
|
||||||
|
Usage: "Specify the database driver. Valid options are \"sqlite3\", \"mysql\" and \"postgres\". Read more at https://xorm.io",
|
||||||
Value: "sqlite3",
|
Value: "sqlite3",
|
||||||
EnvVars: []string{"DB_TYPE"},
|
EnvVars: []string{"DB_TYPE"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "db-conn",
|
Name: "db-conn",
|
||||||
|
Usage: "Specify the database connection. For \"sqlite3\" it's the filepath. Read more at https://go.dev/doc/tutorial/database-access",
|
||||||
Value: "certs.sqlite",
|
Value: "certs.sqlite",
|
||||||
EnvVars: []string{"DB_CONN"},
|
EnvVars: []string{"DB_CONN"},
|
||||||
},
|
},
|
||||||
@ -87,15 +89,21 @@ var (
|
|||||||
EnvVars: []string{"HOST"},
|
EnvVars: []string{"HOST"},
|
||||||
Value: "[::]",
|
Value: "[::]",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.UintFlag{
|
||||||
Name: "port",
|
Name: "port",
|
||||||
Usage: "specifies port of listening address",
|
Usage: "specifies the https port to listen to ssl requests",
|
||||||
EnvVars: []string{"PORT"},
|
EnvVars: []string{"PORT", "HTTPS_PORT"},
|
||||||
Value: "443",
|
Value: 443,
|
||||||
|
},
|
||||||
|
&cli.UintFlag{
|
||||||
|
Name: "http-port",
|
||||||
|
Usage: "specifies the http port, you also have to enable http server via ENABLE_HTTP_SERVER=true",
|
||||||
|
EnvVars: []string{"HTTP_PORT"},
|
||||||
|
Value: 80,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "enable-http-server",
|
Name: "enable-http-server",
|
||||||
// TODO: desc
|
Usage: "start a http server to redirect to https and respond to http acme challenges",
|
||||||
EnvVars: []string{"ENABLE_HTTP_SERVER"},
|
EnvVars: []string{"ENABLE_HTTP_SERVER"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@ -125,23 +133,23 @@ var (
|
|||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "acme-accept-terms",
|
Name: "acme-accept-terms",
|
||||||
// TODO: Usage
|
Usage: "To accept the ACME ToS",
|
||||||
EnvVars: []string{"ACME_ACCEPT_TERMS"},
|
EnvVars: []string{"ACME_ACCEPT_TERMS"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "acme-eab-kid",
|
Name: "acme-eab-kid",
|
||||||
// TODO: Usage
|
Usage: "Register the current account to the ACME server with external binding.",
|
||||||
EnvVars: []string{"ACME_EAB_KID"},
|
EnvVars: []string{"ACME_EAB_KID"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "acme-eab-hmac",
|
Name: "acme-eab-hmac",
|
||||||
// TODO: Usage
|
Usage: "Register the current account to the ACME server with external binding.",
|
||||||
EnvVars: []string{"ACME_EAB_HMAC"},
|
EnvVars: []string{"ACME_EAB_HMAC"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "dns-provider",
|
Name: "dns-provider",
|
||||||
Usage: "Use DNS-Challenge for main domain\n\nRead more at: https://go-acme.github.io/lego/dns/",
|
Usage: "Use DNS-Challenge for main domain. Read more at: https://go-acme.github.io/lego/dns/",
|
||||||
EnvVars: []string{"DNS_PROVIDER"},
|
EnvVars: []string{"DNS_PROVIDER"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
|
40
cmd/main.go
40
cmd/main.go
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server"
|
|
||||||
"codeberg.org/codeberg/pages/server/cache"
|
"codeberg.org/codeberg/pages/server/cache"
|
||||||
"codeberg.org/codeberg/pages/server/certificates"
|
"codeberg.org/codeberg/pages/server/certificates"
|
||||||
"codeberg.org/codeberg/pages/server/gitea"
|
"codeberg.org/codeberg/pages/server/gitea"
|
||||||
@ -48,7 +47,9 @@ func Serve(ctx *cli.Context) error {
|
|||||||
rawDomain := ctx.String("raw-domain")
|
rawDomain := ctx.String("raw-domain")
|
||||||
mainDomainSuffix := ctx.String("pages-domain")
|
mainDomainSuffix := ctx.String("pages-domain")
|
||||||
rawInfoPage := ctx.String("raw-info-page")
|
rawInfoPage := ctx.String("raw-info-page")
|
||||||
listeningAddress := fmt.Sprintf("%s:%s", ctx.String("host"), ctx.String("port"))
|
listeningHost := ctx.String("host")
|
||||||
|
listeningSSLAddress := fmt.Sprintf("%s:%d", listeningHost, ctx.Uint("port"))
|
||||||
|
listeningHTTPAddress := fmt.Sprintf("%s:%d", listeningHost, ctx.Uint("http-port"))
|
||||||
enableHTTPServer := ctx.Bool("enable-http-server")
|
enableHTTPServer := ctx.Bool("enable-http-server")
|
||||||
|
|
||||||
allowedCorsDomains := AllowedCorsDomains
|
allowedCorsDomains := AllowedCorsDomains
|
||||||
@ -91,22 +92,14 @@ func Serve(ctx *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create handler based on settings
|
// Create listener for SSL connections
|
||||||
httpsHandler := handler.Handler(mainDomainSuffix, rawDomain,
|
log.Info().Msgf("Listening on https://%s", listeningSSLAddress)
|
||||||
giteaClient,
|
listener, err := net.Listen("tcp", listeningSSLAddress)
|
||||||
rawInfoPage,
|
|
||||||
BlacklistedPaths, allowedCorsDomains,
|
|
||||||
dnsLookupCache, canonicalDomainCache)
|
|
||||||
|
|
||||||
httpHandler := server.SetupHTTPACMEChallengeServer(challengeCache)
|
|
||||||
|
|
||||||
// Setup listener and TLS
|
|
||||||
log.Info().Msgf("Listening on https://%s", listeningAddress)
|
|
||||||
listener, err := net.Listen("tcp", listeningAddress)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("couldn't create listener: %v", err)
|
return fmt.Errorf("couldn't create listener: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup listener for SSL connections
|
||||||
listener = tls.NewListener(listener, certificates.TLSConfig(mainDomainSuffix,
|
listener = tls.NewListener(listener, certificates.TLSConfig(mainDomainSuffix,
|
||||||
giteaClient,
|
giteaClient,
|
||||||
acmeClient,
|
acmeClient,
|
||||||
@ -119,18 +112,29 @@ func Serve(ctx *cli.Context) error {
|
|||||||
go certificates.MaintainCertDB(certMaintainCtx, interval, acmeClient, mainDomainSuffix, certDB)
|
go certificates.MaintainCertDB(certMaintainCtx, interval, acmeClient, mainDomainSuffix, certDB)
|
||||||
|
|
||||||
if enableHTTPServer {
|
if enableHTTPServer {
|
||||||
|
// Create handler for http->https redirect and http acme challenges
|
||||||
|
httpHandler := certificates.SetupHTTPACMEChallengeServer(challengeCache)
|
||||||
|
|
||||||
|
// Create listener for http and start listening
|
||||||
go func() {
|
go func() {
|
||||||
log.Info().Msg("Start HTTP server listening on :80")
|
log.Info().Msgf("Start HTTP server listening on %s", listeningHTTPAddress)
|
||||||
err := http.ListenAndServe("[::]:80", httpHandler)
|
err := http.ListenAndServe(listeningHTTPAddress, httpHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic().Err(err).Msg("Couldn't start HTTP fastServer")
|
log.Panic().Err(err).Msg("Couldn't start HTTP fastServer")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the web fastServer
|
// Create ssl handler based on settings
|
||||||
|
sslHandler := handler.Handler(mainDomainSuffix, rawDomain,
|
||||||
|
giteaClient,
|
||||||
|
rawInfoPage,
|
||||||
|
BlacklistedPaths, allowedCorsDomains,
|
||||||
|
dnsLookupCache, canonicalDomainCache)
|
||||||
|
|
||||||
|
// Start the ssl listener
|
||||||
log.Info().Msgf("Start listening on %s", listener.Addr())
|
log.Info().Msgf("Start listening on %s", listener.Addr())
|
||||||
if err := http.Serve(listener, httpsHandler); err != nil {
|
if err := http.Serve(listener, sslHandler); err != nil {
|
||||||
log.Panic().Err(err).Msg("Couldn't start fastServer")
|
log.Panic().Err(err).Msg("Couldn't start fastServer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,11 @@ func createAcmeClient(ctx *cli.Context, enableHTTPServer bool, challengeCache ca
|
|||||||
if (!acmeAcceptTerms || dnsProvider == "") && acmeAPI != "https://acme.mock.directory" {
|
if (!acmeAcceptTerms || dnsProvider == "") && acmeAPI != "https://acme.mock.directory" {
|
||||||
return nil, fmt.Errorf("%w: you must set $ACME_ACCEPT_TERMS and $DNS_PROVIDER, unless $ACME_API is set to https://acme.mock.directory", ErrAcmeMissConfig)
|
return nil, fmt.Errorf("%w: you must set $ACME_ACCEPT_TERMS and $DNS_PROVIDER, unless $ACME_API is set to https://acme.mock.directory", ErrAcmeMissConfig)
|
||||||
}
|
}
|
||||||
|
if acmeEabHmac != "" && acmeEabKID == "" {
|
||||||
|
return nil, fmt.Errorf("%w: ACME_EAB_HMAC also needs ACME_EAB_KID to be set", ErrAcmeMissConfig)
|
||||||
|
} else if acmeEabHmac == "" && acmeEabKID != "" {
|
||||||
|
return nil, fmt.Errorf("%w: ACME_EAB_KID also needs ACME_EAB_HMAC to be set", ErrAcmeMissConfig)
|
||||||
|
}
|
||||||
|
|
||||||
return certificates.NewAcmeClient(
|
return certificates.NewAcmeClient(
|
||||||
acmeAccountConf,
|
acmeAccountConf,
|
||||||
|
@ -14,6 +14,8 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const challengePath = "/.well-known/acme-challenge/"
|
||||||
|
|
||||||
func setupAcmeConfig(configFile, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcceptTerms bool) (*lego.Config, error) {
|
func setupAcmeConfig(configFile, acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcceptTerms bool) (*lego.Config, error) {
|
||||||
var myAcmeAccount AcmeAccount
|
var myAcmeAccount AcmeAccount
|
||||||
var myAcmeConfig *lego.Config
|
var myAcmeConfig *lego.Config
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package certificates
|
package certificates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server/cache"
|
"codeberg.org/codeberg/pages/server/cache"
|
||||||
|
"codeberg.org/codeberg/pages/server/context"
|
||||||
|
"codeberg.org/codeberg/pages/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AcmeTLSChallengeProvider struct {
|
type AcmeTLSChallengeProvider struct {
|
||||||
@ -39,3 +43,18 @@ func (a AcmeHTTPChallengeProvider) CleanUp(domain, token, _ string) error {
|
|||||||
a.challengeCache.Remove(domain + "/" + token)
|
a.challengeCache.Remove(domain + "/" + token)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetupHTTPACMEChallengeServer(challengeCache cache.SetGetKey) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
ctx := context.New(w, req)
|
||||||
|
if strings.HasPrefix(ctx.Path(), challengePath) {
|
||||||
|
challenge, ok := challengeCache.Get(utils.TrimHostPort(ctx.Host()) + "/" + strings.TrimPrefix(ctx.Path(), challengePath))
|
||||||
|
if !ok || challenge == nil {
|
||||||
|
ctx.String("no challenge for this token", http.StatusNotFound)
|
||||||
|
}
|
||||||
|
ctx.String(challenge.(string))
|
||||||
|
} else {
|
||||||
|
ctx.Redirect("https://"+ctx.Host()+ctx.Path(), http.StatusMovedPermanently)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,22 +36,23 @@ func TLSConfig(mainDomainSuffix string,
|
|||||||
return &tls.Config{
|
return &tls.Config{
|
||||||
// check DNS name & get certificate from Let's Encrypt
|
// check DNS name & get certificate from Let's Encrypt
|
||||||
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
sni := strings.ToLower(strings.TrimSpace(info.ServerName))
|
domain := strings.ToLower(strings.TrimSpace(info.ServerName))
|
||||||
if len(sni) < 1 {
|
if len(domain) < 1 {
|
||||||
return nil, errors.New("missing sni")
|
return nil, errors.New("missing domain info via SNI (RFC 4366, Section 3.1)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https request init is actually a acme challenge
|
||||||
if info.SupportedProtos != nil {
|
if info.SupportedProtos != nil {
|
||||||
for _, proto := range info.SupportedProtos {
|
for _, proto := range info.SupportedProtos {
|
||||||
if proto != tlsalpn01.ACMETLS1Protocol {
|
if proto != tlsalpn01.ACMETLS1Protocol {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
challenge, ok := challengeCache.Get(sni)
|
challenge, ok := challengeCache.Get(domain)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("no challenge for this domain")
|
return nil, errors.New("no challenge for this domain")
|
||||||
}
|
}
|
||||||
cert, err := tlsalpn01.ChallengeCert(sni, challenge.(string))
|
cert, err := tlsalpn01.ChallengeCert(domain, challenge.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -61,22 +62,22 @@ func TLSConfig(mainDomainSuffix string,
|
|||||||
|
|
||||||
targetOwner := ""
|
targetOwner := ""
|
||||||
mayObtainCert := true
|
mayObtainCert := true
|
||||||
if strings.HasSuffix(sni, mainDomainSuffix) || strings.EqualFold(sni, mainDomainSuffix[1:]) {
|
if strings.HasSuffix(domain, mainDomainSuffix) || strings.EqualFold(domain, mainDomainSuffix[1:]) {
|
||||||
// deliver default certificate for the main domain (*.codeberg.page)
|
// deliver default certificate for the main domain (*.codeberg.page)
|
||||||
sni = mainDomainSuffix
|
domain = mainDomainSuffix
|
||||||
} else {
|
} else {
|
||||||
var targetRepo, targetBranch string
|
var targetRepo, targetBranch string
|
||||||
targetOwner, targetRepo, targetBranch = dnsutils.GetTargetFromDNS(sni, mainDomainSuffix, dnsLookupCache)
|
targetOwner, targetRepo, targetBranch = dnsutils.GetTargetFromDNS(domain, mainDomainSuffix, dnsLookupCache)
|
||||||
if targetOwner == "" {
|
if targetOwner == "" {
|
||||||
// DNS not set up, return main certificate to redirect to the docs
|
// DNS not set up, return main certificate to redirect to the docs
|
||||||
sni = mainDomainSuffix
|
domain = mainDomainSuffix
|
||||||
} else {
|
} else {
|
||||||
targetOpt := &upstream.Options{
|
targetOpt := &upstream.Options{
|
||||||
TargetOwner: targetOwner,
|
TargetOwner: targetOwner,
|
||||||
TargetRepo: targetRepo,
|
TargetRepo: targetRepo,
|
||||||
TargetBranch: targetBranch,
|
TargetBranch: targetBranch,
|
||||||
}
|
}
|
||||||
_, valid := targetOpt.CheckCanonicalDomain(giteaClient, sni, mainDomainSuffix, canonicalDomainCache)
|
_, valid := targetOpt.CheckCanonicalDomain(giteaClient, domain, mainDomainSuffix, canonicalDomainCache)
|
||||||
if !valid {
|
if !valid {
|
||||||
// We shouldn't obtain a certificate when we cannot check if the
|
// We shouldn't obtain a certificate when we cannot check if the
|
||||||
// repository has specified this domain in the `.domains` file.
|
// repository has specified this domain in the `.domains` file.
|
||||||
@ -85,30 +86,34 @@ func TLSConfig(mainDomainSuffix string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tlsCertificate, ok := keyCache.Get(sni); ok {
|
if tlsCertificate, ok := keyCache.Get(domain); ok {
|
||||||
// we can use an existing certificate object
|
// we can use an existing certificate object
|
||||||
return tlsCertificate.(*tls.Certificate), nil
|
return tlsCertificate.(*tls.Certificate), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var tlsCertificate *tls.Certificate
|
var tlsCertificate *tls.Certificate
|
||||||
var err error
|
var err error
|
||||||
if tlsCertificate, err = acmeClient.retrieveCertFromDB(sni, mainDomainSuffix, false, certDB); err != nil {
|
if tlsCertificate, err = acmeClient.retrieveCertFromDB(domain, mainDomainSuffix, false, certDB); err != nil {
|
||||||
// request a new certificate
|
if !errors.Is(err, database.ErrNotFound) {
|
||||||
if strings.EqualFold(sni, mainDomainSuffix) {
|
return nil, err
|
||||||
|
}
|
||||||
|
// we could not find a cert in db, request a new certificate
|
||||||
|
|
||||||
|
// first check if we are allowed to obtain a cert for this domain
|
||||||
|
if strings.EqualFold(domain, mainDomainSuffix) {
|
||||||
return nil, errors.New("won't request certificate for main domain, something really bad has happened")
|
return nil, errors.New("won't request certificate for main domain, something really bad has happened")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mayObtainCert {
|
if !mayObtainCert {
|
||||||
return nil, fmt.Errorf("won't request certificate for %q", sni)
|
return nil, fmt.Errorf("won't request certificate for %q", domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsCertificate, err = acmeClient.obtainCert(acmeClient.legoClient, []string{sni}, nil, targetOwner, false, mainDomainSuffix, certDB)
|
tlsCertificate, err = acmeClient.obtainCert(acmeClient.legoClient, []string{domain}, nil, targetOwner, false, mainDomainSuffix, certDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := keyCache.Set(sni, tlsCertificate, 15*time.Minute); err != nil {
|
if err := keyCache.Set(domain, tlsCertificate, 15*time.Minute); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return tlsCertificate, nil
|
return tlsCertificate, nil
|
||||||
@ -164,7 +169,7 @@ func (c *AcmeClient) retrieveCertFromDB(sni, mainDomainSuffix string, useDnsProv
|
|||||||
if !strings.EqualFold(sni, mainDomainSuffix) {
|
if !strings.EqualFold(sni, mainDomainSuffix) {
|
||||||
tlsCertificate.Leaf, err = x509.ParseCertificate(tlsCertificate.Certificate[0])
|
tlsCertificate.Leaf, err = x509.ParseCertificate(tlsCertificate.Certificate[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsin leaf tlsCert: %w", err)
|
return nil, fmt.Errorf("error parsing leaf tlsCert: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// renew certificates 7 days before they expire
|
// renew certificates 7 days before they expire
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"codeberg.org/codeberg/pages/server/cache"
|
|
||||||
"codeberg.org/codeberg/pages/server/context"
|
|
||||||
"codeberg.org/codeberg/pages/server/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetupHTTPACMEChallengeServer(challengeCache cache.SetGetKey) http.HandlerFunc {
|
|
||||||
challengePath := "/.well-known/acme-challenge/"
|
|
||||||
|
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
ctx := context.New(w, req)
|
|
||||||
if strings.HasPrefix(ctx.Path(), challengePath) {
|
|
||||||
challenge, ok := challengeCache.Get(utils.TrimHostPort(ctx.Host()) + "/" + strings.TrimPrefix(ctx.Path(), challengePath))
|
|
||||||
if !ok || challenge == nil {
|
|
||||||
ctx.String("no challenge for this token", http.StatusNotFound)
|
|
||||||
}
|
|
||||||
ctx.String(challenge.(string))
|
|
||||||
} else {
|
|
||||||
ctx.Redirect("https://"+ctx.Host()+ctx.Path(), http.StatusMovedPermanently)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user