Commit Graph
6 Commits
Author SHA1 Message Date
clawbot d084f4f912 Pin the body cap's order in every page route group (closes #93)
check / check (push) Waiting to run
Follow-ups from an August review of the body cap, each checked against the current tree. One route test now requires an oversized POST, with no session and no CSRF token, to be refused with 413 before CSRF runs, in every page route group with a POST route and in /settings/, so moving a group's body cap after CSRF fails it. The three test router helpers build the server through New with a lifecycle that is never started, so no field is set by hand. The middleware test comment names runMaxBodySize, and the MaxBodySize doc comment says methods other than POST, PUT and PATCH pass uncapped on purpose. The README item was already settled.

Model: opus-5-5
2026-10-02 17:53:21 +02:00
clawbot 2416528b77 Render admin page errors in the normal layout (closes #382)
check / check (push) Successful in 3m12s
Every 400, 403, 404 and 500 on an admin page now answers with an error page in the normal layout: the status, one fixed line explaining it, and a link back to the webhook list, or to sign-in when nobody is signed in. Unknown paths reach it through the router's not-found handler, a refused form token through the CSRF middleware, and a panic through a recoverer each admin page route group installs first. Status codes are unchanged, and the page always sends Cache-Control: no-store.

If the error page fails to render, the answer is the same status in plain text; if it panics, the answer is a 500. The receiver, the healthcheck and /metrics keep their plain answers.

Model: opus-5-5
2026-10-02 08:15:12 +02:00
clawbot 62576f6fc6 Bind the app port deliberately and document the proxy deployment (closes #268) (closes #226)
check / check (push) Successful in 3m4s
2026-08-24 03:38:44 +02:00
clawbot 33e4fa4faa Report handler panics through the logger and answer 500 (closes #187)
check / check (push) Successful in 2m50s
2026-08-18 08:33:12 +02:00
clawbot 76725cffc4 Read form fields from the POST body only (closes #160)
check / check (push) Successful in 2m53s
r.FormValue falls back to the query string, so
POST /source/{id}/targets?url=<secret> created a working target from a
value carried on the request line — where proxy logs, browser history
and Referer all record it. Every form read is now r.PostFormValue,
including the login password and both password-change fields, which had
the same defect in a more acute form.

The Sentry leg needed more than the query string. sentryhttp attaches
the whole request to the scope, and ApplyToEvent copies the teed body
into Request.Data with no SendDefaultPII guard — so reading every field
from the body only pointed every credential this change protects at the
one field the first revision did not scrub. Body and query are now
redacted, Cookies and Env cleared, and Headers reduced to an allowlist,
because the SDK's own filter removes four names and would otherwise ship
X-Csrf-Token and the shared secrets senders put on the receiver route.

Also adds json:"-" to Target.Config, APIKey.Key and Setting.Value —
TargetView is the masking barrier for the HTML path only, and the first
handler to marshal a model would serialise a bearer token or the session
encryption key.

Independently reviewed three times. The second review found the Data
leak and proved it with a scratch module; the third disproved the
PR's own claim that BeforeSend gets no request, so the README now
records that redacting unconditionally is a deliberate choice rather
than a limitation — which is what makes #179 cheap to fix.
2026-08-18 02:04:09 +02:00
clawbot d51cd0fd29 Enforce the body size limit before CSRF parses the form (closes #90)
check / check (push) Superseded by a newer commit; never tested
CSRF ran before MaxBodySize, so the CSRF middleware parsed the form body
before any cap applied and an oversized request was read in full before
being rejected. MaxBodySize is now the first middleware in all four route
groups that parse forms, ahead of CSRF and RequireAuth.

An oversize request therefore gets 413 without the handler running and
without state changing, including the password-change route.

Note the ordering trade: an unauthenticated client now receives 413 rather
than an auth redirect on /user/{username}/password.
2026-08-11 14:37:38 +02:00