diff options
| author | Xe Iaso <me@xeiaso.net> | 2025-04-02 20:00:07 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-02 20:00:07 -0400 |
| commit | b3848e7a4171642e5813a372675b17df45befa46 (patch) | |
| tree | a7a0efc6263c4af705a2f36556374d66387856ee | |
| parent | f9e2a18cf86f4b33766b483694926670a2134ec8 (diff) | |
| parent | 266d8c0cc25f9d93ea7da87eb199bc87e41c653e (diff) | |
| download | anubis-Xe/imessage-scraper-bypass.tar.xz anubis-Xe/imessage-scraper-bypass.zip | |
Merge branch 'main' into Xe/imessage-scraper-bypassXe/imessage-scraper-bypass
Signed-off-by: Xe Iaso <me@xeiaso.net>
| -rw-r--r-- | .github/dependabot.yml | 28 | ||||
| -rw-r--r-- | .github/workflows/docker-pr.yml | 5 | ||||
| -rw-r--r-- | .github/workflows/docker.yml | 1 | ||||
| -rw-r--r-- | .github/workflows/docs-deploy.yml | 2 | ||||
| -rw-r--r-- | .github/workflows/go.yml | 4 | ||||
| -rw-r--r-- | .github/workflows/zizmor.yml | 35 | ||||
| -rw-r--r-- | Makefile | 25 | ||||
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | VERSION | 2 | ||||
| -rw-r--r-- | cmd/anubis/main.go | 58 | ||||
| -rw-r--r-- | docs/docs/CHANGELOG.md | 18 | ||||
| -rw-r--r-- | docs/docs/admin/installation.mdx | 31 | ||||
| -rw-r--r-- | docs/docs/developer/building-anubis.md | 11 | ||||
| -rw-r--r-- | internal/test/playwright_test.go | 10 | ||||
| -rw-r--r-- | lib/anubis.go | 19 | ||||
| -rw-r--r-- | lib/anubis_test.go | 76 | ||||
| -rw-r--r-- | package-lock.json | 298 | ||||
| -rw-r--r-- | package.json | 3 | ||||
| -rw-r--r-- | web/js/proof-of-work.mjs | 2 |
19 files changed, 329 insertions, 303 deletions
diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..dbe7232 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,28 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + github-actions: + patterns: + - "*" + + - package-ecosystem: gomod + directory: / + schedule: + interval: weekly + groups: + gomod: + patterns: + - "*" + + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + groups: + npm: + patterns: + - "*" diff --git a/.github/workflows/docker-pr.yml b/.github/workflows/docker-pr.yml index b124f75..03539f7 100644 --- a/.github/workflows/docker-pr.yml +++ b/.github/workflows/docker-pr.yml @@ -19,6 +19,7 @@ jobs: with: fetch-tags: true fetch-depth: 0 + persist-credentials: false - name: Set up Homebrew uses: Homebrew/actions/setup-homebrew@master @@ -62,4 +63,6 @@ jobs: - run: | echo "Test this with:" - echo "docker pull ${{ steps.build.outputs.docker_image }}"
\ No newline at end of file + echo "docker pull ${DOCKER_IMAGE}" + env: + DOCKER_IMAGE: ${{ steps.build.outputs.docker_image }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c3a532f..d094453 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,6 +25,7 @@ jobs: with: fetch-tags: true fetch-depth: 0 + persist-credentials: false - name: Set up Homebrew uses: Homebrew/actions/setup-homebrew@master diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index 1636c48..652351f 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -17,6 +17,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 09b543a..0be7b37 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,6 +16,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - name: build essential run: | @@ -57,7 +59,7 @@ jobs: ${{ runner.os }}-golang- - name: Cache playwright binaries - uses: actions/cache@v3 + uses: actions/cache@v4 id: playwright-cache with: path: | diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..c2a03ab --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,35 @@ +name: zizmor + +on: + push: + paths: + - '.github/workflows/*.ya?ml' + pull_request: + paths: + - '.github/workflows/*.ya?ml' + +jobs: + zizmor: + name: zizmor latest via PyPI + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v5 + + - name: Run zizmor 🌈 + run: uvx zizmor --format sarif . > results.sarif + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif + category: zizmor diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..380d9f1 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +NODE_MODULES = node_modules + +.PHONY: build assets deps lint test + +$(NODE_MODULES): + npm run assets + +assets: $(NODE_MODULES) + +deps: assets + npm ci + go mod download + +build: deps + npm run build + @echo "Anubis is now built to ./var/anubis" + +all: build + +lint: + go vet ./... + staticcheck ./... + +test: + npm run test
\ No newline at end of file @@ -29,3 +29,7 @@ For live chat, please join the [Patreon](https://patreon.com/cadey) and ask in t ## Star History [](https://www.star-history.com/#TecharoHQ/anubis&Date) + +## Packaging Status + +[](https://repology.org/project/anubis-anti-crawler/versions) @@ -1 +1 @@ -1.15.0 +1.15.1 diff --git a/cmd/anubis/main.go b/cmd/anubis/main.go index 5f858f3..560a261 100644 --- a/cmd/anubis/main.go +++ b/cmd/anubis/main.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "context" "crypto/ed25519" "crypto/rand" @@ -32,22 +33,23 @@ import ( ) var ( - bind = flag.String("bind", ":8923", "network address to bind HTTP to") - bindNetwork = flag.String("bind-network", "tcp", "network family to bind HTTP to, e.g. unix, tcp") - challengeDifficulty = flag.Int("difficulty", anubis.DefaultDifficulty, "difficulty of the challenge") - cookieDomain = flag.String("cookie-domain", "", "if set, the top-level domain that the Anubis cookie will be valid for") - cookiePartitioned = flag.Bool("cookie-partitioned", false, "if true, sets the partitioned flag on Anubis cookies, enabling CHIPS support") - ed25519PrivateKeyHex = flag.String("ed25519-private-key-hex", "", "private key used to sign JWTs, if not set a random one will be assigned") - metricsBind = flag.String("metrics-bind", ":9090", "network address to bind metrics to") - metricsBindNetwork = flag.String("metrics-bind-network", "tcp", "network family for the metrics server to bind to") - socketMode = flag.String("socket-mode", "0770", "socket mode (permissions) for unix domain sockets.") - robotsTxt = flag.Bool("serve-robots-txt", false, "serve a robots.txt file that disallows all robots") - policyFname = flag.String("policy-fname", "", "full path to anubis policy document (defaults to a sensible built-in policy)") - slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)") - target = flag.String("target", "http://localhost:3923", "target to reverse proxy to") - healthcheck = flag.Bool("healthcheck", false, "run a health check against Anubis") - useRemoteAddress = flag.Bool("use-remote-address", false, "read the client's IP address from the network request, useful for debugging and running Anubis on bare metal") - debugBenchmarkJS = flag.Bool("debug-benchmark-js", false, "respond to every request with a challenge for benchmarking hashrate") + bind = flag.String("bind", ":8923", "network address to bind HTTP to") + bindNetwork = flag.String("bind-network", "tcp", "network family to bind HTTP to, e.g. unix, tcp") + challengeDifficulty = flag.Int("difficulty", anubis.DefaultDifficulty, "difficulty of the challenge") + cookieDomain = flag.String("cookie-domain", "", "if set, the top-level domain that the Anubis cookie will be valid for") + cookiePartitioned = flag.Bool("cookie-partitioned", false, "if true, sets the partitioned flag on Anubis cookies, enabling CHIPS support") + ed25519PrivateKeyHex = flag.String("ed25519-private-key-hex", "", "private key used to sign JWTs, if not set a random one will be assigned") + ed25519PrivateKeyHexFile = flag.String("ed25519-private-key-hex-file", "", "file name containing value for ed25519-private-key-hex") + metricsBind = flag.String("metrics-bind", ":9090", "network address to bind metrics to") + metricsBindNetwork = flag.String("metrics-bind-network", "tcp", "network family for the metrics server to bind to") + socketMode = flag.String("socket-mode", "0770", "socket mode (permissions) for unix domain sockets.") + robotsTxt = flag.Bool("serve-robots-txt", false, "serve a robots.txt file that disallows all robots") + policyFname = flag.String("policy-fname", "", "full path to anubis policy document (defaults to a sensible built-in policy)") + slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)") + target = flag.String("target", "http://localhost:3923", "target to reverse proxy to") + healthcheck = flag.Bool("healthcheck", false, "run a health check against Anubis") + useRemoteAddress = flag.Bool("use-remote-address", false, "read the client's IP address from the network request, useful for debugging and running Anubis on bare metal") + debugBenchmarkJS = flag.Bool("debug-benchmark-js", false, "respond to every request with a challenge for benchmarking hashrate") ) func keyFromHex(value string) (ed25519.PrivateKey, error) { @@ -206,18 +208,30 @@ func main() { } var priv ed25519.PrivateKey - if *ed25519PrivateKeyHex == "" { - _, priv, err = ed25519.GenerateKey(rand.Reader) + if *ed25519PrivateKeyHex != "" && *ed25519PrivateKeyHexFile != "" { + log.Fatal("do not specify both ED25519_PRIVATE_KEY_HEX and ED25519_PRIVATE_KEY_HEX_FILE") + } else if *ed25519PrivateKeyHex != "" { + priv, err = keyFromHex(*ed25519PrivateKeyHex) if err != nil { - log.Fatalf("failed to generate ed25519 key: %v", err) + log.Fatalf("failed to parse and validate ED25519_PRIVATE_KEY_HEX: %v", err) + } + } else if *ed25519PrivateKeyHexFile != "" { + hex, err := os.ReadFile(*ed25519PrivateKeyHexFile) + if err != nil { + log.Fatalf("failed to read ED25519_PRIVATE_KEY_HEX_FILE %s: %v", *ed25519PrivateKeyHexFile, err) } - slog.Warn("generating random key, Anubis will have strange behavior when multiple instances are behind the same load balancer target, for more information: see https://anubis.techaro.lol/docs/admin/installation#key-generation") + priv, err = keyFromHex(string(bytes.TrimSpace(hex))) + if err != nil { + log.Fatalf("failed to parse and validate content of ED25519_PRIVATE_KEY_HEX_FILE: %v", err) + } } else { - priv, err = keyFromHex(*ed25519PrivateKeyHex) + _, priv, err = ed25519.GenerateKey(rand.Reader) if err != nil { - log.Fatalf("failed to parse and validate ED25519_PRIVATE_KEY_HEX: %v", err) + log.Fatalf("failed to generate ed25519 key: %v", err) } + + slog.Warn("generating random key, Anubis will have strange behavior when multiple instances are behind the same load balancer target, for more information: see https://anubis.techaro.lol/docs/admin/installation#key-generation") } s, err := libanubis.New(libanubis.Options{ diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index cf5a134..273d8d9 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -29,6 +29,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a wait with button continue + 30 second auto continue after 30s if you click "Why am I seeing this?" - Fixed a typo in the challenge page title. - Disabled running integration tests on Windows hosts due to it's reliance on posix features (see [#133](https://github.com/TecharoHQ/anubis/pull/133#issuecomment-2764732309)). +- Added support for passing the ed25519 signing key in a file with `-ed25519-private-key-hex-file` or `ED25519_PRIVATE_KEY_HEX_FILE`. +- Fixed minor typos +- Added a Makefile to enable comfortable workflows for downstream packagers. +- Added `zizmor` for GitHub Actions static analysis +- Fixed most `zizmor` findings +- Enabled Dependabot + +## v1.15.1 + +Zenos yae Galvus: Echo 1 + +Fixes a recurrence of [CVE-2025-24369](https://github.com/Xe/x/security/advisories/GHSA-56w8-8ppj-2p4f) +due to an incorrect logic change in a refactor. This allows an attacker to mint a valid +access token by passing any SHA-256 hash instead of one that matches the proof-of-work +test. + +This case has been added as a regression test. It was not when CVE-2025-24369 was released +due to the project not having the maturity required to enable this kind of regression testing. ## v1.15.0 diff --git a/docs/docs/admin/installation.mdx b/docs/docs/admin/installation.mdx index ee17a89..b8bc904 100644 --- a/docs/docs/admin/installation.mdx +++ b/docs/docs/admin/installation.mdx @@ -41,21 +41,22 @@ Anubis has very minimal system requirements. I suspect that 128Mi of ram may be Anubis uses these environment variables for configuration: -| Environment Variable | Default value | Explanation | -| :------------------------ | :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `BIND` | `:8923` | The network address that Anubis listens on. For `unix`, set this to a path: `/run/anubis/instance.sock` | -| `BIND_NETWORK` | `tcp` | The address family that Anubis listens on. Accepts `tcp`, `unix` and anything Go's [`net.Listen`](https://pkg.go.dev/net#Listen) supports. | -| `COOKIE_DOMAIN` | unset | The domain the Anubis challenge pass cookie should be set to. This should be set to the domain you bought from your registrar (EG: `techaro.lol` if your webapp is running on `anubis.techaro.lol`). See [here](https://stackoverflow.com/a/1063760) for more information. | -| `COOKIE_PARTITIONED` | `false` | If set to `true`, enables the [partitioned (CHIPS) flag](https://developers.google.com/privacy-sandbox/cookies/chips), meaning that Anubis inside an iframe has a different set of cookies than the domain hosting the iframe. | -| `DIFFICULTY` | `5` | The difficulty of the challenge, or the number of leading zeroes that must be in successful responses. | -| `ED25519_PRIVATE_KEY_HEX` | | The hex-encoded ed25519 private key used to sign Anubis responses. If this is not set, Anubis will generate one for you. This should be exactly 64 characters long. See below for details. | -| `METRICS_BIND` | `:9090` | The network address that Anubis serves Prometheus metrics on. See `BIND` for more information. | -| `METRICS_BIND_NETWORK` | `tcp` | The address family that the Anubis metrics server listens on. See `BIND_NETWORK` for more information. | -| `SOCKET_MODE` | `0770` | _Only used when at least one of the `*_BIND_NETWORK` variables are set to `unix`._ The socket mode (permissions) for Unix domain sockets. | -| `POLICY_FNAME` | unset | The file containing [bot policy configuration](./policies.md). See the bot policy documentation for more details. If unset, the default bot policy configuration is used. | -| `SERVE_ROBOTS_TXT` | `false` | If set `true`, Anubis will serve a default `robots.txt` file that disallows all known AI scrapers by name and then additionally disallows every scraper. This is useful if facts and circumstances make it difficult to change the underlying service to serve such a `robots.txt` file. | -| `TARGET` | `http://localhost:3923` | The URL of the service that Anubis should forward valid requests to. Supports Unix domain sockets, set this to a URI like so: `unix:///path/to/socket.sock`. | -| `USE_REMOTE_ADDRESS` | unset | If set to `true`, Anubis will take the client's IP from the network socket. For production deployments, it is expected that a reverse proxy is used in front of Anubis, which pass the IP using headers, instead. | +| Environment Variable | Default value | Explanation | +| :----------------------------- | :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `BIND` | `:8923` | The network address that Anubis listens on. For `unix`, set this to a path: `/run/anubis/instance.sock` | +| `BIND_NETWORK` | `tcp` | The address family that Anubis listens on. Accepts `tcp`, `unix` and anything Go's [`net.Listen`](https://pkg.go.dev/net#Listen) supports. | +| `COOKIE_DOMAIN` | unset | The domain the Anubis challenge pass cookie should be set to. This should be set to the domain you bought from your registrar (EG: `techaro.lol` if your webapp is running on `anubis.techaro.lol`). See [here](https://stackoverflow.com/a/1063760) for more information. | +| `COOKIE_PARTITIONED` | `false` | If set to `true`, enables the [partitioned (CHIPS) flag](https://developers.google.com/privacy-sandbox/cookies/chips), meaning that Anubis inside an iframe has a different set of cookies than the domain hosting the iframe. | +| `DIFFICULTY` | `5` | The difficulty of the challenge, or the number of leading zeroes that must be in successful responses. | +| `ED25519_PRIVATE_KEY_HEX` | unset | The hex-encoded ed25519 private key used to sign Anubis responses. If this is not set, Anubis will generate one for you. This should be exactly 64 characters long. See below for details. | +| `ED25519_PRIVATE_KEY_HEX_FILE` | unset | Path to a file containing the hex-encoded ed25519 private key. Only one of this or its sister option may be set. | +| `METRICS_BIND` | `:9090` | The network address that Anubis serves Prometheus metrics on. See `BIND` for more information. | +| `METRICS_BIND_NETWORK` | `tcp` | The address family that the Anubis metrics server listens on. See `BIND_NETWORK` for more information. | +| `SOCKET_MODE` | `0770` | _Only used when at least one of the `*_BIND_NETWORK` variables are set to `unix`._ The socket mode (permissions) for Unix domain sockets. | +| `POLICY_FNAME` | unset | The file containing [bot policy configuration](./policies.md). See the bot policy documentation for more details. If unset, the default bot policy configuration is used. | +| `SERVE_ROBOTS_TXT` | `false` | If set `true`, Anubis will serve a default `robots.txt` file that disallows all known AI scrapers by name and then additionally disallows every scraper. This is useful if facts and circumstances make it difficult to change the underlying service to serve such a `robots.txt` file. | +| `TARGET` | `http://localhost:3923` | The URL of the service that Anubis should forward valid requests to. Supports Unix domain sockets, set this to a URI like so: `unix:///path/to/socket.sock`. | +| `USE_REMOTE_ADDRESS` | unset | If set to `true`, Anubis will take the client's IP from the network socket. For production deployments, it is expected that a reverse proxy is used in front of Anubis, which pass the IP using headers, instead. | ### Key generation diff --git a/docs/docs/developer/building-anubis.md b/docs/docs/developer/building-anubis.md index a55b8e7..69b2404 100644 --- a/docs/docs/developer/building-anubis.md +++ b/docs/docs/developer/building-anubis.md @@ -22,20 +22,23 @@ In order to build a production-ready binary of Anubis, you need the following pa ## Install dependencies ```text -go mod download -npm ci +make deps ``` +This will download Go and NPM dependencies. + ## Building static assets ```text -npm run assets +make assets ``` +This will build all static assets (CSS, JavaScript) for distribution. + ## Building Anubis to the `./var` folder ```text -go build -o ./var/anubis ./cmd/anubis +make build ``` From this point it is up to you to make sure that `./var/anubis` ends up in the right place. You may want to consult the `./run` folder for useful files such as a systemd unit and `anubis.env.default` file. diff --git a/internal/test/playwright_test.go b/internal/test/playwright_test.go index d722427..88368c7 100644 --- a/internal/test/playwright_test.go +++ b/internal/test/playwright_test.go @@ -228,17 +228,17 @@ func TestPlaywrightBrowser(t *testing.T) { t.Skip("skipping hard challenge with deadline") } - var perfomedAction action + var performedAction action var err error for i := 0; i < 5; i++ { - perfomedAction, err = executeTestCase(t, tc, typ, anubisURL) - if perfomedAction == tc.action { + performedAction, err = executeTestCase(t, tc, typ, anubisURL) + if performedAction == tc.action { break } time.Sleep(time.Duration(i+1) * 250 * time.Millisecond) } - if perfomedAction != tc.action { - t.Errorf("unexpected test result, expected %s, got %s", tc.action, perfomedAction) + if performedAction != tc.action { + t.Errorf("unexpected test result, expected %s, got %s", tc.action, performedAction) } if err != nil { t.Fatalf("test error: %v", err) diff --git a/lib/anubis.go b/lib/anubis.go index 1b2ebfc..732d2c3 100644 --- a/lib/anubis.go +++ b/lib/anubis.go @@ -145,14 +145,13 @@ func New(opts Options) (*Server, error) { } type Server struct { - mux *http.ServeMux - next http.Handler - priv ed25519.PrivateKey - pub ed25519.PublicKey - policy *policy.ParsedConfig - opts Options - DNSBLCache *decaymap.Impl[string, dnsbl.DroneBLResponse] - ChallengeDifficulty int + mux *http.ServeMux + next http.Handler + priv ed25519.PrivateKey + pub ed25519.PublicKey + policy *policy.ParsedConfig + opts Options + DNSBLCache *decaymap.Impl[string, dnsbl.DroneBLResponse] } func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -441,9 +440,9 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) { } // compare the leading zeroes - if !strings.HasPrefix(response, strings.Repeat("0", s.ChallengeDifficulty)) { + if !strings.HasPrefix(response, strings.Repeat("0", rule.Challenge.Difficulty)) { s.ClearCookie(w) - lg.Debug("difficulty check failed", "response", response, "difficulty", s.ChallengeDifficulty) + lg.Debug("difficulty check failed", "response", response, "difficulty", rule.Challenge.Difficulty) templ.Handler(web.Base("Oh noes!", web.ErrorPage("invalid response")), templ.WithStatus(http.StatusForbidden)).ServeHTTP(w, r) failedValidations.Inc() return diff --git a/lib/anubis_test.go b/lib/anubis_test.go index 58c8834..79a0532 100644 --- a/lib/anubis_test.go +++ b/lib/anubis_test.go @@ -34,6 +34,79 @@ func spawnAnubis(t *testing.T, opts Options) *Server { return s } +type challenge struct { + Challenge string `json:"challenge"` +} + +func makeChallenge(t *testing.T, ts *httptest.Server) challenge { + t.Helper() + + resp, err := ts.Client().Post(ts.URL+"/.within.website/x/cmd/anubis/api/make-challenge", "", nil) + if err != nil { + t.Fatalf("can't request challenge: %v", err) + } + defer resp.Body.Close() + + var chall challenge + if err := json.NewDecoder(resp.Body).Decode(&chall); err != nil { + t.Fatalf("can't read challenge response body: %v", err) + } + + return chall +} + +// Regression test for CVE-2025-24369 +func TestCVE2025_24369(t *testing.T) { + pol := loadPolicies(t, "") + pol.DefaultDifficulty = 4 + + srv := spawnAnubis(t, Options{ + Next: http.NewServeMux(), + Policy: pol, + + CookieDomain: "local.cetacean.club", + CookiePartitioned: true, + CookieName: t.Name(), + }) + + ts := httptest.NewServer(internal.RemoteXRealIP(true, "tcp", srv)) + defer ts.Close() + + chall := makeChallenge(t, ts) + calcString := fmt.Sprintf("%s%d", chall.Challenge, 0) + calculated := internal.SHA256sum(calcString) + nonce := 0 + elapsedTime := 420 + redir := "/" + + cli := ts.Client() + cli.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + + req, err := http.NewRequest(http.MethodGet, ts.URL+"/.within.website/x/cmd/anubis/api/pass-challenge", nil) + if err != nil { + t.Fatalf("can't make request: %v", err) + } + + q := req.URL.Query() + q.Set("response", calculated) + q.Set("nonce", fmt.Sprint(nonce)) + q.Set("redir", redir) + q.Set("elapsedTime", fmt.Sprint(elapsedTime)) + req.URL.RawQuery = q.Encode() + + resp, err := cli.Do(req) + if err != nil { + t.Fatalf("can't do challenge passing") + } + + if resp.StatusCode == http.StatusFound { + t.Log("Regression on CVE-2025-24369") + t.Errorf("wanted HTTP status %d, got: %d", http.StatusForbidden, resp.StatusCode) + } +} + func TestCookieSettings(t *testing.T) { pol := loadPolicies(t, "") pol.DefaultDifficulty = 0 @@ -72,8 +145,9 @@ func TestCookieSettings(t *testing.T) { nonce := 0 elapsedTime := 420 redir := "/" + calculated := "" calcString := fmt.Sprintf("%s%d", chall.Challenge, nonce) - calculated := internal.SHA256sum(calcString) + calculated = internal.SHA256sum(calcString) req, err := http.NewRequest(http.MethodGet, ts.URL+"/.within.website/x/cmd/anubis/api/pass-challenge", nil) if err != nil { diff --git a/package-lock.json b/package-lock.json index 0e60570..e94f885 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,73 +1,22 @@ { "name": "@xeserv/xess", - "version": "1.0.0", + "version": "1.0.0-see-VERSION-file", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@xeserv/xess", - "version": "1.0.0", + "version": "1.0.0-see-VERSION-file", "license": "ISC", "devDependencies": { "cssnano": "^7.0.6", "cssnano-preset-advanced": "^7.0.6", - "postcss-cli": "^11.0.0", + "postcss-cli": "^11.0.1", "postcss-import": "^16.1.0", "postcss-import-url": "^7.2.0", "postcss-url": "^10.1.3" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev |
