remove EnvOr use flags

This commit is contained in:
6543 2021-12-03 03:05:38 +01:00
parent ac93a5661c
commit 35e08d2252
No known key found for this signature in database
GPG key ID: C99B82E40B027BAE
5 changed files with 93 additions and 61 deletions

View file

@ -1,37 +1,72 @@
package cmd package cmd
import ( import (
"codeberg.org/codeberg/pages/server"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
// GiteaRoot specifies the root URL of the Gitea instance, without a trailing slash.
var GiteaRoot = []byte(server.EnvOr("GITEA_ROOT", "https://codeberg.org"))
var GiteaApiToken = server.EnvOr("GITEA_API_TOKEN", "")
// RawDomain specifies the domain from which raw repository content shall be served in the following format:
// https://{RawDomain}/{owner}/{repo}[/{branch|tag|commit}/{version}]/{filepath...}
// (set to []byte(nil) to disable raw content hosting)
var RawDomain = []byte(server.EnvOr("RAW_DOMAIN", "raw.codeberg.org"))
// RawInfoPage will be shown (with a redirect) when trying to access RawDomain directly (or without owner/repo/path).
var RawInfoPage = server.EnvOr("REDIRECT_RAW_INFO", "https://docs.codeberg.org/pages/raw-content/")
var ServeFlags = []cli.Flag{ var ServeFlags = []cli.Flag{
// MainDomainSuffix specifies the main domain (starting with a dot) for which subdomains shall be served as static // MainDomainSuffix specifies the main domain (starting with a dot) for which subdomains shall be served as static
// pages, or used for comparison in CNAME lookups. Static pages can be accessed through // pages, or used for comparison in CNAME lookups. Static pages can be accessed through
// https://{owner}.{MainDomain}[/{repo}], with repo defaulting to "pages". // https://{owner}.{MainDomain}[/{repo}], with repo defaulting to "pages".
// var MainDomainSuffix = []byte("." + server.EnvOr("PAGES_DOMAIN", "codeberg.page"))
&cli.StringFlag{ &cli.StringFlag{
Name: "main-domain-suffix", Name: "main-domain-suffix",
Aliases: nil,
Usage: "specifies the main domain (starting with a dot) for which subdomains shall be served as static pages", Usage: "specifies the main domain (starting with a dot) for which subdomains shall be served as static pages",
EnvVars: []string{"PAGES_DOMAIN"}, EnvVars: []string{"PAGES_DOMAIN"},
FilePath: "",
Required: false,
Hidden: false,
TakesFile: false,
Value: "codeberg.page", Value: "codeberg.page",
}, },
// GiteaRoot specifies the root URL of the Gitea instance, without a trailing slash.
&cli.StringFlag{
Name: "gitea-root",
Usage: "specifies the root URL of the Gitea instance, without a trailing slash.",
EnvVars: []string{"GITEA_ROOT"},
Value: "https://codeberg.org",
},
// GiteaApiToken specifies an api token for the Gitea instance
&cli.StringFlag{
Name: "gitea-api-token",
Usage: "specifies an api token for the Gitea instance",
EnvVars: []string{"GITEA_API_TOKEN"},
Value: "",
},
// RawDomain specifies the domain from which raw repository content shall be served in the following format:
// https://{RawDomain}/{owner}/{repo}[/{branch|tag|commit}/{version}]/{filepath...}
// (set to []byte(nil) to disable raw content hosting)
&cli.StringFlag{
Name: "raw-domain",
Usage: "specifies the domain from which raw repository content shall be served, not set disable raw content hosting",
EnvVars: []string{"RAW_DOMAIN"},
Value: "raw.codeberg.org",
},
// RawInfoPage will be shown (with a redirect) when trying to access RawDomain directly (or without owner/repo/path).
&cli.StringFlag{
Name: "raw-info-page",
Usage: "will be shown (with a redirect) when trying to access $RAW_DOMAIN directly (or without owner/repo/path)",
EnvVars: []string{"REDIRECT_RAW_INFO"},
Value: "https://docs.codeberg.org/pages/raw-content/",
},
&cli.StringFlag{
Name: "host",
Usage: "specifies host of listening address",
EnvVars: []string{"HOST"},
Value: "[::]",
},
&cli.StringFlag{
Name: "port",
Usage: "specifies port of listening address",
EnvVars: []string{"PORT"},
Value: "443",
},
// ACME_API
&cli.StringFlag{
Name: "acme-api",
EnvVars: []string{"ACME_API"},
Value: "https://acme-v02.api.letsencrypt.org/directory",
},
&cli.StringFlag{
Name: "acme-email",
EnvVars: []string{"ACME_EMAIL"},
Value: "noreply@example.email",
},
} }

View file

@ -4,12 +4,13 @@ import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"log"
"net" "net"
"net/http" "net/http"
"os" "os"
"strings"
"time" "time"
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
@ -17,8 +18,8 @@ import (
) )
// AllowedCorsDomains lists the domains for which Cross-Origin Resource Sharing is allowed. // AllowedCorsDomains lists the domains for which Cross-Origin Resource Sharing is allowed.
// TODO: make it a flag
var AllowedCorsDomains = [][]byte{ var AllowedCorsDomains = [][]byte{
RawDomain,
[]byte("fonts.codeberg.org"), []byte("fonts.codeberg.org"),
[]byte("design.codeberg.org"), []byte("design.codeberg.org"),
} }
@ -30,20 +31,26 @@ var BlacklistedPaths = [][]byte{
// Serve sets up and starts the web server. // Serve sets up and starts the web server.
func Serve(ctx *cli.Context) error { func Serve(ctx *cli.Context) error {
giteaRoot := strings.TrimSuffix(ctx.String("gitea-root"), "/")
giteaAPIToken := ctx.String("gitea-api-token")
rawDomain := ctx.String("raw-domain")
mainDomainSuffix := []byte(ctx.String("main-domain-suffix")) mainDomainSuffix := []byte(ctx.String("main-domain-suffix"))
rawInfoPage := ctx.String("raw-info-page")
listeningAddress := fmt.Sprintf("%s:%s", ctx.String("host"), ctx.String("port"))
acmeAPI := ctx.String("acme-api")
acmeMail := ctx.String("acme-email")
allowedCorsDomains := AllowedCorsDomains
if len(rawDomain) != 0 {
allowedCorsDomains = append(allowedCorsDomains, []byte(rawDomain))
}
// Make sure MainDomain has a trailing dot, and GiteaRoot has no trailing slash // Make sure MainDomain has a trailing dot, and GiteaRoot has no trailing slash
if !bytes.HasPrefix(mainDomainSuffix, []byte{'.'}) { if !bytes.HasPrefix(mainDomainSuffix, []byte{'.'}) {
mainDomainSuffix = append([]byte{'.'}, mainDomainSuffix...) mainDomainSuffix = append([]byte{'.'}, mainDomainSuffix...)
} }
GiteaRoot = bytes.TrimSuffix(GiteaRoot, []byte{'/'})
// Use HOST and PORT environment variables to determine listening address
address := fmt.Sprintf("%s:%s", server.EnvOr("HOST", "[::]"), server.EnvOr("PORT", "443"))
log.Printf("Listening on https://%s", address)
// Create handler based on settings // Create handler based on settings
handler := server.Handler(mainDomainSuffix, RawDomain, GiteaRoot, RawInfoPage, GiteaApiToken, BlacklistedPaths, AllowedCorsDomains) handler := server.Handler(mainDomainSuffix, []byte(rawDomain), giteaRoot, rawInfoPage, giteaAPIToken, BlacklistedPaths, allowedCorsDomains)
// Enable compression by wrapping the handler with the compression function provided by FastHTTP // Enable compression by wrapping the handler with the compression function provided by FastHTTP
compressedHandler := fasthttp.CompressHandlerBrotliLevel(handler, fasthttp.CompressBrotliBestSpeed, fasthttp.CompressBestSpeed) compressedHandler := fasthttp.CompressHandlerBrotliLevel(handler, fasthttp.CompressBrotliBestSpeed, fasthttp.CompressBestSpeed)
@ -60,13 +67,14 @@ func Serve(ctx *cli.Context) error {
} }
// Setup listener and TLS // Setup listener and TLS
listener, err := net.Listen("tcp", address) log.Info().Msgf("Listening on https://%s", listeningAddress)
listener, err := net.Listen("tcp", listeningAddress)
if err != nil { if err != nil {
log.Fatalf("Couldn't create listener: %s", err) return fmt.Errorf("couldn't create listener: %s", err)
} }
listener = tls.NewListener(listener, server.TlsConfig(mainDomainSuffix, string(GiteaRoot), GiteaApiToken)) listener = tls.NewListener(listener, server.TlsConfig(mainDomainSuffix, giteaRoot, giteaAPIToken))
server.SetupCertificates(mainDomainSuffix) server.SetupCertificates(mainDomainSuffix, acmeAPI, acmeMail)
if os.Getenv("ENABLE_HTTP_SERVER") == "true" { if os.Getenv("ENABLE_HTTP_SERVER") == "true" {
go (func() { go (func() {
challengePath := []byte("/.well-known/acme-challenge/") challengePath := []byte("/.well-known/acme-challenge/")
@ -83,7 +91,7 @@ func Serve(ctx *cli.Context) error {
} }
}) })
if err != nil { if err != nil {
log.Fatalf("Couldn't start HTTP fastServer: %s", err) log.Fatal().Err(err).Msg("Couldn't start HTTP fastServer")
} }
})() })()
} }
@ -91,7 +99,7 @@ func Serve(ctx *cli.Context) error {
// Start the web fastServer // Start the web fastServer
err = fastServer.Serve(listener) err = fastServer.Serve(listener)
if err != nil { if err != nil {
log.Fatalf("Couldn't start fastServer: %s", err) log.Fatal().Err(err).Msg("Couldn't start fastServer")
} }
return nil return nil

View file

@ -399,7 +399,7 @@ func mockCert(domain, msg, mainDomainSuffix string) tls.Certificate {
return tlsCertificate return tlsCertificate
} }
func SetupCertificates(mainDomainSuffix []byte) { func SetupCertificates(mainDomainSuffix []byte, acmeAPI, acmeMail string) {
if KeyDatabaseErr != nil { if KeyDatabaseErr != nil {
panic(KeyDatabaseErr) panic(KeyDatabaseErr)
} }
@ -425,7 +425,7 @@ func SetupCertificates(mainDomainSuffix []byte) {
panic(err) panic(err)
} }
myAcmeConfig = lego.NewConfig(&myAcmeAccount) myAcmeConfig = lego.NewConfig(&myAcmeAccount)
myAcmeConfig.CADirURL = EnvOr("ACME_API", "https://acme-v02.api.letsencrypt.org/directory") myAcmeConfig.CADirURL = acmeAPI
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048 myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
_, err := lego.NewClient(myAcmeConfig) _, err := lego.NewClient(myAcmeConfig)
if err != nil { if err != nil {
@ -437,12 +437,12 @@ func SetupCertificates(mainDomainSuffix []byte) {
panic(err) panic(err)
} }
myAcmeAccount = AcmeAccount{ myAcmeAccount = AcmeAccount{
Email: EnvOr("ACME_EMAIL", "noreply@example.email"), Email: acmeMail,
Key: privateKey, Key: privateKey,
KeyPEM: string(certcrypto.PEMEncode(privateKey)), KeyPEM: string(certcrypto.PEMEncode(privateKey)),
} }
myAcmeConfig = lego.NewConfig(&myAcmeAccount) myAcmeConfig = lego.NewConfig(&myAcmeAccount)
myAcmeConfig.CADirURL = EnvOr("ACME_API", "https://acme-v02.api.letsencrypt.org/directory") myAcmeConfig.CADirURL = acmeAPI
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048 myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
tempClient, err := lego.NewClient(myAcmeConfig) tempClient, err := lego.NewClient(myAcmeConfig)
if err != nil { if err != nil {

View file

@ -19,7 +19,7 @@ import (
) )
// Handler handles a single HTTP request to the web server. // Handler handles a single HTTP request to the web server.
func Handler(mainDomainSuffix, rawDomain, giteaRoot []byte, rawInfoPage, giteaApiToken string, blacklistedPaths, allowedCorsDomains [][]byte) func(ctx *fasthttp.RequestCtx) { func Handler(mainDomainSuffix, rawDomain []byte, giteaRoot, rawInfoPage, giteaApiToken string, blacklistedPaths, allowedCorsDomains [][]byte) func(ctx *fasthttp.RequestCtx) {
return func(ctx *fasthttp.RequestCtx) { return func(ctx *fasthttp.RequestCtx) {
log := log.With().Str("Handler", string(ctx.Request.Header.RequestURI())).Logger() log := log.With().Str("Handler", string(ctx.Request.Header.RequestURI())).Logger()
@ -86,7 +86,7 @@ func Handler(mainDomainSuffix, rawDomain, giteaRoot []byte, rawInfoPage, giteaAp
} }
// Check if the branch exists, otherwise treat it as a file path // Check if the branch exists, otherwise treat it as a file path
branchTimestampResult := getBranchTimestamp(targetOwner, repo, branch, string(giteaRoot), giteaApiToken) branchTimestampResult := getBranchTimestamp(targetOwner, repo, branch, giteaRoot, giteaApiToken)
if branchTimestampResult == nil { if branchTimestampResult == nil {
// branch doesn't exist // branch doesn't exist
return false return false
@ -115,7 +115,7 @@ func Handler(mainDomainSuffix, rawDomain, giteaRoot []byte, rawInfoPage, giteaAp
var tryUpstream = func() { var tryUpstream = func() {
// check if a canonical domain exists on a request on MainDomain // check if a canonical domain exists on a request on MainDomain
if bytes.HasSuffix(trimmedHost, mainDomainSuffix) { if bytes.HasSuffix(trimmedHost, mainDomainSuffix) {
canonicalDomain, _ := checkCanonicalDomain(targetOwner, targetRepo, targetBranch, "", string(mainDomainSuffix), string(giteaRoot), giteaApiToken) canonicalDomain, _ := checkCanonicalDomain(targetOwner, targetRepo, targetBranch, "", string(mainDomainSuffix), giteaRoot, giteaApiToken)
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix)) { if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], string(mainDomainSuffix)) {
canonicalPath := string(ctx.RequestURI()) canonicalPath := string(ctx.RequestURI())
if targetRepo != "pages" { if targetRepo != "pages" {
@ -127,7 +127,7 @@ func Handler(mainDomainSuffix, rawDomain, giteaRoot []byte, rawInfoPage, giteaAp
} }
// Try to request the file from the Gitea API // Try to request the file from the Gitea API
if !upstream(ctx, targetOwner, targetRepo, targetBranch, targetPath, string(giteaRoot), giteaApiToken, targetOptions) { if !upstream(ctx, targetOwner, targetRepo, targetBranch, targetPath, giteaRoot, giteaApiToken, targetOptions) {
returnErrorPage(ctx, ctx.Response.StatusCode()) returnErrorPage(ctx, ctx.Response.StatusCode())
} }
} }
@ -155,7 +155,7 @@ func Handler(mainDomainSuffix, rawDomain, giteaRoot []byte, rawInfoPage, giteaAp
if len(pathElements) > 2 && strings.HasPrefix(pathElements[2], "@") { if len(pathElements) > 2 && strings.HasPrefix(pathElements[2], "@") {
log.Debug().Msg("raw domain preparations, now trying with specified branch") log.Debug().Msg("raw domain preparations, now trying with specified branch")
if tryBranch(targetRepo, pathElements[2][1:], pathElements[3:], if tryBranch(targetRepo, pathElements[2][1:], pathElements[3:],
string(giteaRoot)+"/"+targetOwner+"/"+targetRepo+"/src/branch/%b/%p", giteaRoot+"/"+targetOwner+"/"+targetRepo+"/src/branch/%b/%p",
) { ) {
log.Debug().Msg("tryBranch, now trying upstream") log.Debug().Msg("tryBranch, now trying upstream")
tryUpstream() tryUpstream()
@ -167,7 +167,7 @@ func Handler(mainDomainSuffix, rawDomain, giteaRoot []byte, rawInfoPage, giteaAp
} else { } else {
log.Debug().Msg("raw domain preparations, now trying with default branch") log.Debug().Msg("raw domain preparations, now trying with default branch")
tryBranch(targetRepo, "", pathElements[2:], tryBranch(targetRepo, "", pathElements[2:],
string(giteaRoot)+"/"+targetOwner+"/"+targetRepo+"/src/branch/%b/%p", giteaRoot+"/"+targetOwner+"/"+targetRepo+"/src/branch/%b/%p",
) )
log.Debug().Msg("tryBranch, now trying upstream") log.Debug().Msg("tryBranch, now trying upstream")
tryUpstream() tryUpstream()
@ -266,7 +266,7 @@ func Handler(mainDomainSuffix, rawDomain, giteaRoot []byte, rawInfoPage, giteaAp
// Try to use the given repo on the given branch or the default branch // Try to use the given repo on the given branch or the default branch
log.Debug().Msg("custom domain preparations, now trying with details from DNS") log.Debug().Msg("custom domain preparations, now trying with details from DNS")
if tryBranch(targetRepo, targetBranch, pathElements, canonicalLink) { if tryBranch(targetRepo, targetBranch, pathElements, canonicalLink) {
canonicalDomain, valid := checkCanonicalDomain(targetOwner, targetRepo, targetBranch, trimmedHostStr, string(mainDomainSuffix), string(giteaRoot), giteaApiToken) canonicalDomain, valid := checkCanonicalDomain(targetOwner, targetRepo, targetBranch, trimmedHostStr, string(mainDomainSuffix), giteaRoot, giteaApiToken)
if !valid { if !valid {
returnErrorPage(ctx, fasthttp.StatusMisdirectedRequest) returnErrorPage(ctx, fasthttp.StatusMisdirectedRequest)
return return

View file

@ -3,8 +3,6 @@ package server
import ( import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"os"
"github.com/akrylysov/pogreb" "github.com/akrylysov/pogreb"
) )
@ -56,12 +54,3 @@ func PogrebGet(db *pogreb.DB, name []byte, obj interface{}) bool {
} }
return true return true
} }
// EnvOr reads an environment variable and returns a default value if it's empty.
// TODO: to helpers.go or use CLI framework
func EnvOr(env string, or string) string {
if v := os.Getenv(env); v != "" {
return v
}
return or
}