diff --git a/.woodpecker.yml b/.woodpecker.yml index b83a4dd..2674e9b 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -26,12 +26,12 @@ pipeline: when: event: [ "pull_request", "push" ] - build-docker: + docker-dryrun: + group: compliant image: plugins/kaniko settings: dockerfile: Dockerfile no_push: true - repo: Codeberg/pages-server tags: latest when: event: [ "pull_request", "push" ] @@ -47,14 +47,14 @@ pipeline: event: [ "tag" ] test: - image: a6543/golang_just group: test + image: a6543/golang_just commands: - just test integration-tests: - image: a6543/golang_just group: test + image: a6543/golang_just commands: - just integration environment: @@ -78,3 +78,31 @@ pipeline: - DRONE_COMMIT_REF=${CI_COMMIT_REF} when: event: [ "tag" ] + + docker-next: + image: plugins/kaniko + settings: + registry: codeberg.org + dockerfile: Dockerfile + repo: codeberg.org/codeberg/pages-server + tags: next + username: + from_secret: bot_user + password: + from_secret: bot_token + when: + event: [ "push" ] + + docker-tag: + image: plugins/kaniko + settings: + registry: codeberg.org + dockerfile: Dockerfile + repo: codeberg.org/codeberg/pages-server + tag: [ latest, "${CI_COMMIT_TAG}" ] + username: + from_secret: bot_user + password: + from_secret: bot_token + when: + event: [ "tag" ] diff --git a/Justfile b/Justfile index c824efa..03a7436 100644 --- a/Justfile +++ b/Justfile @@ -6,7 +6,8 @@ dev: export PAGES_DOMAIN=localhost.mock.directory export RAW_DOMAIN=raw.localhost.mock.directory export PORT=4430 - go run . --verbose + export LOG_LEVEL=trace + go run . build: CGO_ENABLED=0 go build -ldflags '-s -w' -v -o build/codeberg-pages-server ./ @@ -45,4 +46,4 @@ integration: go test -race -tags integration codeberg.org/codeberg/pages/integration/... integration-run TEST: - go test -race -tags integration -run "^{{TEST}}$" codeberg.org/codeberg/pages/integration/... \ No newline at end of file + go test -race -tags integration -run "^{{TEST}}$" codeberg.org/codeberg/pages/integration/... diff --git a/cmd/flags.go b/cmd/flags.go index 3c9aef6..8ac09ec 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -5,12 +5,6 @@ import ( ) var ServeFlags = []cli.Flag{ - &cli.BoolFlag{ - Name: "verbose", - // TODO: Usage - EnvVars: []string{"DEBUG"}, - }, - // 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 // https://{owner}.{MainDomain}[/{repo}], with repo defaulting to "pages". @@ -74,11 +68,19 @@ var ServeFlags = []cli.Flag{ Name: "enable-lfs-support", Usage: "enable lfs support, require gitea v1.17.0 as backend", EnvVars: []string{"ENABLE_LFS_SUPPORT"}, + Value: true, }, &cli.BoolFlag{ Name: "enable-symlink-support", Usage: "follow symlinks if enabled, require gitea v1.18.0 as backend", EnvVars: []string{"ENABLE_SYMLINK_SUPPORT"}, + Value: true, + }, + &cli.StringFlag{ + Name: "log-level", + Value: "warn", + Usage: "specify at which log level should be logged. Possible options: info, warn, error, fatal", + EnvVars: []string{"LOG_LEVEL"}, }, // ACME diff --git a/cmd/main.go b/cmd/main.go index b147306..a380695 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "net" + "os" "strings" "time" @@ -36,10 +37,12 @@ var BlacklistedPaths = [][]byte{ // Serve sets up and starts the web server. func Serve(ctx *cli.Context) error { - verbose := ctx.Bool("verbose") - if !verbose { - zerolog.SetGlobalLevel(zerolog.InfoLevel) + // Initalize the logger. + logLevel, err := zerolog.ParseLevel(ctx.String("log-level")) + if err != nil { + return err } + log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).With().Timestamp().Logger().Level(logLevel) giteaRoot := strings.TrimSuffix(ctx.String("gitea-root"), "/") giteaAPIToken := ctx.String("gitea-api-token") @@ -98,7 +101,7 @@ func Serve(ctx *cli.Context) error { log.Info().Msgf("Listening on https://%s", listeningAddress) listener, err := net.Listen("tcp", listeningAddress) if err != nil { - return fmt.Errorf("couldn't create listener: %s", err) + return fmt.Errorf("couldn't create listener: %v", err) } // TODO: make "key-database.pogreb" set via flag @@ -131,7 +134,7 @@ func Serve(ctx *cli.Context) error { if enableHTTPServer { go func() { - log.Info().Timestamp().Msg("Start listening on :80") + log.Info().Msg("Start HTTP server listening on :80") err := httpServer.ListenAndServe("[::]:80") if err != nil { log.Panic().Err(err).Msg("Couldn't start HTTP fastServer") @@ -140,7 +143,7 @@ func Serve(ctx *cli.Context) error { } // Start the web fastServer - log.Info().Timestamp().Msgf("Start listening on %s", listener.Addr()) + log.Info().Msgf("Start listening on %s", listener.Addr()) err = fastServer.Serve(listener) if err != nil { log.Panic().Err(err).Msg("Couldn't start fastServer") diff --git a/go.mod b/go.mod index 913021f..58e0c4d 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/go-acme/lego/v4 v4.5.3 github.com/joho/godotenv v1.4.0 github.com/reugn/equalizer v0.0.0-20210216135016-a959c509d7ad - github.com/rs/zerolog v1.26.0 + github.com/rs/zerolog v1.27.0 github.com/stretchr/testify v1.7.0 github.com/urfave/cli/v2 v2.3.0 github.com/valyala/fasthttp v1.31.0 @@ -76,7 +76,8 @@ require ( github.com/liquidweb/go-lwApi v0.0.5 // indirect github.com/liquidweb/liquidweb-cli v0.6.9 // indirect github.com/liquidweb/liquidweb-go v1.6.3 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/miekg/dns v1.1.43 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect diff --git a/go.sum b/go.sum index 87001b7..e088334 100644 --- a/go.sum +++ b/go.sum @@ -97,7 +97,7 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpu/goacmedns v0.1.1 h1:DM3H2NiN2oam7QljgGY5ygy4yDXhK5Z4JUnqaugs2C4= github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobeGqugQ= @@ -330,12 +330,15 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -437,8 +440,8 @@ github.com/reugn/equalizer v0.0.0-20210216135016-a959c509d7ad/go.mod h1:h0+DiDRe github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE= -github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo= +github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -519,7 +522,6 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -580,7 +582,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -614,7 +615,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -680,7 +680,8 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -737,7 +738,6 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration/get_test.go b/integration/get_test.go index ccb8b6b..6054e17 100644 --- a/integration/get_test.go +++ b/integration/get_test.go @@ -7,17 +7,17 @@ import ( "bytes" "crypto/tls" "io" + "log" "net/http" "net/http/cookiejar" "strings" "testing" - "github.com/rs/zerolog/log" "github.com/stretchr/testify/assert" ) func TestGetRedirect(t *testing.T) { - log.Printf("=== TestGetRedirect ===\n") + log.Println("=== TestGetRedirect ===") // test custom domain redirect resp, err := getTestHTTPSClient().Get("https://calciumdibromid.localhost.mock.directory:4430") assert.NoError(t, err) @@ -29,7 +29,7 @@ func TestGetRedirect(t *testing.T) { } func TestGetContent(t *testing.T) { - log.Printf("=== TestGetContent ===\n") + log.Println("=== TestGetContent ===") // test get image resp, err := getTestHTTPSClient().Get("https://magiclike.localhost.mock.directory:4430/images/827679288a.jpg") assert.NoError(t, err) @@ -65,7 +65,7 @@ func TestGetContent(t *testing.T) { } func TestCustomDomain(t *testing.T) { - log.Printf("=== TestCustomDomain ===\n") + log.Println("=== TestCustomDomain ===") resp, err := getTestHTTPSClient().Get("https://mock-pages.codeberg-test.org:4430/README.md") assert.NoError(t, err) if !assert.EqualValues(t, http.StatusOK, resp.StatusCode) { @@ -77,7 +77,7 @@ func TestCustomDomain(t *testing.T) { } func TestGetNotFound(t *testing.T) { - log.Printf("=== TestGetNotFound ===\n") + log.Println("=== TestGetNotFound ===") // test custom not found pages resp, err := getTestHTTPSClient().Get("https://crystal.localhost.mock.directory:4430/pages-404-demo/blah") assert.NoError(t, err) diff --git a/integration/main_test.go b/integration/main_test.go index c8f524f..06d553f 100644 --- a/integration/main_test.go +++ b/integration/main_test.go @@ -5,25 +5,25 @@ package integration import ( "context" + "log" "os" "testing" "time" "codeberg.org/codeberg/pages/cmd" - "github.com/rs/zerolog/log" "github.com/urfave/cli/v2" ) func TestMain(m *testing.M) { - log.Printf("=== TestMain: START Server ===\n") + log.Println("=== TestMain: START Server ===") serverCtx, serverCancel := context.WithCancel(context.Background()) if err := startServer(serverCtx); err != nil { - log.Fatal().Msgf("could not start server: %v", err) + log.Fatalf("could not start server: %v", err) } defer func() { serverCancel() - log.Printf("=== TestMain: Server STOPED ===\n") + log.Println("=== TestMain: Server STOPED ===") }() time.Sleep(10 * time.Second) @@ -48,7 +48,7 @@ func startServer(ctx context.Context) error { go func() { if err := app.RunContext(ctx, args); err != nil { - log.Fatal().Msgf("run server error: %v", err) + log.Fatalf("run server error: %v", err) } }() diff --git a/server/certificates/certificates.go b/server/certificates/certificates.go index 2684dfa..8944468 100644 --- a/server/certificates/certificates.go +++ b/server/certificates/certificates.go @@ -12,7 +12,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "strconv" "strings" @@ -229,7 +228,7 @@ func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUs res.CSR = nil // acme client doesn't like CSR to be set tlsCertificate, err = obtainCert(acmeClient, []string{string(sni)}, res, "", dnsProvider, mainDomainSuffix, acmeUseRateLimits, certDB) if err != nil { - log.Printf("Couldn't renew certificate for %s: %s", sni, err) + log.Error().Msgf("Couldn't renew certificate for %s: %v", string(sni), err) } })() } @@ -272,10 +271,10 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re if acmeUseRateLimits { acmeClientRequestLimit.Take() } - log.Printf("Renewing certificate for %v", domains) + log.Debug().Msgf("Renewing certificate for: %v", domains) res, err = acmeClient.Certificate.Renew(*renew, true, false, "") if err != nil { - log.Printf("Couldn't renew certificate for %v, trying to request a new one: %s", domains, err) + log.Error().Err(err).Msgf("Couldn't renew certificate for %v, trying to request a new one", domains) res = nil } } @@ -290,7 +289,7 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re acmeClientOrderLimit.Take() acmeClientRequestLimit.Take() } - log.Printf("Requesting new certificate for %v", domains) + log.Debug().Msgf("Re-requesting new certificate for %v", domains) res, err = acmeClient.Certificate.Obtain(certificate.ObtainRequest{ Domains: domains, Bundle: true, @@ -298,7 +297,7 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re }) } if err != nil { - log.Printf("Couldn't obtain certificate for %v: %s", domains, err) + log.Error().Err(err).Msgf("Couldn't obtain again a certificate or %v", domains) if renew != nil && renew.CertURL != "" { tlsCertificate, err := tls.X509KeyPair(renew.Certificate, renew.PrivateKey) if err == nil && tlsCertificate.Leaf.NotAfter.After(time.Now()) { @@ -312,7 +311,7 @@ func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Re } return mockCert(domains[0], err.Error(), string(mainDomainSuffix), keyDatabase), err } - log.Printf("Obtained certificate for %v", domains) + log.Debug().Msgf("Obtained certificate for %v", domains) if err := keyDatabase.Put(name, res); err != nil { return tls.Certificate{}, err @@ -329,7 +328,7 @@ func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcce var myAcmeAccount AcmeAccount var myAcmeConfig *lego.Config - if account, err := ioutil.ReadFile(configFile); err == nil { + if account, err := os.ReadFile(configFile); err == nil { if err := json.Unmarshal(account, &myAcmeAccount); err != nil { return nil, err } @@ -345,7 +344,7 @@ func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcce _, 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) + log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only") } return myAcmeConfig, nil } else if !os.IsNotExist(err) { @@ -366,13 +365,13 @@ func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcce 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) + log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only") } 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) + log.Error().Err(err).Msg("Can't register ACME account, continuing with mock certs only") } else { myAcmeAccount.Registration = reg } @@ -383,7 +382,7 @@ func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcce HmacEncoded: acmeEabHmac, }) if err != nil { - log.Printf("[ERROR] Can't register ACME account, continuing with mock certs only: %s", err) + log.Error().Err(err).Msg("Can't register ACME account, continuing with mock certs only") } else { myAcmeAccount.Registration = reg } @@ -392,12 +391,12 @@ func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcce 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) + log.Error().Err(err).Msg("json.Marshalfailed, waiting for manual restart to avoid rate limits") select {} } - err = ioutil.WriteFile(configFile, acmeAccountJSON, 0o600) + err = os.WriteFile(configFile, acmeAccountJSON, 0o600) if err != nil { - log.Printf("[FAIL] Error during ioutil.WriteFile(\"acme-account.json\"), waiting for manual restart to avoid rate limits: %s", err) + log.Error().Err(err).Msg("os.WriteFile failed, waiting for manual restart to avoid rate limits") select {} } } @@ -415,38 +414,38 @@ func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig * acmeClient, err = lego.NewClient(acmeConfig) if err != nil { - log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err) + log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only") } else { err = acmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{challengeCache}) if err != nil { - log.Printf("[ERROR] Can't create TLS-ALPN-01 provider: %s", err) + log.Error().Err(err).Msg("Can't create TLS-ALPN-01 provider") } if enableHTTPServer { err = acmeClient.Challenge.SetHTTP01Provider(AcmeHTTPChallengeProvider{challengeCache}) if err != nil { - log.Printf("[ERROR] Can't create HTTP-01 provider: %s", err) + log.Error().Err(err).Msg("Can't create HTTP-01 provider") } } } mainDomainAcmeClient, err = lego.NewClient(acmeConfig) if err != nil { - log.Printf("[ERROR] Can't create ACME client, continuing with mock certs only: %s", err) + log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only") } else { if dnsProvider == "" { // using mock server, don't use wildcard certs err := mainDomainAcmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{challengeCache}) if err != nil { - log.Printf("[ERROR] Can't create TLS-ALPN-01 provider: %s", err) + log.Error().Err(err).Msg("Can't create TLS-ALPN-01 provider") } } else { provider, err := dns.NewDNSChallengeProviderByName(dnsProvider) if err != nil { - log.Printf("[ERROR] Can't create DNS Challenge provider: %s", err) + log.Error().Err(err).Msg("Can't create DNS Challenge provider") } err = mainDomainAcmeClient.Challenge.SetDNS01Provider(provider) if err != nil { - log.Printf("[ERROR] Can't create DNS-01 provider: %s", err) + log.Error().Err(err).Msg("Can't create DNS-01 provider") } } } @@ -454,7 +453,7 @@ func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig * if mainCertBytes == nil { _, err = obtainCert(mainDomainAcmeClient, []string{"*" + string(mainDomainSuffix), string(mainDomainSuffix[1:])}, nil, "", dnsProvider, mainDomainSuffix, acmeUseRateLimits, certDB) if err != nil { - log.Printf("[ERROR] Couldn't renew main domain certificate, continuing with mock certs only: %s", err) + log.Error().Err(err).Msg("Couldn't renew main domain certificate, continuing with mock certs only") } } @@ -482,7 +481,7 @@ func MaintainCertDB(ctx context.Context, interval time.Duration, mainDomainSuffi if err != nil || !tlsCertificates[0].NotAfter.After(now) { err := certDB.Delete(string(key)) if err != nil { - log.Printf("[ERROR] Deleting expired certificate for %s failed: %s", string(key), err) + log.Error().Err(err).Msgf("Deleting expired certificate for %q failed", string(key)) } else { expiredCertCount++ } @@ -490,22 +489,22 @@ func MaintainCertDB(ctx context.Context, interval time.Duration, mainDomainSuffi } key, resBytes, err = keyDatabaseIterator.Next() } - log.Printf("[INFO] Removed %d expired certificates from the database", expiredCertCount) + log.Debug().Msgf("Removed %d expired certificates from the database", expiredCertCount) // compact the database msg, err := certDB.Compact() if err != nil { - log.Printf("[ERROR] Compacting key database failed: %s", err) + log.Error().Err(err).Msg("Compacting key database failed") } else { - log.Printf("[INFO] Compacted key database (%s)", msg) + log.Debug().Msgf("Compacted key database: %s", msg) } // update main cert res, err := certDB.Get(string(mainDomainSuffix)) if err != nil { - log.Err(err).Msgf("could not get cert for domain '%s'", mainDomainSuffix) + log.Error().Msgf("Couldn't get cert for domain %q", mainDomainSuffix) } else if res == nil { - log.Error().Msgf("Couldn't renew certificate for main domain: %s", "expected main domain cert to exist, but it's missing - seems like the database is corrupted") + log.Error().Msgf("Couldn't renew certificate for main domain %q expected main domain cert to exist, but it's missing - seems like the database is corrupted", string(mainDomainSuffix)) } else { tlsCertificates, err := certcrypto.ParsePEMBundle(res.Certificate) @@ -514,7 +513,7 @@ func MaintainCertDB(ctx context.Context, interval time.Duration, mainDomainSuffi go (func() { _, err = obtainCert(mainDomainAcmeClient, []string{"*" + string(mainDomainSuffix), string(mainDomainSuffix[1:])}, res, "", dnsProvider, mainDomainSuffix, acmeUseRateLimits, certDB) if err != nil { - log.Printf("[ERROR] Couldn't renew certificate for main domain: %s", err) + log.Error().Err(err).Msg("Couldn't renew certificate for main domain") } })() } diff --git a/server/database/setup.go b/server/database/setup.go index bbcf431..1c5a0af 100644 --- a/server/database/setup.go +++ b/server/database/setup.go @@ -72,7 +72,7 @@ func (p aDB) sync() { for { err := p.intern.Sync() if err != nil { - log.Err(err).Msg("Syncing cert database failed") + log.Error().Err(err).Msg("Syncing cert database failed") } select { case <-p.ctx.Done(): diff --git a/server/gitea/client.go b/server/gitea/client.go index 6e9a9ec..3c1bb49 100644 --- a/server/gitea/client.go +++ b/server/gitea/client.go @@ -9,4 +9,5 @@ var ErrorNotFound = errors.New("not found") const ( branchTimestampCacheKeyPrefix = "branchTime" defaultBranchCacheKeyPrefix = "defaultBranch" + giteaObjectTypeHeader = "X-Gitea-Object-Type" ) diff --git a/server/gitea/client_fasthttp.go b/server/gitea/client_fasthttp.go index ce34fae..904272b 100644 --- a/server/gitea/client_fasthttp.go +++ b/server/gitea/client_fasthttp.go @@ -16,8 +16,7 @@ import ( ) const ( - giteaAPIRepos = "/api/v1/repos/" - giteaObjectTypeHeader = "X-Gitea-Object-Type" + giteaAPIRepos = "/api/v1/repos/" ) type Client struct { @@ -71,7 +70,10 @@ func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource str switch resp.StatusCode() { case fasthttp.StatusOK: - if client.followSymlinks && string(resp.Header.Peek(giteaObjectTypeHeader)) == "symlink" { + objType := string(resp.Header.Peek(giteaObjectTypeHeader)) + log.Trace().Msgf("server raw content object: %s", objType) + if client.followSymlinks && objType == "symlink" { + // TODO: limit to 1000 chars if we switched to std linkDest := strings.TrimSpace(string(resp.Body())) log.Debug().Msgf("follow symlink from '%s' to '%s'", resource, linkDest) return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest) diff --git a/server/gitea/client_std.go b/server/gitea/client_std.go index 5a39150..d8d1f9f 100644 --- a/server/gitea/client_std.go +++ b/server/gitea/client_std.go @@ -11,6 +11,7 @@ import ( "time" "code.gitea.io/sdk/gitea" + "github.com/rs/zerolog/log" "codeberg.org/codeberg/pages/server/cache" ) @@ -25,14 +26,19 @@ type Client struct { func NewClient(giteaRoot, giteaAPIToken string, respCache cache.SetGetKey, followSymlinks, supportLFS bool) (*Client, error) { rootURL, err := url.Parse(giteaRoot) + if err != nil { + return nil, err + } giteaRoot = strings.Trim(rootURL.String(), "/") stdClient := http.Client{Timeout: 10 * time.Second} sdk, err := gitea.NewClient(giteaRoot, gitea.SetHTTPClient(&stdClient), gitea.SetToken(giteaAPIToken)) return &Client{ - sdkClient: sdk, - responseCache: respCache, + sdkClient: sdk, + responseCache: respCache, + followSymlinks: followSymlinks, + supportLFS: supportLFS, }, err } @@ -78,6 +84,21 @@ func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource str // _ = fileResponseCache.Set(uri+"?timestamp="+o.timestamp(), cachedResponse, fileCacheTimeout) // } + objType := resp.Header.Get(giteaObjectTypeHeader) + log.Trace().Msgf("server raw content object: %s", objType) + if client.followSymlinks && objType == "symlink" { + // limit to 1000 chars + defer reader.Close() + linkDestBytes, err := io.ReadAll(io.LimitReader(reader, 10000)) + if err != nil { + return nil, nil, err + } + linkDest := strings.TrimSpace(string(linkDestBytes)) + + log.Debug().Msgf("follow symlink from '%s' to '%s'", resource, linkDest) + return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest) + } + return reader, resp.Response, err case http.StatusNotFound: diff --git a/server/handler.go b/server/handler.go index cda0af5..7350fbb 100644 --- a/server/handler.go +++ b/server/handler.go @@ -28,7 +28,7 @@ func Handler(mainDomainSuffix, rawDomain []byte, dnsLookupCache, canonicalDomainCache cache.SetGetKey, ) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { - log := log.With().Str("Handler", req.RequestURI).Logger() + log := log.With().Strs("Handler", []string{string(req.Host), req.RequestURI}).Logger() w.Header().Set("Server", "CodebergPages/"+version.Version) diff --git a/server/handler_fasthttp.go b/server/handler_fasthttp.go index 764f1b2..2e15ab4 100644 --- a/server/handler_fasthttp.go +++ b/server/handler_fasthttp.go @@ -27,7 +27,7 @@ func Handler(mainDomainSuffix, rawDomain []byte, dnsLookupCache, canonicalDomainCache cache.SetGetKey, ) func(ctx *fasthttp.RequestCtx) { return func(ctx *fasthttp.RequestCtx) { - log := log.With().Str("Handler", string(ctx.Request.Header.RequestURI())).Logger() + log := log.With().Strs("Handler", []string{string(ctx.Request.Host()), string(ctx.Request.Header.RequestURI())}).Logger() ctx.Response.Header.Set("Server", "CodebergPages/"+version.Version) diff --git a/server/setup.go b/server/setup.go index 6476d41..421f047 100644 --- a/server/setup.go +++ b/server/setup.go @@ -4,11 +4,11 @@ package server import ( "bytes" + "fmt" "net/http" "time" "github.com/rs/zerolog/log" - "github.com/valyala/fasthttp" "codeberg.org/codeberg/pages/server/cache" @@ -18,7 +18,7 @@ import ( type fasthttpLogger struct{} func (fasthttpLogger) Printf(format string, args ...interface{}) { - log.Printf("[FASTHTTP] "+format, args...) + log.Printf("FastHTTP: %s", fmt.Sprintf(format, args...)) } func SetupServer(handler fasthttp.RequestHandler) *fasthttp.Server { diff --git a/server/try.go b/server/try.go index 63904ec..d65d1b2 100644 --- a/server/try.go +++ b/server/try.go @@ -43,6 +43,7 @@ func tryUpstream(ctx *context.Context, giteaClient *gitea.Client, targetOptions.TargetRepo = targetRepo targetOptions.TargetBranch = targetBranch targetOptions.TargetPath = targetPath + targetOptions.Host = string(trimmedHost) // Try to request the file from the Gitea API if !targetOptions.Upstream(ctx, giteaClient) {