Compare commits

..

No commits in common. "main" and "v6.1" have entirely different histories.
main ... v6.1

23 changed files with 730 additions and 2241 deletions

1
.envrc
View file

@ -1 +0,0 @@
use_flake

2
.gitignore vendored
View file

@ -8,5 +8,3 @@ vendor/
pages
certs.sqlite
.bash_history
pkg/
.direnv/

View file

@ -5,22 +5,22 @@ when:
steps:
# use vendor to cache dependencies
vendor:
image: golang:1.24
image: golang:1.23
commands:
- go mod vendor
build:
depends_on: vendor
image: codeberg.org/6543/docker-images/golang_just:go-1.24
image: codeberg.org/6543/docker-images/golang_just:go-1.22
commands:
- go version
- just build
when:
- event: [push, pull_request, tag]
- event: [push, pull_request]
docker-dryrun:
depends_on: vendor
image: woodpeckerci/plugin-docker-buildx:5.2.1
image: woodpeckerci/plugin-docker-buildx:5.0.0
settings:
dockerfile: Dockerfile
platforms: linux/amd64
@ -32,7 +32,7 @@ steps:
build-tag:
depends_on: vendor
image: codeberg.org/6543/docker-images/golang_just:go-1.24
image: codeberg.org/6543/docker-images/golang_just:go-1.22
commands:
- go version
- just build-tag ${CI_COMMIT_TAG##v}
@ -41,29 +41,28 @@ steps:
test:
depends_on: build
image: codeberg.org/6543/docker-images/golang_just:go-1.24
image: codeberg.org/6543/docker-images/golang_just:go-1.22
commands:
- just test
when:
- event: [pull_request]
integration-tests:
failure: ignore
depends_on: build
image: codeberg.org/6543/docker-images/golang_just:go-1.24
image: codeberg.org/6543/docker-images/golang_just:go-1.22
commands:
- just integration
environment:
ACME_API: https://acme.mock.directory
PAGES_DOMAIN: localhost.mock.directory
RAW_DOMAIN: raw.localhost.mock.directory
PORT: 4430
- ACME_API=https://acme.mock.directory
- PAGES_DOMAIN=localhost.mock.directory
- RAW_DOMAIN=raw.localhost.mock.directory
- PORT=4430
when:
- event: [pull_request]
release:
depends_on: build
image: woodpeckerci/plugin-release:0.2.5
image: woodpeckerci/plugin-release:0.2.1
settings:
base_url: https://codeberg.org
file_exists: overwrite
@ -75,7 +74,7 @@ steps:
docker-next:
depends_on: vendor
image: woodpeckerci/plugin-docker-buildx:5.2.1
image: woodpeckerci/plugin-docker-buildx:5.0.0
settings:
registry: codeberg.org
dockerfile: Dockerfile
@ -90,7 +89,7 @@ steps:
- event: [push]
'Publish PR image':
image: woodpeckerci/plugin-docker-buildx:5.2.1
image: woodpeckerci/plugin-docker-buildx:5.0.0
depends_on: test
settings:
registry: codeberg.org
@ -108,7 +107,7 @@ steps:
docker-release:
depends_on: vendor
image: woodpeckerci/plugin-docker-buildx:5.2.1
image: woodpeckerci/plugin-docker-buildx:5.0.0
settings:
registry: codeberg.org
dockerfile: Dockerfile

View file

@ -6,25 +6,25 @@ when:
steps:
lint:
depends_on: []
image: golangci/golangci-lint:v1.64.8
image: golangci/golangci-lint:v1.61.0
commands:
- go version
- go install mvdan.cc/gofumpt@latest
- "[ $(gofumpt -extra -l . | wc -l) != 0 ] && { echo 'code not formated'; exit 1; }"
- golangci-lint run --timeout 10m --build-tags integration
- golangci-lint run --timeout 5m --build-tags integration
editor-config:
depends_on: []
image: mstruebing/editorconfig-checker:v3.2.0
image: mstruebing/editorconfig-checker:v3.0.3
yamllint:
image: pipelinecomponents/yamllint:0.33.0
image: pipelinecomponents/yamllint:0.32.1
depends_on: []
commands:
- yamllint .
prettier:
image: docker.io/woodpeckerci/plugin-prettier:1.3.0
image: docker.io/woodpeckerci/plugin-prettier:0.2.0
depends_on: []
settings:
version: 3.2.5

View file

@ -1,8 +1,8 @@
# Set the default Go version as a build argument
ARG XGO="go-1.24.x"
ARG XGO="go-1.21.x"
# Use xgo (a Go cross-compiler tool) as build image
FROM --platform=$BUILDPLATFORM techknowlogick/xgo:${XGO} AS build
FROM --platform=$BUILDPLATFORM techknowlogick/xgo:${XGO} as build
# Set the working directory and copy the source code
WORKDIR /go/src/codeberg.org/codeberg/pages

4
flake.lock generated
View file

@ -20,8 +20,8 @@
"nixpkgs": {
"locked": {
"lastModified": 0,
"narHash": "sha256-WFZDy4bG2RkkCQloIEG8BXEvzyKklFVJbAismOJsIp4=",
"path": "/nix/store/c77dsgfxjywplw8bk8s8jlkdsr7a1bi9-source",
"narHash": "sha256-x07g4NcqGP6mQn6AISXJaks9sQYDjZmTMBlKIvajvyc=",
"path": "/nix/store/2w8kz6zh3aq80f1dypiin222fry1rv51-source",
"type": "path"
},
"original": {

View file

@ -13,7 +13,7 @@
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
glibc.static
gcc
go
gofumpt
golangci-lint

291
go.mod
View file

@ -1,237 +1,144 @@
module codeberg.org/codeberg/pages
go 1.24.0
go 1.22.0
toolchain go1.23.1
require (
code.gitea.io/sdk/gitea v0.20.0
code.gitea.io/sdk/gitea v0.17.1
github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a
github.com/creasty/defaults v1.8.0
github.com/go-acme/lego/v4 v4.21.0
github.com/go-sql-driver/mysql v1.8.1
github.com/hashicorp/go-uuid v1.0.3
github.com/creasty/defaults v1.7.0
github.com/go-acme/lego/v4 v4.5.3
github.com/go-sql-driver/mysql v1.6.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/joho/godotenv v1.5.1
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.24
github.com/microcosm-cc/bluemonday v1.0.27
github.com/pelletier/go-toml/v2 v2.2.3
github.com/pires/go-proxyproto v0.8.0
github.com/joho/godotenv v1.4.0
github.com/lib/pq v1.10.7
github.com/mattn/go-sqlite3 v1.14.16
github.com/microcosm-cc/bluemonday v1.0.26
github.com/pelletier/go-toml/v2 v2.1.0
github.com/reugn/equalizer v0.0.0-20210216135016-a959c509d7ad
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.27.5
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
xorm.io/xorm v1.3.9
github.com/rs/zerolog v1.27.0
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.3.0
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
xorm.io/xorm v1.3.2
)
require (
cloud.google.com/go/auth v0.14.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/42wim/httpsig v1.2.2 // indirect
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
cloud.google.com/go v0.54.0 // indirect
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.29 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest v0.11.19 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 // indirect
github.com/aws/aws-sdk-go-v2 v1.33.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.53 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.24 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9 // indirect
github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.10 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.10 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.8 // indirect
github.com/aws/smithy-go v1.22.1 // indirect
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183 // indirect
github.com/aws/aws-sdk-go v1.39.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/boombuler/barcode v1.0.2 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/civo/civogo v0.3.92 // indirect
github.com/cloudflare/cloudflare-go v0.114.0 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
github.com/cloudflare/cloudflare-go v0.20.0 // indirect
github.com/cpu/goacmedns v0.1.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/deepmap/oapi-codegen v1.6.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/dnsimple/dnsimple-go v1.7.0 // indirect
github.com/exoscale/egoscale/v3 v3.1.8 // indirect
github.com/dnsimple/dnsimple-go v0.70.1 // indirect
github.com/exoscale/egoscale v0.67.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.24.0 // indirect
github.com/go-resty/resty/v2 v2.16.3 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/goccy/go-json v0.10.4 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect
github.com/goccy/go-json v0.8.1 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/gophercloud/gophercloud v1.14.1 // indirect
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.132 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
github.com/gophercloud/gophercloud v0.16.0 // indirect
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect
github.com/jarcoal/httpmock v1.0.6 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
github.com/labbsr0x/goh v1.0.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/linode/linodego v1.46.0 // indirect
github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
github.com/liquidweb/liquidweb-go v1.6.4 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
github.com/linode/linodego v0.31.1 // indirect
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-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.5.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
github.com/nrdcg/auroradns v1.1.0 // indirect
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 // indirect
github.com/nrdcg/desec v0.10.0 // indirect
github.com/nrdcg/auroradns v1.0.1 // indirect
github.com/nrdcg/desec v0.6.0 // indirect
github.com/nrdcg/dnspod-go v0.4.0 // indirect
github.com/nrdcg/freemyip v0.3.0 // indirect
github.com/nrdcg/goinwx v0.10.0 // indirect
github.com/nrdcg/mailinabox v0.2.0 // indirect
github.com/nrdcg/freemyip v0.2.0 // indirect
github.com/nrdcg/goinwx v0.8.1 // indirect
github.com/nrdcg/namesilo v0.2.1 // indirect
github.com/nrdcg/nodion v0.1.0 // indirect
github.com/nrdcg/porkbun v0.4.0 // indirect
github.com/nzdjb/go-metaname v1.0.0 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/oracle/oci-go-sdk/v65 v65.81.2 // indirect
github.com/ovh/go-ovh v1.6.0 // indirect
github.com/nrdcg/porkbun v0.1.1 // indirect
github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
github.com/ovh/go-ovh v1.1.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/peterhellberg/link v1.2.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pires/go-proxyproto v0.8.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pquerna/otp v1.4.0 // indirect
github.com/regfish/regfish-dnsapi-go v0.1.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sacloud/api-client-go v0.2.10 // indirect
github.com/sacloud/go-http v0.1.9 // indirect
github.com/sacloud/iaas-api-go v1.14.0 // indirect
github.com/sacloud/packages-go v0.0.11 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30 // indirect
github.com/selectel/domains-go v1.1.0 // indirect
github.com/selectel/go-selvpcclient/v3 v3.2.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pquerna/otp v1.3.0 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/sacloud/libsacloud v1.36.2 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sirupsen/logrus v1.4.2 // indirect
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
github.com/softlayer/softlayer-go v1.1.7 // indirect
github.com/softlayer/softlayer-go v1.0.3 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/sony/gobreaker v1.0.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1084 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/transip/gotransip/v6 v6.26.0 // indirect
github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec // indirect
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
github.com/volcengine/volc-sdk-golang v1.0.193 // indirect
github.com/vultr/govultr/v3 v3.14.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20241220122821-aeb3b05efd1c // indirect
github.com/yandex-cloud/go-sdk v0.0.0-20241220131134-2393e243c134 // indirect
go.mongodb.org/mongo-driver v1.17.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/ratelimit v0.3.1 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/oauth2 v0.25.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.31.0 // indirect
google.golang.org/api v0.217.0 // indirect
google.golang.org/genproto v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/grpc v1.69.4 // indirect
google.golang.org/protobuf v1.36.3 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.13.0 // indirect
github.com/transip/gotransip/v6 v6.6.1 // indirect
github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14 // indirect
github.com/vultr/govultr/v2 v2.7.1 // indirect
go.opencensus.io v0.22.3 // indirect
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
google.golang.org/api v0.20.0 // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/genproto v0.0.0-20200305110556-506484158171 // indirect
google.golang.org/grpc v1.27.1 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.6.2 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.32.1 // indirect
k8s.io/apimachinery v0.32.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
xorm.io/builder v0.3.13 // indirect
xorm.io/builder v0.3.12 // indirect
)

2403
go.sum

File diff suppressed because it is too large Load diff

View file

@ -16,11 +16,9 @@ import (
"github.com/go-acme/lego/v4/lego"
"github.com/hashicorp/golang-lru/v2/expirable"
"github.com/reugn/equalizer"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"codeberg.org/codeberg/pages/server/cache"
psContext "codeberg.org/codeberg/pages/server/context"
"codeberg.org/codeberg/pages/server/database"
dnsutils "codeberg.org/codeberg/pages/server/dns"
"codeberg.org/codeberg/pages/server/gitea"
@ -45,11 +43,7 @@ func TLSConfig(mainDomainSuffix string,
return &tls.Config{
// check DNS name & get certificate from Let's Encrypt
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
ctx := psContext.New(nil, nil)
log := log.With().Str("ReqId", ctx.ReqId).Logger()
domain := strings.ToLower(strings.TrimSpace(info.ServerName))
log.Debug().Str("domain", domain).Msg("start: get tls certificate")
if len(domain) < 1 {
return nil, errors.New("missing domain info via SNI (RFC 4366, Section 3.1)")
}
@ -106,7 +100,7 @@ func TLSConfig(mainDomainSuffix string,
TargetRepo: targetRepo,
TargetBranch: targetBranch,
}
_, valid := targetOpt.CheckCanonicalDomain(ctx, giteaClient, domain, mainDomainSuffix, canonicalDomainCache)
_, valid := targetOpt.CheckCanonicalDomain(giteaClient, domain, mainDomainSuffix, canonicalDomainCache)
if !valid {
// We shouldn't obtain a certificate when we cannot check if the
// repository has specified this domain in the `.domains` file.
@ -122,7 +116,7 @@ func TLSConfig(mainDomainSuffix string,
var tlsCertificate *tls.Certificate
var err error
if tlsCertificate, err = acmeClient.retrieveCertFromDB(log, domain, mainDomainSuffix, false, certDB); err != nil {
if tlsCertificate, err = acmeClient.retrieveCertFromDB(domain, mainDomainSuffix, false, certDB); err != nil {
if !errors.Is(err, database.ErrNotFound) {
return nil, err
}
@ -136,7 +130,7 @@ func TLSConfig(mainDomainSuffix string,
return nil, fmt.Errorf("won't request certificate for %q", domain)
}
tlsCertificate, err = acmeClient.obtainCert(log, acmeClient.legoClient, []string{domain}, nil, targetOwner, false, mainDomainSuffix, certDB)
tlsCertificate, err = acmeClient.obtainCert(acmeClient.legoClient, []string{domain}, nil, targetOwner, false, mainDomainSuffix, certDB)
if err != nil {
return nil, err
}
@ -179,7 +173,7 @@ func (c *AcmeClient) checkUserLimit(user string) error {
return nil
}
func (c *AcmeClient) retrieveCertFromDB(log zerolog.Logger, sni, mainDomainSuffix string, useDnsProvider bool, certDB database.CertDB) (*tls.Certificate, error) {
func (c *AcmeClient) retrieveCertFromDB(sni, mainDomainSuffix string, useDnsProvider bool, certDB database.CertDB) (*tls.Certificate, error) {
// parse certificate from database
res, err := certDB.Get(sni)
if err != nil {
@ -212,7 +206,7 @@ func (c *AcmeClient) retrieveCertFromDB(log zerolog.Logger, sni, mainDomainSuffi
// TODO: make a queue ?
go (func() {
res.CSR = nil // acme client doesn't like CSR to be set
if _, err := c.obtainCert(log, c.legoClient, []string{sni}, res, "", useDnsProvider, mainDomainSuffix, certDB); err != nil {
if _, err := c.obtainCert(c.legoClient, []string{sni}, res, "", useDnsProvider, mainDomainSuffix, certDB); err != nil {
log.Error().Msgf("Couldn't renew certificate for %s: %v", sni, err)
}
})()
@ -222,7 +216,7 @@ func (c *AcmeClient) retrieveCertFromDB(log zerolog.Logger, sni, mainDomainSuffi
return &tlsCertificate, nil
}
func (c *AcmeClient) obtainCert(log zerolog.Logger, acmeClient *lego.Client, domains []string, renew *certificate.Resource, user string, useDnsProvider bool, mainDomainSuffix string, keyDatabase database.CertDB) (*tls.Certificate, error) {
func (c *AcmeClient) obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Resource, user string, useDnsProvider bool, mainDomainSuffix string, keyDatabase database.CertDB) (*tls.Certificate, error) {
name := strings.TrimPrefix(domains[0], "*")
// lock to avoid simultaneous requests
@ -232,7 +226,7 @@ func (c *AcmeClient) obtainCert(log zerolog.Logger, acmeClient *lego.Client, dom
time.Sleep(100 * time.Millisecond)
_, working = c.obtainLocks.Load(name)
}
cert, err := c.retrieveCertFromDB(log, name, mainDomainSuffix, useDnsProvider, keyDatabase)
cert, err := c.retrieveCertFromDB(name, mainDomainSuffix, useDnsProvider, keyDatabase)
if err != nil {
return nil, fmt.Errorf("certificate failed in synchronous request: %w", err)
}
@ -326,7 +320,7 @@ func (c *AcmeClient) obtainCert(log zerolog.Logger, acmeClient *lego.Client, dom
return &tlsCertificate, nil
}
func SetupMainDomainCertificates(log zerolog.Logger, mainDomainSuffix string, acmeClient *AcmeClient, certDB database.CertDB) error {
func SetupMainDomainCertificates(mainDomainSuffix string, acmeClient *AcmeClient, certDB database.CertDB) error {
// getting main cert before ACME account so that we can fail here without hitting rate limits
mainCertBytes, err := certDB.Get(mainDomainSuffix)
if err != nil && !errors.Is(err, database.ErrNotFound) {
@ -334,7 +328,7 @@ func SetupMainDomainCertificates(log zerolog.Logger, mainDomainSuffix string, ac
}
if mainCertBytes == nil {
_, err = acmeClient.obtainCert(log, acmeClient.dnsChallengerLegoClient, []string{"*" + mainDomainSuffix, mainDomainSuffix[1:]}, nil, "", true, mainDomainSuffix, certDB)
_, err = acmeClient.obtainCert(acmeClient.dnsChallengerLegoClient, []string{"*" + mainDomainSuffix, mainDomainSuffix[1:]}, nil, "", true, mainDomainSuffix, certDB)
if err != nil {
log.Error().Err(err).Msg("Couldn't renew main domain certificate, continuing with mock certs only")
}
@ -343,7 +337,7 @@ func SetupMainDomainCertificates(log zerolog.Logger, mainDomainSuffix string, ac
return nil
}
func MaintainCertDB(log zerolog.Logger, ctx context.Context, interval time.Duration, acmeClient *AcmeClient, mainDomainSuffix string, certDB database.CertDB) {
func MaintainCertDB(ctx context.Context, interval time.Duration, acmeClient *AcmeClient, mainDomainSuffix string, certDB database.CertDB) {
for {
// delete expired certs that will be invalid until next clean up
threshold := time.Now().Add(interval)
@ -381,7 +375,7 @@ func MaintainCertDB(log zerolog.Logger, ctx context.Context, interval time.Durat
} else if tlsCertificates[0].NotAfter.Before(time.Now().Add(30 * 24 * time.Hour)) {
// renew main certificate 30 days before it expires
go (func() {
_, err = acmeClient.obtainCert(log, acmeClient.dnsChallengerLegoClient, []string{"*" + mainDomainSuffix, mainDomainSuffix[1:]}, res, "", true, mainDomainSuffix, certDB)
_, err = acmeClient.obtainCert(acmeClient.dnsChallengerLegoClient, []string{"*" + mainDomainSuffix, mainDomainSuffix[1:]}, res, "", true, mainDomainSuffix, certDB)
if err != nil {
log.Error().Err(err).Msg("Couldn't renew certificate for main domain")
}

View file

@ -5,29 +5,19 @@ import (
"net/http"
"codeberg.org/codeberg/pages/server/utils"
"github.com/hashicorp/go-uuid"
"github.com/rs/zerolog/log"
)
type Context struct {
RespWriter http.ResponseWriter
Req *http.Request
StatusCode int
ReqId string
}
func New(w http.ResponseWriter, r *http.Request) *Context {
req_uuid, err := uuid.GenerateUUID()
if err != nil {
log.Error().Err(err).Msg("Failed to generate request id, assigning error value")
req_uuid = "ERROR"
}
return &Context{
RespWriter: w,
Req: r,
StatusCode: http.StatusOK,
ReqId: req_uuid,
}
}

View file

@ -8,11 +8,9 @@ import (
"net/http"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"codeberg.org/codeberg/pages/server/cache"
"codeberg.org/codeberg/pages/server/context"
)
const (
@ -40,16 +38,15 @@ type FileResponse struct {
Exists bool `json:"exists"`
IsSymlink bool `json:"isSymlink"`
ETag string `json:"eTag"`
MimeType string `json:"mimeType"` // uncompressed MIME type
RawMime string `json:"rawMime"` // raw MIME type (if compressed, type of compression)
Body []byte `json:"-"` // saved separately
MimeType string `json:"mimeType"`
Body []byte `json:"-"` // saved separately
}
func (f FileResponse) IsEmpty() bool {
return len(f.Body) == 0
}
func (f FileResponse) createHttpResponse(cacheKey string, decompress bool) (header http.Header, statusCode int) {
func (f FileResponse) createHttpResponse(cacheKey string) (header http.Header, statusCode int) {
header = make(http.Header)
if f.Exists {
@ -62,13 +59,7 @@ func (f FileResponse) createHttpResponse(cacheKey string, decompress bool) (head
header.Set(giteaObjectTypeHeader, objTypeSymlink)
}
header.Set(ETagHeader, f.ETag)
if decompress {
header.Set(ContentTypeHeader, f.MimeType)
} else {
header.Set(ContentTypeHeader, f.RawMime)
}
header.Set(ContentTypeHeader, f.MimeType)
header.Set(ContentLengthHeader, fmt.Sprintf("%d", len(f.Body)))
header.Set(PagesCacheIndicatorHeader, "true")
@ -91,17 +82,16 @@ type writeCacheReader struct {
hasError bool
doNotCache bool
complete bool
log zerolog.Logger
}
func (t *writeCacheReader) Read(p []byte) (n int, err error) {
t.log.Trace().Msgf("[cache] read %q", t.cacheKey)
log.Trace().Msgf("[cache] read %q", t.cacheKey)
n, err = t.originalReader.Read(p)
if err == io.EOF {
t.complete = true
}
if err != nil && err != io.EOF {
t.log.Trace().Err(err).Msgf("[cache] original reader for %q has returned an error", t.cacheKey)
log.Trace().Err(err).Msgf("[cache] original reader for %q has returned an error", t.cacheKey)
t.hasError = true
} else if n > 0 {
if t.buffer.Len()+n > int(fileCacheSizeLimit) {
@ -121,23 +111,22 @@ func (t *writeCacheReader) Close() error {
if doWrite {
jsonToCache, err := json.Marshal(fc)
if err != nil {
t.log.Trace().Err(err).Msgf("[cache] marshaling json for %q has returned an error", t.cacheKey+"|Metadata")
log.Trace().Err(err).Msgf("[cache] marshaling json for %q has returned an error", t.cacheKey+"|Metadata")
}
err = t.cache.Set(t.cacheKey+"|Metadata", jsonToCache, fileCacheTimeout)
if err != nil {
t.log.Trace().Err(err).Msgf("[cache] writer for %q has returned an error", t.cacheKey+"|Metadata")
log.Trace().Err(err).Msgf("[cache] writer for %q has returned an error", t.cacheKey+"|Metadata")
}
err = t.cache.Set(t.cacheKey+"|Body", fc.Body, fileCacheTimeout)
if err != nil {
t.log.Trace().Err(err).Msgf("[cache] writer for %q has returned an error", t.cacheKey+"|Body")
log.Trace().Err(err).Msgf("[cache] writer for %q has returned an error", t.cacheKey+"|Body")
}
}
t.log.Trace().Msgf("cacheReader for %q saved=%t closed", t.cacheKey, doWrite)
log.Trace().Msgf("cacheReader for %q saved=%t closed", t.cacheKey, doWrite)
return t.originalReader.Close()
}
func (f FileResponse) CreateCacheReader(ctx *context.Context, r io.ReadCloser, cache cache.ICache, cacheKey string) io.ReadCloser {
log := log.With().Str("ReqId", ctx.ReqId).Logger()
func (f FileResponse) CreateCacheReader(r io.ReadCloser, cache cache.ICache, cacheKey string) io.ReadCloser {
if r == nil || cache == nil || cacheKey == "" {
log.Error().Msg("could not create CacheReader")
return nil
@ -149,6 +138,5 @@ func (f FileResponse) CreateCacheReader(ctx *context.Context, r io.ReadCloser, c
fileResponse: &f,
cache: cache,
cacheKey: cacheKey,
log: log,
}
}

View file

@ -19,7 +19,6 @@ import (
"codeberg.org/codeberg/pages/config"
"codeberg.org/codeberg/pages/server/cache"
"codeberg.org/codeberg/pages/server/context"
"codeberg.org/codeberg/pages/server/version"
)
@ -41,15 +40,13 @@ const (
objTypeSymlink = "symlink"
// std
ETagHeader = "ETag"
ContentTypeHeader = "Content-Type"
ContentLengthHeader = "Content-Length"
ContentEncodingHeader = "Content-Encoding"
ETagHeader = "ETag"
ContentTypeHeader = "Content-Type"
ContentLengthHeader = "Content-Length"
)
type Client struct {
sdkClient *gitea.Client
sdkFileClient *gitea.Client
responseCache cache.ICache
giteaRoot string
@ -69,6 +66,8 @@ func NewClient(cfg config.ForgeConfig, respCache cache.ICache) (*Client, error)
}
giteaRoot := strings.TrimSuffix(rootURL.String(), "/")
stdClient := http.Client{Timeout: 10 * time.Second}
forbiddenMimeTypes := make(map[string]bool, len(cfg.ForbiddenMimeTypes))
for _, mimeType := range cfg.ForbiddenMimeTypes {
forbiddenMimeTypes[mimeType] = true
@ -79,26 +78,15 @@ func NewClient(cfg config.ForgeConfig, respCache cache.ICache) (*Client, error)
defaultMimeType = "application/octet-stream"
}
sdkClient, err := gitea.NewClient(
sdk, err := gitea.NewClient(
giteaRoot,
gitea.SetHTTPClient(&http.Client{Timeout: 10 * time.Second}),
gitea.SetToken(cfg.Token),
gitea.SetUserAgent("pages-server/"+version.Version),
)
if err != nil {
return nil, err
}
sdkFileClient, err := gitea.NewClient(
giteaRoot,
gitea.SetHTTPClient(&http.Client{Timeout: 1 * time.Hour}),
gitea.SetHTTPClient(&stdClient),
gitea.SetToken(cfg.Token),
gitea.SetUserAgent("pages-server/"+version.Version),
)
return &Client{
sdkClient: sdkClient,
sdkFileClient: sdkFileClient,
sdkClient: sdk,
responseCache: respCache,
giteaRoot: giteaRoot,
@ -115,8 +103,8 @@ func (client *Client) ContentWebLink(targetOwner, targetRepo, branch, resource s
return path.Join(client.giteaRoot, targetOwner, targetRepo, "src/branch", branch, resource)
}
func (client *Client) GiteaRawContent(ctx *context.Context, targetOwner, targetRepo, ref, resource string) ([]byte, error) {
reader, _, _, err := client.ServeRawContent(ctx, targetOwner, targetRepo, ref, resource, false)
func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource string) ([]byte, error) {
reader, _, _, err := client.ServeRawContent(targetOwner, targetRepo, ref, resource)
if err != nil {
return nil, err
}
@ -124,9 +112,9 @@ func (client *Client) GiteaRawContent(ctx *context.Context, targetOwner, targetR
return io.ReadAll(reader)
}
func (client *Client) ServeRawContent(ctx *context.Context, targetOwner, targetRepo, ref, resource string, decompress bool) (io.ReadCloser, http.Header, int, error) {
func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource string) (io.ReadCloser, http.Header, int, error) {
cacheKey := fmt.Sprintf("%s/%s/%s|%s|%s", rawContentCacheKeyPrefix, targetOwner, targetRepo, ref, resource)
log := log.With().Str("ReqId", ctx.ReqId).Str("cache_key", cacheKey).Logger()
log := log.With().Str("cache_key", cacheKey).Logger()
log.Trace().Msg("try file in cache")
// handle if cache entry exist
if cacheMetadata, ok := client.responseCache.Get(cacheKey + "|Metadata"); ok {
@ -148,12 +136,12 @@ func (client *Client) ServeRawContent(ctx *context.Context, targetOwner, targetR
}
cache.Body = body.([]byte)
cachedHeader, cachedStatusCode := cache.createHttpResponse(cacheKey, decompress)
cachedHeader, cachedStatusCode := cache.createHttpResponse(cacheKey)
if cache.Exists {
if cache.IsSymlink {
linkDest := string(cache.Body)
log.Debug().Msgf("[cache] follow symlink from %q to %q", resource, linkDest)
return client.ServeRawContent(ctx, targetOwner, targetRepo, ref, linkDest, decompress)
return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest)
} else {
log.Debug().Msgf("[cache] return %d bytes", len(cache.Body))
return io.NopCloser(bytes.NewReader(cache.Body)), cachedHeader, cachedStatusCode, nil
@ -164,7 +152,7 @@ func (client *Client) ServeRawContent(ctx *context.Context, targetOwner, targetR
}
log.Trace().Msg("file not in cache")
// not in cache, open reader via gitea api
reader, resp, err := client.sdkFileClient.GetFileReader(targetOwner, targetRepo, ref, resource, client.supportLFS)
reader, resp, err := client.sdkClient.GetFileReader(targetOwner, targetRepo, ref, resource, client.supportLFS)
if resp != nil {
switch resp.StatusCode {
case http.StatusOK:
@ -205,27 +193,21 @@ func (client *Client) ServeRawContent(ctx *context.Context, targetOwner, targetR
}
log.Debug().Msgf("follow symlink from %q to %q", resource, linkDest)
return client.ServeRawContent(ctx, targetOwner, targetRepo, ref, linkDest, decompress)
return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest)
}
}
// now we are sure it's content so set the MIME type
mimeType, rawType := client.getMimeTypeByExtension(resource)
mimeType := client.getMimeTypeByExtension(resource)
resp.Response.Header.Set(ContentTypeHeader, mimeType)
if decompress {
resp.Response.Header.Set(ContentTypeHeader, mimeType)
} else {
resp.Response.Header.Set(ContentTypeHeader, rawType)
}
// now we write to cache and respond at the same time
fileResp := FileResponse{
Exists: true,
ETag: resp.Header.Get(ETagHeader),
MimeType: mimeType,
RawMime: rawType,
}
return fileResp.CreateCacheReader(ctx, reader, client.responseCache, cacheKey), resp.Response.Header, resp.StatusCode, nil
return fileResp.CreateCacheReader(reader, client.responseCache, cacheKey), resp.Response.Header, resp.StatusCode, nil
case http.StatusNotFound:
jsonToCache, err := json.Marshal(FileResponse{ETag: resp.Header.Get(ETagHeader)})
@ -358,29 +340,13 @@ func (client *Client) GiteaCheckIfOwnerExists(owner string) (bool, error) {
return false, nil
}
func (client *Client) extToMime(ext string) string {
mimeType := mime.TypeByExtension(path.Ext(ext))
func (client *Client) getMimeTypeByExtension(resource string) string {
mimeType := mime.TypeByExtension(path.Ext(resource))
mimeTypeSplit := strings.SplitN(mimeType, ";", 2)
if client.forbiddenMimeTypes[mimeTypeSplit[0]] || mimeType == "" {
mimeType = client.defaultMimeType
}
log.Trace().Msgf("probe mime of extension '%q' is '%q'", ext, mimeType)
log.Trace().Msgf("probe mime of %q is %q", resource, mimeType)
return mimeType
}
func (client *Client) getMimeTypeByExtension(resource string) (mimeType, rawType string) {
rawExt := path.Ext(resource)
innerExt := rawExt
switch rawExt {
case ".gz", ".br", ".zst":
innerExt = path.Ext(resource[:len(resource)-len(rawExt)])
}
rawType = client.extToMime(rawExt)
mimeType = rawType
if innerExt != rawExt {
mimeType = client.extToMime(innerExt)
}
log.Trace().Msgf("probe mime of %q is (%q / raw %q)", resource, mimeType, rawType)
return mimeType, rawType
}

View file

@ -26,9 +26,9 @@ func Handler(
canonicalDomainCache, redirectsCache cache.ICache,
) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
ctx := context.New(w, req)
log := log.With().Str("ReqId", ctx.ReqId).Strs("Handler", []string{req.Host, req.RequestURI}).Logger()
log.Debug().Msg("\n----------------------------------------------------------")
log := log.With().Strs("Handler", []string{req.Host, req.RequestURI}).Logger()
ctx := context.New(w, req)
ctx.RespWriter.Header().Set("Server", "pages-server")

View file

@ -47,7 +47,7 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
TargetBranch: targetBranch,
TargetPath: path.Join(pathParts...),
}, canonicalLink); works {
canonicalDomain, valid := targetOpt.CheckCanonicalDomain(ctx, giteaClient, trimmedHost, mainDomainSuffix, canonicalDomainCache)
canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHost, mainDomainSuffix, canonicalDomainCache)
if !valid {
html.ReturnErrorPage(ctx, "domain not specified in <code>.domains</code> file", http.StatusMisdirectedRequest)
return
@ -63,8 +63,8 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
return
}
log.Debug().Str("url", trimmedHost).Msg("tryBranch, now trying upstream")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
log.Debug().Msg("tryBranch, now trying upstream 7")
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
return
}

View file

@ -45,7 +45,7 @@ func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Clie
TargetPath: path.Join(pathElements[3:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve raw domain with specified branch")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
return
}
log.Debug().Msg("missing branch info")
@ -62,7 +62,7 @@ func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Clie
TargetPath: path.Join(pathElements[2:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve raw domain with default branch")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(ctx,
fmt.Sprintf("raw domain could not find repo <code>%s/%s</code> or repo is empty", targetOpt.TargetOwner, targetOpt.TargetRepo),

View file

@ -53,7 +53,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements[2:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve with specified repo and branch")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(
ctx,
@ -85,7 +85,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements[1:]...),
}, true); works {
log.Trace().Msg("tryUpstream: serve default pages repo with specified branch")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(
ctx,
@ -110,7 +110,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements[1:]...),
}, false); works {
log.Debug().Msg("tryBranch, now trying upstream 5")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
return
}
}
@ -126,7 +126,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements...),
}, false); works {
log.Debug().Msg("tryBranch, now trying upstream 6")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
return
}
}
@ -141,7 +141,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
TargetPath: path.Join(pathElements...),
}, false); works {
log.Debug().Msg("tryBranch, now trying upstream 6")
tryUpstream(log, ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
return
}

View file

@ -15,7 +15,7 @@ import (
)
// tryUpstream forwards the target request to the Gitea API, and shows an error page on failure.
func tryUpstream(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Client,
func tryUpstream(ctx *context.Context, giteaClient *gitea.Client,
mainDomainSuffix, trimmedHost string,
options *upstream.Options,
canonicalDomainCache cache.ICache,
@ -23,7 +23,7 @@ func tryUpstream(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Cl
) {
// check if a canonical domain exists on a request on MainDomain
if strings.HasSuffix(trimmedHost, mainDomainSuffix) && !options.ServeRaw {
canonicalDomain, _ := options.CheckCanonicalDomain(ctx, giteaClient, "", mainDomainSuffix, canonicalDomainCache)
canonicalDomain, _ := options.CheckCanonicalDomain(giteaClient, "", mainDomainSuffix, canonicalDomainCache)
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], mainDomainSuffix) {
canonicalPath := ctx.Req.RequestURI
if options.TargetRepo != defaultPagesRepo {
@ -32,12 +32,7 @@ func tryUpstream(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Cl
canonicalPath = "/" + path[2]
}
}
redirect_to := "https://" + canonicalDomain + canonicalPath
log.Debug().Str("to", redirect_to).Msg("redirecting")
ctx.Redirect(redirect_to, http.StatusTemporaryRedirect)
ctx.Redirect("https://"+canonicalDomain+canonicalPath, http.StatusTemporaryRedirect)
return
}
}
@ -46,7 +41,6 @@ func tryUpstream(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Cl
options.Host = trimmedHost
// Try to request the file from the Gitea API
log.Debug().Msg("requesting from upstream")
if !options.Upstream(ctx, giteaClient, redirectsCache) {
html.ReturnErrorPage(ctx, fmt.Sprintf("Forge returned %d %s", ctx.StatusCode, http.StatusText(ctx.StatusCode)), ctx.StatusCode)
}

View file

@ -27,7 +27,7 @@ import (
// Serve sets up and starts the web server.
func Serve(ctx *cli.Context) error {
// initialize logger with Trace, overridden later with actual level
log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).With().Timestamp().Caller().Logger().Level(zerolog.TraceLevel)
log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).With().Timestamp().Logger().Level(zerolog.TraceLevel)
cfg, err := config.ReadConfig(ctx)
if err != nil {
@ -41,8 +41,7 @@ func Serve(ctx *cli.Context) error {
if err != nil {
return err
}
fmt.Printf("Setting log level to: %s\n", logLevel)
log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).With().Timestamp().Caller().Logger().Level(logLevel)
log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).With().Timestamp().Logger().Level(logLevel)
listeningSSLAddress := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
listeningHTTPAddress := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.HttpPort)
@ -86,7 +85,7 @@ func Serve(ctx *cli.Context) error {
return err
}
if err := certificates.SetupMainDomainCertificates(log.Logger, cfg.Server.MainDomain, acmeClient, certDB); err != nil {
if err := certificates.SetupMainDomainCertificates(cfg.Server.MainDomain, acmeClient, certDB); err != nil {
return err
}
@ -115,7 +114,7 @@ func Serve(ctx *cli.Context) error {
interval := 12 * time.Hour
certMaintainCtx, cancelCertMaintain := context.WithCancel(context.Background())
defer cancelCertMaintain()
go certificates.MaintainCertDB(log.Logger, certMaintainCtx, interval, acmeClient, cfg.Server.MainDomain, certDB)
go certificates.MaintainCertDB(certMaintainCtx, interval, acmeClient, cfg.Server.MainDomain, certDB)
if cfg.Server.HttpServerEnabled {
// Create handler for http->https redirect and http acme challenges

View file

@ -8,7 +8,6 @@ import (
"github.com/rs/zerolog/log"
"codeberg.org/codeberg/pages/server/cache"
"codeberg.org/codeberg/pages/server/context"
"codeberg.org/codeberg/pages/server/gitea"
)
@ -18,7 +17,7 @@ var canonicalDomainCacheTimeout = 15 * time.Minute
const canonicalDomainConfig = ".domains"
// CheckCanonicalDomain returns the canonical domain specified in the repo (using the `.domains` file).
func (o *Options) CheckCanonicalDomain(ctx *context.Context, giteaClient *gitea.Client, actualDomain, mainDomainSuffix string, canonicalDomainCache cache.ICache) (domain string, valid bool) {
func (o *Options) CheckCanonicalDomain(giteaClient *gitea.Client, actualDomain, mainDomainSuffix string, canonicalDomainCache cache.ICache) (domain string, valid bool) {
// Check if this request is cached.
if cachedValue, ok := canonicalDomainCache.Get(o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch); ok {
domains := cachedValue.([]string)
@ -31,7 +30,7 @@ func (o *Options) CheckCanonicalDomain(ctx *context.Context, giteaClient *gitea.
return domains[0], valid
}
body, err := giteaClient.GiteaRawContent(ctx, o.TargetOwner, o.TargetRepo, o.TargetBranch, canonicalDomainConfig)
body, err := giteaClient.GiteaRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, canonicalDomainConfig)
if err != nil && !errors.Is(err, gitea.ErrorNotFound) {
log.Error().Err(err).Msgf("could not read %s of %s/%s", canonicalDomainConfig, o.TargetOwner, o.TargetRepo)
}

View file

@ -24,8 +24,5 @@ func (o *Options) setHeader(ctx *context.Context, header http.Header) {
} else {
ctx.RespWriter.Header().Set(gitea.ContentTypeHeader, mime)
}
if encoding := header.Get(gitea.ContentEncodingHeader); encoding != "" && encoding != "identity" {
ctx.RespWriter.Header().Set(gitea.ContentEncodingHeader, encoding)
}
ctx.RespWriter.Header().Set(headerLastModified, o.BranchTimestamp.In(time.UTC).Format(http.TimeFormat))
}

View file

@ -44,7 +44,7 @@ var redirectsCacheTimeout = 10 * time.Minute
const redirectsConfig = "_redirects"
// getRedirects returns redirects specified in the _redirects file.
func (o *Options) getRedirects(ctx *context.Context, giteaClient *gitea.Client, redirectsCache cache.ICache) []Redirect {
func (o *Options) getRedirects(giteaClient *gitea.Client, redirectsCache cache.ICache) []Redirect {
var redirects []Redirect
cacheKey := o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch
@ -53,7 +53,7 @@ func (o *Options) getRedirects(ctx *context.Context, giteaClient *gitea.Client,
redirects = cachedValue.([]Redirect)
} else {
// Get _redirects file and parse
body, err := giteaClient.GiteaRawContent(ctx, o.TargetOwner, o.TargetRepo, o.TargetBranch, redirectsConfig)
body, err := giteaClient.GiteaRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, redirectsConfig)
if err == nil {
for _, line := range strings.Split(string(body), "\n") {
redirectArr := strings.Fields(line)
@ -92,9 +92,8 @@ func (o *Options) matchRedirects(ctx *context.Context, giteaClient *gitea.Client
for _, redirect := range redirects {
if dstURL, ok := redirect.rewriteURL(reqURL); ok {
if o.TargetPath == dstURL { // recursion base case, rewrite directly when paths are the same
return true
} else if redirect.StatusCode == 200 { // do rewrite if status code is 200
// do rewrite if status code is 200
if redirect.StatusCode == 200 {
o.TargetPath = dstURL
o.Upstream(ctx, giteaClient, redirectsCache)
} else {

View file

@ -125,7 +125,7 @@ func AcceptEncodings(header string) []string {
// Upstream requests a file from the Gitea API at GiteaRoot and writes it to the request context.
func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redirectsCache cache.ICache) bool {
log := log.With().Str("ReqId", ctx.ReqId).Strs("upstream", []string{o.TargetOwner, o.TargetRepo, o.TargetBranch, o.TargetPath}).Logger()
log := log.With().Strs("upstream", []string{o.TargetOwner, o.TargetRepo, o.TargetBranch, o.TargetPath}).Logger()
log.Debug().Msg("Start")
@ -182,13 +182,10 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
// add extension for encoding
path := o.TargetPath + allowedEncodings[encoding]
reader, header, statusCode, err = giteaClient.ServeRawContent(ctx, o.TargetOwner, o.TargetRepo, o.TargetBranch, path, true)
if statusCode == http.StatusNotFound {
reader, header, statusCode, err = giteaClient.ServeRawContent(o.TargetOwner, o.TargetRepo, o.TargetBranch, path)
if statusCode == 404 {
continue
}
if err != nil {
break
}
log.Debug().Msgf("using %s encoding", encoding)
if encoding != "identity" {
header.Set(headerContentEncoding, encoding)
@ -206,7 +203,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
if err != nil && errors.Is(err, gitea.ErrorNotFound) {
log.Debug().Msg("Handling not found error")
// Get and match redirects
redirects := o.getRedirects(ctx, giteaClient, redirectsCache)
redirects := o.getRedirects(giteaClient, redirectsCache)
if o.matchRedirects(ctx, giteaClient, redirects, redirectsCache) {
log.Trace().Msg("redirect")
return true
@ -234,7 +231,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
}
}
log.Debug().Msg("not found")
log.Trace().Msg("not found")
ctx.StatusCode = http.StatusNotFound
if o.TryIndexPages {