Compare commits

...

17 Commits

Author SHA1 Message Date
Max Stanley
53efc01268 Fix lint 2024-08-25 22:22:51 +01:00
Max Stanley
b2d40c5154 Support multiple canonical-domain-files 2024-08-25 22:13:08 +01:00
Max Stanley
2410137438 Support canonical-domain-file configuration 2024-08-23 21:57:24 +01:00
Dependency bot
557a295732 chore(deps): update golangci/golangci-lint docker tag to v1.60.1 (#381)
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [golangci/golangci-lint](https://github.com/golangci/golangci-lint) | minor | `v1.59.1` -> `v1.60.1` |

---

### Release Notes

<details>
<summary>golangci/golangci-lint (golangci/golangci-lint)</summary>

### [`v1.60.1`](https://github.com/golangci/golangci-lint/blob/HEAD/CHANGELOG.md#v1601)

[Compare Source](https://github.com/golangci/golangci-lint/compare/v1.59.1...v1.60.1)

1.  Updated linters
    -   `errorlint`: from 1.5.2 to 1.6.0
    -   `exhaustruct`: from 3.2.0 to 3.3.0 (recognize custom error values in return)
    -   `fatcontext`: from 0.2.2 to 0.4.0 (fix false positives for context stored in structs)
    -   `gocognit`: from 1.1.2 to 1.1.3
    -   `gomodguard`: from 1.3.2 to 1.3.3
    -   `govet` (`printf`): report non-constant format, no args
    -   `lll`: advertise max line length instead of just reporting failure
    -   `revive`: from 1.3.7 to 1.3.9 (new rule: `comments-density`)
    -   `sloglint`: from 0.7.1 to 0.7.2
    -   `spancheck`: from 0.6.1 to 0.6.2
    -   `staticcheck`: from 0.4.7 to 0.5.0
    -   `tenv`: from 1.7.1 to 1.10.0 (remove reports on fuzzing)
    -   `testifylint`: from 1.3.1 to 1.4.3 (new options: `formatter`, `suite-broken-parallel`, `suite-subtest-run`)
    -   `tparallel`: from 0.3.1 to 0.3.2
    -   `usestdlibvars`: from 1.26.0 to 1.27.0 (fix false-positive with number used inside a mathematical operations)
    -   `wsl`: from 4.2.1 to 4.4.1
    -   ️⚠️ `unused`: remove `exported-is-used` option
2.  Fixes
    -   SARIF: sanitize level property
    -   ️⚠️ `typecheck` issues should never be ignored
3.  Documentation
    -   Add link on linter without configuration
    -   Remove 'trusted by' page
    -   `wsl` update documentation of the configuration
4.  misc.
    -   🎉 go1.23 support

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" (UTC), Automerge - "before 4am" (UTC).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40NDAuNyIsInVwZGF0ZWRJblZlciI6IjM3LjQ0MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: woodpecker-bot <woodpecker-bot@obermui.de>
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/381
Co-authored-by: Dependency bot <renovate-bot@noreply.codeberg.org>
Co-committed-by: Dependency bot <renovate-bot@noreply.codeberg.org>
2024-08-19 20:20:59 +00:00
Dependency bot
c76daaca4d chore(deps): update golang docker tag to v1.23 (#380)
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| golang | minor | `1.22` -> `1.23` |

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" (UTC), Automerge - "before 4am" (UTC).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40NDAuNyIsInVwZGF0ZWRJblZlciI6IjM3LjQ0MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: woodpecker-bot <woodpecker-bot@obermui.de>
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/380
Co-authored-by: Dependency bot <renovate-bot@noreply.codeberg.org>
Co-committed-by: Dependency bot <renovate-bot@noreply.codeberg.org>
2024-08-19 20:20:07 +00:00
Dependency bot
6cff8d2ee9 chore(deps): update woodpeckerci/plugin-release docker tag to v0.2.1 (#376)
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [woodpeckerci/plugin-release](https://codeberg.org/woodpecker-plugins/release) ([source](https://codeberg.org/woodpecker-plugins/release.git)) | minor | `0.1.0` -> `0.2.1` |

---

### Release Notes

<details>
<summary>woodpecker-plugins/release (woodpeckerci/plugin-release)</summary>

### [`v0.2.1`](https://codeberg.org/woodpecker-plugins/release/releases/tag/v0.2.1)

[Compare Source](https://codeberg.org/woodpecker-plugins/release/compare/v0.2.0...v0.2.1)

-   Fix infinite loop ([#&#8203;13](https://github.com/woodpecker-plugins/release/issues/13))

### [`v0.2.0`](https://codeberg.org/woodpecker-plugins/release/releases/tag/v0.2.0)

[Compare Source](https://codeberg.org/woodpecker-plugins/release/compare/v0.1.0...v0.2.0)

### Bugfix

-   Fix loading without releases ([#&#8203;9](https://github.com/woodpecker-plugins/release/issues/9))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" (UTC), Automerge - "before 4am" (UTC).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40NDAuNyIsInVwZGF0ZWRJblZlciI6IjM3LjQ0MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: woodpecker-bot <woodpecker-bot@obermui.de>
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/376
Co-authored-by: Dependency bot <renovate-bot@noreply.codeberg.org>
Co-committed-by: Dependency bot <renovate-bot@noreply.codeberg.org>
2024-08-19 20:19:04 +00:00
Gnaaarwhal
9524b1eb12 Fix typo in README.md (#374)
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/374
Reviewed-by: crapStone <codeberg@crapstone.dev>
Co-authored-by: Gnaaarwhal <gnaaarwhal@noreply.codeberg.org>
Co-committed-by: Gnaaarwhal <gnaaarwhal@noreply.codeberg.org>
2024-08-02 12:52:44 +00:00
crapStone
c9be1ce75d fix docker latest tagging (#372)
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/372
Co-authored-by: crapStone <me@crapstone.dev>
Co-committed-by: crapStone <me@crapstone.dev>
2024-07-23 21:18:06 +00:00
crapStone
5265b3884b
don't depend on lint for push to main 2024-07-23 22:58:34 +02:00
crapStone
68825a1727 improve pipeline config (#371)
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/371
Co-authored-by: crapStone <me@crapstone.dev>
Co-committed-by: crapStone <me@crapstone.dev>
2024-07-23 20:32:46 +00:00
Dependency bot
abbebbbcee fix(deps): update golang.org/x/exp digest to 8a7402a (#368) 2024-07-23 20:19:44 +00:00
Dependency bot
6ce17461e6 chore(deps): update woodpeckerci/plugin-docker-buildx docker tag to v4.2.0 (#362)
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [woodpeckerci/plugin-docker-buildx](https://codeberg.org/woodpecker-plugins/docker-buildx) ([source](https://codeberg.org/woodpecker-plugins/docker-buildx.git)) | minor | `4.0.0` -> `4.2.0` |
| [woodpeckerci/plugin-docker-buildx](https://codeberg.org/woodpecker-plugins/docker-buildx) ([source](https://codeberg.org/woodpecker-plugins/docker-buildx.git)) | major | `3.2.1` -> `4.2.0` |

---

### Release Notes

<details>
<summary>woodpecker-plugins/docker-buildx (woodpeckerci/plugin-docker-buildx)</summary>

### [`v4.2.0`](https://codeberg.org/woodpecker-plugins/docker-buildx/releases/tag/v4.2.0)

[Compare Source](https://codeberg.org/woodpecker-plugins/docker-buildx/compare/v4.1.0...v4.2.0)

##### Features

-   Add dedicated setting to automatically handle proxy configuration ([#&#8203;171](https://github.com/woodpecker-plugins/docker-buildx/issues/171))

##### Dependencies

-   chore(deps): update docker/buildx-bin docker tag to v0.16.0
-   fix(deps): update module github.com/aws/aws-sdk-go to v1.54.19

### [`v4.1.0`](https://codeberg.org/woodpecker-plugins/docker-buildx/releases/tag/v4.1.0)

[Compare Source](https://codeberg.org/woodpecker-plugins/docker-buildx/compare/v4.0.0...v4.1.0)

##### Features

-   Pass Daemon.Mirror to Docker daemon ([#&#8203;165](https://github.com/woodpecker-plugins/docker-buildx/issues/165))

##### Bug Fixes

-   Respect repository mirrors without login credentials ([#&#8203;164](https://github.com/woodpecker-plugins/docker-buildx/issues/164))

##### Dependencies

-   chore(deps): update docker/buildx-bin docker tag to v0.15.1
-   chore(deps): update docker docker tag to v26.1.4

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "every weekend" (UTC), Automerge - "before 4am" (UTC).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40MzEuMCIsInVwZGF0ZWRJblZlciI6IjM3LjQzMi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: woodpecker-bot <woodpecker-bot@obermui.de>
Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/362
Reviewed-by: crapStone <codeberg@crapstone.dev>
Co-authored-by: Dependency bot <renovate-bot@noreply.codeberg.org>
Co-committed-by: Dependency bot <renovate-bot@noreply.codeberg.org>
2024-07-23 20:01:02 +00:00
crapStone
efd1adae0f fix woodpecker pipeline definition (#370)
use https://woodpecker-ci.org/plugins/Release instead of the old drone plugin

Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/370
Co-authored-by: crapStone <me@crapstone.dev>
Co-committed-by: crapStone <me@crapstone.dev>
2024-07-23 19:50:54 +00:00
Peter Gerber
bc9111a05f Use correct timestamp format for Last-Modified header (#365)
HTTP uses GMT [1,2] rather than UTC as timezone for timestamps. However,
the Last-Modified header used UTC which confused at least wget.

Before, UTC was used:

$ wget --no-check-certificate -S --spider https://cb_pages_tests.localhost.mock.directory:4430/images/827679288a.jpg
...
  Last-Modified: Sun, 11 Sep 2022 08:37:42 UTC
...
Last-modified header invalid -- time-stamp ignored.
...

After, GMT is used:

$ wget --no-check-certificate -S --spider https://cb_pages_tests.localhost.mock.directory:4430/images/827679288a.jpg
...
  Last-Modified: Sun, 11 Sep 2022 08:37:42 GMT
...
(no last-modified-header-invalid warning)

[1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified
[2]: https://www.rfc-editor.org/rfc/rfc9110#name-date-time-formats

Fixes #364

---

Whatt I noticed is that the If-Modified-Since header isn't accepted (neither with GMT nor with UTC):

```
$ wget --header "If-Modified-Since: Sun, 11 Sep 2022 08:37:42 GMT" --no-check-certificate -S --spider https://cb_pages_tests.localhost.mock.directory:4430/images/827679288a.jpg
Spider mode enabled. Check if remote file exists.
--2024-07-15 23:31:41--  https://cb_pages_tests.localhost.mock.directory:4430/images/827679288a.jpg
Resolving cb_pages_tests.localhost.mock.directory (cb_pages_tests.localhost.mock.directory)... 127.0.0.1
Connecting to cb_pages_tests.localhost.mock.directory (cb_pages_tests.localhost.mock.directory)|127.0.0.1|:4430... connected.
WARNING: The certificate of ‘cb_pages_tests.localhost.mock.directory’ is not trusted.
WARNING: The certificate of ‘cb_pages_tests.localhost.mock.directory’ doesn't have a known issuer.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Allow: GET, HEAD, OPTIONS
  Cache-Control: public, max-age=600
  Content-Length: 124635
  Content-Type: image/jpeg
  Etag: "073af1960852e2a4ef446202c7974768b9881814"
  Last-Modified: Sun, 11 Sep 2022 08:37:42 GMT
  Referrer-Policy: strict-origin-when-cross-origin
  Server: pages-server
  Strict-Transport-Security: max-age=63072000; includeSubdomains; preload
  Date: Mon, 15 Jul 2024 21:31:42 GMT
Length: 124635 (122K) [image/jpeg]
Remote file exists
```

I would have expected a 304 (Not Modified) rather than a 200 (OK). I assume this is simply not supported and on production 304 is returned by a caching proxy in front of pages-server.

Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/365
Reviewed-by: crapStone <codeberg@crapstone.dev>
Co-authored-by: Peter Gerber <peter@arbitrary.ch>
Co-committed-by: Peter Gerber <peter@arbitrary.ch>
2024-07-23 18:42:24 +00:00
Dependency bot
17530a065b fix(deps): update golang.org/x/exp digest to 46b0784 (#363) 2024-07-14 01:21:11 +00:00
Dependency bot
d583587773 chore(deps): update mstruebing/editorconfig-checker docker tag to v3.0.3 (#360) 2024-07-08 00:52:53 +00:00
Dependency bot
4e44ea1d58 chore(deps): update pipelinecomponents/yamllint docker tag to v0.31.3 (#361) 2024-07-07 01:09:14 +00:00
19 changed files with 280 additions and 180 deletions

View File

@ -1,71 +1,59 @@
when:
- event: [pull_request, tag, cron]
- event: push
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- renovate/*
depends_on:
- lint
- event: [push, pull_request, tag, cron]
branch: ${CI_REPO_DEFAULT_BRANCH}
steps:
# use vendor to cache dependencies
vendor:
image: golang:1.22
image: golang:1.23
commands:
- go mod vendor
build:
depends_on: vendor
image: codeberg.org/6543/docker-images/golang_just
pull: true
commands:
- go version
- just build
when:
- event: [push, pull_request]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- renovate/*
docker-dryrun:
depends_on: vendor
image: woodpeckerci/plugin-docker-buildx:4.0.0
image: woodpeckerci/plugin-docker-buildx:4.2.0
settings:
dockerfile: Dockerfile
platforms: linux/amd64
dry-run: true
tags: latest
when:
- event: [push, pull_request]
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- renovate/*
- event: [pull_request]
path: Dockerfile
build-tag:
depends_on: vendor
image: codeberg.org/6543/docker-images/golang_just
pull: true
commands:
- go version
- just build-tag ${CI_COMMIT_TAG##v}
when:
- event: ['tag']
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- event: [tag]
test:
depends_on: build
image: codeberg.org/6543/docker-images/golang_just
pull: true
commands:
- just test
when:
- event: pull_request
- event: push
branch: renovate/*
- event: [pull_request]
integration-tests:
depends_on: build
image: codeberg.org/6543/docker-images/golang_just
pull: true
commands:
- just integration
environment:
@ -74,32 +62,23 @@ steps:
- RAW_DOMAIN=raw.localhost.mock.directory
- PORT=4430
when:
- event: pull_request
- event: push
branch: renovate/*
- event: [pull_request]
release:
depends_on: build
image: plugins/gitea-release:1.1.0
image: woodpeckerci/plugin-release:0.2.1
settings:
base_url: https://codeberg.org
file_exists: overwrite
files: build/codeberg-pages-server
api_key:
from_secret: bot_token
environment:
- CI_REPO_OWNER=${CI_REPO_OWNER}
- CI_REPO_NAME=${CI_REPO_NAME}
- CI_BUILD_EVENT=${CI_BUILD_EVENT}
- CI_COMMIT_REF=${CI_COMMIT_REF}
when:
- event: ['tag']
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- event: [tag]
docker-next:
depends_on: vendor
image: woodpeckerci/plugin-docker-buildx:4.0.0
image: woodpeckerci/plugin-docker-buildx:4.2.0
settings:
registry: codeberg.org
dockerfile: Dockerfile
@ -111,11 +90,10 @@ steps:
password:
from_secret: bot_token
when:
- event: ['push']
branch: ${CI_REPO_DEFAULT_BRANCH}
- event: [push]
'Publish PR image':
image: woodpeckerci/plugin-docker-buildx:3.2.1
image: woodpeckerci/plugin-docker-buildx:4.2.0
depends_on: test
settings:
registry: codeberg.org
@ -131,9 +109,9 @@ steps:
evaluate: 'CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_image"'
event: pull_request
docker-tag:
docker-release:
depends_on: vendor
image: woodpeckerci/plugin-docker-buildx:4.0.0
image: woodpeckerci/plugin-docker-buildx:4.2.0
settings:
registry: codeberg.org
dockerfile: Dockerfile
@ -145,5 +123,4 @@ steps:
password:
from_secret: bot_token
when:
- event: ['push']
branch: ${CI_REPO_DEFAULT_BRANCH}
- event: [tag]

View File

@ -1,41 +1,27 @@
when:
- event: pull_request
- event: push
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- renovate/**
steps:
lint:
depends_on: []
image: golangci/golangci-lint:v1.59.1
image: golangci/golangci-lint:v1.60.1
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 5m --build-tags integration
when:
- event: pull_request
- event: push
branch: renovate/*
editor-config:
depends_on: []
image: mstruebing/editorconfig-checker:v3.0.1
when:
- event: pull_request
- event: push
branch: renovate/*
image: mstruebing/editorconfig-checker:v3.0.3
yamllint:
image: pipelinecomponents/yamllint:0.31.2
image: pipelinecomponents/yamllint:0.31.3
depends_on: []
commands:
- yamllint .
when:
- event: pull_request
- event: push
branch: renovate/*
prettier:
image: docker.io/woodpeckerci/plugin-prettier:0.1.0

View File

@ -70,7 +70,7 @@ This will trigger a build of the PR which will build a docker image to be used f
### Environment Variables
- `ACME_ACCEPT_TERMS` (default: use self-signed certificate): Set this to "true" to accept the Terms of Service of your ACME provider.
- `ACME_API` (default: <https://acme-v02.api.letsencrypt.org/directory>): set this to <https://acme.mock.director> to use invalid certificates without any verification (great for debugging). ZeroSSL might be better in the future as it doesn't have rate limits and doesn't clash with the official Codeberg certificates (which are using Let's Encrypt), but I couldn't get it to work yet.
- `ACME_API` (default: <https://acme-v02.api.letsencrypt.org/directory>): set this to <https://acme.mock.directory> to use invalid certificates without any verification (great for debugging). ZeroSSL might be better in the future as it doesn't have rate limits and doesn't clash with the official Codeberg certificates (which are using Let's Encrypt), but I couldn't get it to work yet.
- `ACME_EAB_KID` & `ACME_EAB_HMAC` (default: don't use EAB): EAB credentials, for example for ZeroSSL.
- `ACME_EMAIL` (default: `noreply@example.email`): Set the email sent to the ACME API server to receive, for example, renewal reminders.
- `ACME_USE_RATE_LIMITS` (default: true): Set this to false to disable rate limits, e.g. with ZeroSSL.

View File

@ -81,6 +81,12 @@ var (
Usage: "specifies the domain from which raw repository content shall be served, not set disable raw content hosting",
EnvVars: []string{"RAW_DOMAIN"},
},
&cli.StringSliceFlag{
Name: "canonical-domain-file",
Usage: "specifies the file from which the canonical domain may be specified in. Use this flag multiple times to support multiple different file names, if multiple files exist in a single repository they will be merged.",
EnvVars: []string{"CANONICAL_DOMAIN_FILES"},
Value: cli.NewStringSlice(".domains"),
},
// #########################
// ### Page Server Setup ###

View File

@ -9,15 +9,16 @@ type Config struct {
}
type ServerConfig struct {
Host string `default:"[::]"`
Port uint16 `default:"443"`
HttpPort uint16 `default:"80"`
HttpServerEnabled bool `default:"true"`
MainDomain string
RawDomain string
PagesBranches []string
AllowedCorsDomains []string
BlacklistedPaths []string
Host string `default:"[::]"`
Port uint16 `default:"443"`
HttpPort uint16 `default:"80"`
HttpServerEnabled bool `default:"true"`
MainDomain string
RawDomain string
CanonicalDomainFiles []string `default:"[\".domains\"]"`
PagesBranches []string `default:"[\"main\", \"master\", \"pages\"]"`
AllowedCorsDomains []string
BlacklistedPaths []string
}
type ForgeConfig struct {

View File

@ -20,9 +20,6 @@ func NewDefaultConfig() Config {
panic(err)
}
// defaults does not support setting arrays from strings
config.Server.PagesBranches = []string{"main", "master", "pages"}
return config
}
@ -75,6 +72,9 @@ func mergeServerConfig(ctx *cli.Context, config *ServerConfig) {
if ctx.IsSet("raw-domain") {
config.RawDomain = ctx.String("raw-domain")
}
if ctx.IsSet("canonical-domain-file") {
config.CanonicalDomainFiles = ctx.StringSlice("canonical-domain-file")
}
if ctx.IsSet("pages-branch") {
config.PagesBranches = ctx.StringSlice("pages-branch")
}

View File

@ -136,15 +136,16 @@ func TestMergeConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *testing.T
cfg := &Config{
LogLevel: "original",
Server: ServerConfig{
Host: "original",
Port: 8080,
HttpPort: 80,
HttpServerEnabled: false,
MainDomain: "original",
RawDomain: "original",
PagesBranches: []string{"original"},
AllowedCorsDomains: []string{"original"},
BlacklistedPaths: []string{"original"},
Host: "original",
Port: 8080,
HttpPort: 80,
HttpServerEnabled: false,
MainDomain: "original",
RawDomain: "original",
CanonicalDomainFiles: []string{"original"},
PagesBranches: []string{"original"},
AllowedCorsDomains: []string{"original"},
BlacklistedPaths: []string{"original"},
},
Forge: ForgeConfig{
Root: "original",
@ -176,15 +177,16 @@ func TestMergeConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *testing.T
expectedConfig := &Config{
LogLevel: "changed",
Server: ServerConfig{
Host: "changed",
Port: 8443,
HttpPort: 443,
HttpServerEnabled: true,
MainDomain: "changed",
RawDomain: "changed",
PagesBranches: []string{"changed"},
AllowedCorsDomains: []string{"changed"},
BlacklistedPaths: append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...),
Host: "changed",
Port: 8443,
HttpPort: 443,
HttpServerEnabled: true,
MainDomain: "changed",
RawDomain: "changed",
CanonicalDomainFiles: []string{"changed"},
PagesBranches: []string{"changed"},
AllowedCorsDomains: []string{"changed"},
BlacklistedPaths: append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...),
},
Forge: ForgeConfig{
Root: "changed",
@ -220,6 +222,7 @@ func TestMergeConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *testing.T
// Server
"--pages-domain", "changed",
"--raw-domain", "changed",
"--canonical-domain-file", "changed",
"--allowed-cors-domains", "changed",
"--blacklisted-paths", "changed",
"--pages-branch", "changed",
@ -273,27 +276,29 @@ func TestMergeServerConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *tes
t,
func(ctx *cli.Context) error {
cfg := &ServerConfig{
Host: "original",
Port: 8080,
HttpPort: 80,
HttpServerEnabled: false,
MainDomain: "original",
RawDomain: "original",
AllowedCorsDomains: []string{"original"},
BlacklistedPaths: []string{"original"},
Host: "original",
Port: 8080,
HttpPort: 80,
HttpServerEnabled: false,
MainDomain: "original",
RawDomain: "original",
CanonicalDomainFiles: []string{"original"},
AllowedCorsDomains: []string{"original"},
BlacklistedPaths: []string{"original"},
}
mergeServerConfig(ctx, cfg)
expectedConfig := &ServerConfig{
Host: "changed",
Port: 8443,
HttpPort: 443,
HttpServerEnabled: true,
MainDomain: "changed",
RawDomain: "changed",
AllowedCorsDomains: fixArrayFromCtx(ctx, "allowed-cors-domains", []string{"changed"}),
BlacklistedPaths: fixArrayFromCtx(ctx, "blacklisted-paths", append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...)),
Host: "changed",
Port: 8443,
HttpPort: 443,
HttpServerEnabled: true,
MainDomain: "changed",
RawDomain: "changed",
CanonicalDomainFiles: fixArrayFromCtx(ctx, "canonical-domain-file", []string{"changed"}),
AllowedCorsDomains: fixArrayFromCtx(ctx, "allowed-cors-domains", []string{"changed"}),
BlacklistedPaths: fixArrayFromCtx(ctx, "blacklisted-paths", append([]string{"changed"}, ALWAYS_BLACKLISTED_PATHS...)),
}
assert.Equal(t, expectedConfig, cfg)
@ -303,6 +308,7 @@ func TestMergeServerConfigShouldReplaceAllExistingValuesGivenAllArgsExist(t *tes
[]string{
"--pages-domain", "changed",
"--raw-domain", "changed",
"--canonical-domain-file", "changed",
"--allowed-cors-domains", "changed",
"--blacklisted-paths", "changed",
"--host", "changed",
@ -326,6 +332,7 @@ func TestMergeServerConfigShouldReplaceOnlyOneValueExistingValueGivenOnlyOneArgE
{args: []string{"--enable-http-server"}, callback: func(sc *ServerConfig) { sc.HttpServerEnabled = true }},
{args: []string{"--pages-domain", "changed"}, callback: func(sc *ServerConfig) { sc.MainDomain = "changed" }},
{args: []string{"--raw-domain", "changed"}, callback: func(sc *ServerConfig) { sc.RawDomain = "changed" }},
{args: []string{"--canonical-domain-file", "changed"}, callback: func(sc *ServerConfig) { sc.CanonicalDomainFiles = []string{"changed"} }},
{args: []string{"--pages-branch", "changed"}, callback: func(sc *ServerConfig) { sc.PagesBranches = []string{"changed"} }},
{args: []string{"--allowed-cors-domains", "changed"}, callback: func(sc *ServerConfig) { sc.AllowedCorsDomains = []string{"changed"} }},
{args: []string{"--blacklisted-paths", "changed"}, callback: func(sc *ServerConfig) { sc.BlacklistedPaths = []string{"changed"} }},
@ -336,21 +343,23 @@ func TestMergeServerConfigShouldReplaceOnlyOneValueExistingValueGivenOnlyOneArgE
t,
func(ctx *cli.Context) error {
cfg := ServerConfig{
Host: "original",
Port: 8080,
HttpPort: 80,
HttpServerEnabled: false,
MainDomain: "original",
RawDomain: "original",
PagesBranches: []string{"original"},
AllowedCorsDomains: []string{"original"},
BlacklistedPaths: []string{"original"},
Host: "original",
Port: 8080,
HttpPort: 80,
HttpServerEnabled: false,
MainDomain: "original",
RawDomain: "original",
CanonicalDomainFiles: []string{"original"},
PagesBranches: []string{"original"},
AllowedCorsDomains: []string{"original"},
BlacklistedPaths: []string{"original"},
}
expectedConfig := cfg
pair.callback(&expectedConfig)
expectedConfig.BlacklistedPaths = append(expectedConfig.BlacklistedPaths, ALWAYS_BLACKLISTED_PATHS...)
expectedConfig.CanonicalDomainFiles = fixArrayFromCtx(ctx, "canonical-domain-file", expectedConfig.CanonicalDomainFiles)
expectedConfig.PagesBranches = fixArrayFromCtx(ctx, "pages-branch", expectedConfig.PagesBranches)
expectedConfig.AllowedCorsDomains = fixArrayFromCtx(ctx, "allowed-cors-domains", expectedConfig.AllowedCorsDomains)
expectedConfig.BlacklistedPaths = fixArrayFromCtx(ctx, "blacklisted-paths", expectedConfig.BlacklistedPaths)

2
go.mod
View File

@ -20,7 +20,7 @@ require (
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-20240613232115-7f521ea00fb8
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
xorm.io/xorm v1.3.2
)

12
go.sum
View File

@ -786,8 +786,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -810,8 +810,8 @@ 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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=
@ -1004,8 +1004,8 @@ golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -32,6 +32,7 @@ func TLSConfig(mainDomainSuffix string,
giteaClient *gitea.Client,
acmeClient *AcmeClient,
firstDefaultBranch string,
canonicalDomainConfigs []string,
challengeCache, canonicalDomainCache cache.ICache,
certDB database.CertDB,
noDNS01 bool,
@ -100,10 +101,10 @@ func TLSConfig(mainDomainSuffix string,
TargetRepo: targetRepo,
TargetBranch: targetBranch,
}
_, valid := targetOpt.CheckCanonicalDomain(giteaClient, domain, mainDomainSuffix, canonicalDomainCache)
_, valid := targetOpt.CheckCanonicalDomain(giteaClient, domain, mainDomainSuffix, canonicalDomainConfigs, canonicalDomainCache)
if !valid {
// We shouldn't obtain a certificate when we cannot check if the
// repository has specified this domain in the `.domains` file.
// repository has specified this domain in the specified canonical domain file such as the `.domains` file.
mayObtainCert = false
}
}
@ -196,7 +197,7 @@ func (c *AcmeClient) retrieveCertFromDB(sni, mainDomainSuffix string, useDnsProv
// renew certificates 7 days before they expire
if tlsCertificate.Leaf.NotAfter.Before(time.Now().Add(7 * 24 * time.Hour)) {
// TODO: use ValidTill of custom cert struct
if res.CSR != nil && len(res.CSR) > 0 {
if len(res.CSR) > 0 {
// CSR stores the time when the renewal shall be tried again
nextTryUnix, err := strconv.ParseInt(string(res.CSR), 10, 64)
if err == nil && time.Now().Before(time.Unix(nextTryUnix, 0)) {

View File

@ -92,6 +92,7 @@ func Handler(
cfg.MainDomain,
trimmedHost,
pathElements,
cfg.CanonicalDomainFiles,
canonicalDomainCache, redirectsCache)
} else if strings.HasSuffix(trimmedHost, cfg.MainDomain) {
log.Debug().Msg("subdomain request detected")
@ -100,6 +101,7 @@ func Handler(
cfg.PagesBranches,
trimmedHost,
pathElements,
cfg.CanonicalDomainFiles,
canonicalDomainCache, redirectsCache)
} else {
log.Debug().Msg("custom domain request detected")
@ -108,6 +110,7 @@ func Handler(
trimmedHost,
pathElements,
cfg.PagesBranches[0],
cfg.CanonicalDomainFiles,
canonicalDomainCache, redirectsCache)
}
}

View File

@ -1,6 +1,7 @@
package handler
import (
"fmt"
"net/http"
"path"
"strings"
@ -19,6 +20,7 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
trimmedHost string,
pathElements []string,
firstDefaultBranch string,
canonicalDomainConfigs []string,
canonicalDomainCache, redirectsCache cache.ICache,
) {
// Serve pages from custom domains
@ -47,9 +49,10 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
TargetBranch: targetBranch,
TargetPath: path.Join(pathParts...),
}, canonicalLink); works {
canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHost, mainDomainSuffix, canonicalDomainCache)
canonicalDomain, valid := targetOpt.CheckCanonicalDomain(giteaClient, trimmedHost, mainDomainSuffix, canonicalDomainConfigs, canonicalDomainCache)
if !valid {
html.ReturnErrorPage(ctx, "domain not specified in <code>.domains</code> file", http.StatusMisdirectedRequest)
msg := fmt.Sprintf("canonical domain not specified, files checked: <code>%s</code>", strings.Join(canonicalDomainConfigs, "</code>, <code>"))
html.ReturnErrorPage(ctx, msg, http.StatusMisdirectedRequest)
return
} else if canonicalDomain != trimmedHost {
// only redirect if the target is also a codeberg page!
@ -64,7 +67,7 @@ func handleCustomDomain(log zerolog.Logger, ctx *context.Context, giteaClient *g
}
log.Debug().Msg("tryBranch, now trying upstream 7")
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}

View File

@ -19,6 +19,7 @@ func handleRaw(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Clie
mainDomainSuffix string,
trimmedHost string,
pathElements []string,
canonicalDomainConfigs []string,
canonicalDomainCache, redirectsCache cache.ICache,
) {
// Serve raw content from RawDomain
@ -45,7 +46,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(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
log.Debug().Msg("missing branch info")
@ -62,7 +63,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(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, 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

@ -21,6 +21,7 @@ func handleSubDomain(log zerolog.Logger, ctx *context.Context, giteaClient *gite
defaultPagesBranches []string,
trimmedHost string,
pathElements []string,
canonicalDomainConfigs []string,
canonicalDomainCache, redirectsCache cache.ICache,
) {
// Serve pages from subdomains of MainDomainSuffix
@ -53,7 +54,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(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(
ctx,
@ -85,7 +86,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(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
} else {
html.ReturnErrorPage(
ctx,
@ -110,7 +111,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(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
}
@ -126,7 +127,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(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}
}
@ -141,7 +142,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(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainCache, redirectsCache)
tryUpstream(ctx, giteaClient, mainDomainSuffix, trimmedHost, targetOpt, canonicalDomainConfigs, canonicalDomainCache, redirectsCache)
return
}

View File

@ -18,12 +18,13 @@ import (
func tryUpstream(ctx *context.Context, giteaClient *gitea.Client,
mainDomainSuffix, trimmedHost string,
options *upstream.Options,
canonicalDomainConfigs []string,
canonicalDomainCache cache.ICache,
redirectsCache cache.ICache,
) {
// check if a canonical domain exists on a request on MainDomain
if strings.HasSuffix(trimmedHost, mainDomainSuffix) && !options.ServeRaw {
canonicalDomain, _ := options.CheckCanonicalDomain(giteaClient, "", mainDomainSuffix, canonicalDomainCache)
canonicalDomain, _ := options.CheckCanonicalDomain(giteaClient, "", mainDomainSuffix, canonicalDomainConfigs, canonicalDomainCache)
if !strings.HasSuffix(strings.SplitN(canonicalDomain, "/", 2)[0], mainDomainSuffix) {
canonicalPath := ctx.Req.RequestURI
if options.TargetRepo != defaultPagesRepo {

View File

@ -101,6 +101,7 @@ func Serve(ctx *cli.Context) error {
giteaClient,
acmeClient,
cfg.Server.PagesBranches[0],
cfg.Server.CanonicalDomainFiles,
challengeCache, canonicalDomainCache,
certDB,
cfg.ACME.NoDNS01,

View File

@ -14,57 +14,92 @@ import (
// canonicalDomainCacheTimeout specifies the timeout for the canonical domain cache.
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(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)
for _, domain := range domains {
if domain == actualDomain {
valid = true
break
}
}
return domains[0], valid
}
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)
}
func (o *Options) CheckCanonicalDomain(giteaClient *gitea.Client, actualDomain, mainDomainSuffix string, canonicalDomainConfigs []string, canonicalDomainCache cache.ICache) (domain string, valid bool) {
canonicalDomainCacheKey := o.TargetOwner + "/" + o.TargetRepo + "/" + o.TargetBranch + "/(" + strings.Join(canonicalDomainConfigs, "|") + ")"
var domains []string
for _, domain := range strings.Split(string(body), "\n") {
domain = strings.ToLower(domain)
domain = strings.TrimSpace(domain)
domain = strings.TrimPrefix(domain, "http://")
domain = strings.TrimPrefix(domain, "https://")
if domain != "" && !strings.HasPrefix(domain, "#") && !strings.ContainsAny(domain, "\t /") && strings.ContainsRune(domain, '.') {
domains = append(domains, domain)
}
// Check if this request is cached.
if cachedValue, ok := canonicalDomainCache.Get(canonicalDomainCacheKey); ok {
domains = cachedValue.([]string)
} else {
// Create cache entry for future invocations.
domains = o.canonicalDomainList(giteaClient, mainDomainSuffix, canonicalDomainConfigs)
// Add result to cache.
_ = canonicalDomainCache.Set(canonicalDomainCacheKey, domains, canonicalDomainCacheTimeout)
}
for _, domain := range domains {
if domain == actualDomain {
valid = true
break
}
}
// Add [owner].[pages-domain] as valid domain.
domains = append(domains, o.TargetOwner+mainDomainSuffix)
if domains[len(domains)-1] == actualDomain {
valid = true
}
// If the target repository isn't called pages, add `/[repository]` to the
// previous valid domain.
if o.TargetRepo != "" && o.TargetRepo != "pages" {
domains[len(domains)-1] += "/" + o.TargetRepo
}
// Add result to cache.
_ = canonicalDomainCache.Set(o.TargetOwner+"/"+o.TargetRepo+"/"+o.TargetBranch, domains, canonicalDomainCacheTimeout)
// Return the first domain from the list and return if any of the domains
// matched the requested domain.
return domains[0], valid
}
// canonicalDomainList returns a list of normalized canonical domains as reported by the repository being served.
func (o *Options) canonicalDomainList(giteaClient *gitea.Client, mainDomainSuffix string, canonicalDomainConfigs []string) []string {
domainConfigMerge := ""
for _, canonicalDomainConfig := range canonicalDomainConfigs {
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)
continue
}
// Ensures files that don't end with a `\n` don't cause domains to be concatenated when combining files.
domainConfigMerge = domainConfigMerge + "\n" + string(body)
}
domains := normalizeDomainEntries(domainConfigMerge)
// Add [owner].[pages-domain] as valid domain.
domains = append(domains, o.pageMainDomain(mainDomainSuffix))
return domains
}
// pageMainDomain returns the [owner].[pages-domain] domain.
func (o *Options) pageMainDomain(mainDomainSuffix string) string {
pageMainDomain := o.TargetOwner + mainDomainSuffix
// If the target repository isn't called pages, add `/[repository]` to the
// previous valid domain.
if o.TargetRepo != "" && o.TargetRepo != "pages" {
pageMainDomain += "/" + o.TargetRepo
}
return pageMainDomain
}
// normalizeDomainEntries returns a list of domains, ill formatted domains are skipped.
// domainEntries is a new-line separated list of domains.
func normalizeDomainEntries(domainEntries string) []string {
domains := []string{}
for _, domain := range strings.Split(domainEntries, "\n") {
domain = strings.ToLower(domain)
domain = strings.TrimSpace(domain)
domain = strings.TrimPrefix(domain, "http://")
domain = strings.TrimPrefix(domain, "https://")
// Skip blank lines.
// Skip commented lines.
// Skip poorly formatted lines.
// Skip domains without '.'.
if domain == "" || strings.HasPrefix(domain, "#") || strings.ContainsAny(domain, "\t /") || !strings.ContainsRune(domain, '.') {
continue
}
domains = append(domains, domain)
}
return domains
}

View File

@ -0,0 +1,75 @@
package upstream
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestPageMainDomainGeneratesTheExpectedDomain(t *testing.T) {
defaultOptions := Options{
TargetOwner: "",
TargetRepo: "",
TargetBranch: "",
TargetPath: "",
Host: "",
TryIndexPages: false,
BranchTimestamp: time.Time{},
appendTrailingSlash: false,
redirectIfExists: "",
ServeRaw: false,
}
for _, tc := range []struct {
targetOwner string
targetRepo string
domainSuffix string
expectedDomain string
}{
{"foo", "", ".localhost.mock.directory", "foo.localhost.mock.directory"},
{"foo", "pages", ".localhost.mock.directory", "foo.localhost.mock.directory"},
{"foo", "bar", ".localhost.mock.directory", "foo.localhost.mock.directory/bar"},
} {
options := defaultOptions
options.TargetOwner = tc.targetOwner
options.TargetRepo = tc.targetRepo
actualDomain := options.pageMainDomain(tc.domainSuffix)
assert.Equal(t, tc.expectedDomain, actualDomain)
}
}
func TestNormalizeDomainEntries(t *testing.T) {
for _, tc := range []struct {
domain string
}{
{"abc.com"},
{"ABC.com"},
{" ABC.com"},
{"ABC.com "},
{" ABC.com "},
{"http://ABC.com"},
{"https://ABC.com"},
} {
actualDomains := normalizeDomainEntries(tc.domain)
expectedDomains := []string{"abc.com"}
assert.Equal(t, expectedDomains, actualDomains)
}
for _, tc := range []struct {
domains string
expectedDomains []string
}{
{"", []string{}},
{"ABC.com", []string{"abc.com"}},
{"ABC.com\nhttps://example.com", []string{"abc.com", "example.com"}},
{"\n\nABC.com\n\nhttps://example.com\n", []string{"abc.com", "example.com"}},
} {
actualDomains := normalizeDomainEntries(tc.domains)
assert.Equal(t, tc.expectedDomains, actualDomains)
}
}

View File

@ -24,5 +24,5 @@ func (o *Options) setHeader(ctx *context.Context, header http.Header) {
} else {
ctx.RespWriter.Header().Set(gitea.ContentTypeHeader, mime)
}
ctx.RespWriter.Header().Set(headerLastModified, o.BranchTimestamp.In(time.UTC).Format(time.RFC1123))
ctx.RespWriter.Header().Set(headerLastModified, o.BranchTimestamp.In(time.UTC).Format(http.TimeFormat))
}