Refuse API writes that are not application/json (closes #271) #273

Open
clawbot wants to merge 1 commits from issue-271-require-json-content-type into next
pull from: issue-271-require-json-content-type
Collaborator

Fixes #271.

A browser sends a text/plain or form POST to another origin of the same site without a preflight, and attaches the SameSite=Strict cookie. A page there could therefore send messages or log the user out.

  • RequireJSON in internal/middleware runs on the whole /api/v1 router. A POST, PUT or DELETE whose media type is not application/json, or that has no Content-Type, gets 415 with {"error":"content type must be application/json"} before the handler runs. Parameters such as charset are allowed.
  • Because the check runs on the router, a non-JSON POST to an unknown path under /api/v1/ gets 415 before the router would answer 404 or 405.
  • README.md: one convention bullet under "Using the HTTP API", one sentence under "Other paths" on that 415, plus the internal/middleware/ layout line. The curl examples already carried the header.
  • Tests: a table in internal/middleware covers methods and types. One in internal/handlers checks that refused sends store no message and refused logouts leave the client signed in.
  • The test helper doRequestAuth now sets the header on every non-GET request, because the logout tests send no body.

Not in the diff:

  • The web client and neoirc-cli already send Content-Type: application/json on every request, so neither changed. Neither calls POST /api/v1/logout.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/neoirc/issues/271. A browser sends a `text/plain` or form `POST` to another origin of the same site without a preflight, and attaches the `SameSite=Strict` cookie. A page there could therefore send messages or log the user out. - `RequireJSON` in `internal/middleware` runs on the whole `/api/v1` router. A `POST`, `PUT` or `DELETE` whose media type is not `application/json`, or that has no `Content-Type`, gets `415` with `{"error":"content type must be application/json"}` before the handler runs. Parameters such as `charset` are allowed. - Because the check runs on the router, a non-JSON `POST` to an unknown path under `/api/v1/` gets `415` before the router would answer `404` or `405`. - `README.md`: one convention bullet under "Using the HTTP API", one sentence under "Other paths" on that `415`, plus the `internal/middleware/` layout line. The `curl` examples already carried the header. - Tests: a table in `internal/middleware` covers methods and types. One in `internal/handlers` checks that refused sends store no message and refused logouts leave the client signed in. - The test helper `doRequestAuth` now sets the header on every non-`GET` request, because the logout tests send no body. Not in the diff: - The web client and `neoirc-cli` already send `Content-Type: application/json` on every request, so neither changed. Neither calls `POST /api/v1/logout`. Model: opus-5-5
clawbot added the needs-review label 2026-11-11 01:46:30 +01:00
clawbot self-assigned this 2026-11-11 01:46:31 +01:00
Author
Collaborator

FAIL: needs-rework.

  1. README.md lines 522–524, "Other paths": "An unknown path under /api/v1/ gets a plain-text 404. A request whose method the path does not take gets 405 with no body." Both sentences are now false for a POST, PUT or DELETE without Content-Type: application/json. RequireJSON runs on the whole /api/v1 router, so POST /api/v1/nope and POST /api/v1/state without the header get 415 and the JSON error instead. The PR body discloses this, but the README still states the old behaviour. Acceptable: the README is true for every request. For example, add one short sentence after these two saying that a POST, PUT or DELETE without the JSON type gets the 415 first.

  2. PR body: the list headed "Not in the diff:" includes the doRequestAuth change in internal/handlers/api_test.go and the 415-before-404/405 behaviour. The diff contains both. Acceptable: a heading that matches its items, or those two items moved out from under it.

Model: opus-5-5

FAIL: `needs-rework`. 1. `README.md` lines 522–524, "Other paths": "An unknown path under `/api/v1/` gets a plain-text `404`. A request whose method the path does not take gets `405` with no body." Both sentences are now false for a `POST`, `PUT` or `DELETE` without `Content-Type: application/json`. `RequireJSON` runs on the whole `/api/v1` router, so `POST /api/v1/nope` and `POST /api/v1/state` without the header get `415` and the JSON error instead. The PR body discloses this, but the README still states the old behaviour. Acceptable: the README is true for every request. For example, add one short sentence after these two saying that a `POST`, `PUT` or `DELETE` without the JSON type gets the `415` first. 2. PR body: the list headed "Not in the diff:" includes the `doRequestAuth` change in `internal/handlers/api_test.go` and the `415`-before-`404`/`405` behaviour. The diff contains both. Acceptable: a heading that matches its items, or those two items moved out from under it. Model: opus-5-5
Author
Collaborator

For the reworker: fix findings 1 and 2 of #273 (comment) as each says is acceptable; change nothing else.

Model: opus-5-5

For the reworker: fix findings 1 and 2 of https://git.eeqj.de/sneak/neoirc/pulls/273#issuecomment-176741 as each says is acceptable; change nothing else. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-11-11 02:24:37 +01:00
clawbot added 1 commit 2026-11-11 02:33:11 +01:00
A page on another origin of the same site could send a text/plain or
form POST with the user's cookie, since a browser sends such a request
without a preflight. RequireJSON on the /api/v1 router answers 415 to a
POST, PUT or DELETE whose Content-Type is not application/json, or that
has none, before the handler runs.

The web client and neoirc-cli already send the header on every request.

Model: opus-5-5
clawbot force-pushed issue-271-require-json-content-type from 0dd748ddf7 to 2be34bcedf 2026-11-11 02:33:11 +01:00 Compare
Author
Collaborator

Findings of #273 (comment):

  1. README.md "Other paths" has a new sentence after the 405 one: "Under /api/v1/, a POST, PUT or DELETE without Content-Type: application/json gets 415 instead." The PR body's README.md item names it.
  2. The doRequestAuth item and the 415-before-404-or-405 item moved into the PR body's list of changes; "Not in the diff:" keeps only the web client and neoirc-cli item.

Model: opus-5-5

Findings of https://git.eeqj.de/sneak/neoirc/pulls/273#issuecomment-176741: 1. `README.md` "Other paths" has a new sentence after the `405` one: "Under `/api/v1/`, a `POST`, `PUT` or `DELETE` without `Content-Type: application/json` gets `415` instead." The PR body's `README.md` item names it. 2. The `doRequestAuth` item and the `415`-before-`404`-or-`405` item moved into the PR body's list of changes; "Not in the diff:" keeps only the web client and `neoirc-cli` item. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-11-11 02:41:32 +01:00
Some checks are pending
check / check (push) Waiting to run
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-271-require-json-content-type:issue-271-require-json-content-type
git checkout issue-271-require-json-content-type
Sign in to join this conversation.