`GET /api/contact/submissions` had no authentication. `require_admin` was imported inside the function body and never used as a dependency, so the import read as protection and was none: anyone who guessed the path could read every sender's name, email address and message. `PUT .../read` was open the same way. Both now depend on `require_admin`, with a test that a learner gets 403 and an administrator gets the list. A row with a null timestamp no longer takes the whole listing down with it — which is the only reason the hole showed up as a 500 rather than as data. Also: the tutor's site switch lives in Redis, which the tests share with the running site, so turning the tutor off in the interface turned a test red. The test now sets the flag it depends on and puts it back. And the tutor button is hidden until the server says it is allowed, rather than shown and then withdrawn — on a site with it switched off that flicker reads as a bug rather than a policy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN |
||
|---|---|---|
| .. | ||
| public | ||
| src | ||
| .dockerignore | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| index.html | ||
| nginx.conf | ||
| package-lock.json | ||
| package.json | ||
| vite.config.js | ||