ameer bb070a688d fix(room): guard against non-dict WS payloads and unhashable answers
The first-pass JSON-decode hardening exposed two latent bugs that the
fuzz scenario hits as soon as the WS handler stays alive past a bad
message:

1) `data.get("type")` is called on whatever `receive_json()` decodes,
   but valid JSON can be a list/string/number, not just a dict. Reject
   non-object payloads with a structured bad_message error before
   dispatch.

2) `submit_answer` did `if answer not in {"A","B","C","D"}` which
   raises TypeError when the client sends an unhashable answer
   (e.g. a dict). Add an isinstance(str) guard so any non-string
   answer falls into the bad_answer branch instead of crashing the
   handler.

31/31 pytest still passes. Together with the prior commit, the WS
handlers now survive the full set of fuzz payloads without dropping
the connection.
2026-05-02 17:34:18 +08:00
2026-05-02 03:02:08 +08:00
2026-05-02 02:54:34 +08:00
2026-05-02 02:52:43 +08:00
2026-05-02 02:54:34 +08:00

Live In-Lecture Quiz Portal

FastAPI, SQLite, WebSocket, and vanilla frontend implementation for a live classroom quiz.

Install

cd /home/ameer/RD/Projects/Apps/quiz
python3 -m venv .venv
. .venv/bin/activate
pip install -e '.[dev]'
cp .env.example .env

Edit .env and set real values for QUIZ_SECRET_KEY and QUIZ_ADMIN_PASSWORD.

Run

. .venv/bin/activate
uvicorn app.main:app --host 127.0.0.1 --port 8001 --reload

Open http://127.0.0.1:8001/admin/, log in, create a quiz pool, then create a session. Use the displayed join URL in another browser or private window for the student view.

Test

. .venv/bin/activate
pytest -q
pytest --cov=app

The load simulation test creates 50 student WebSocket clients and runs a 5-question quiz.

Manual Smoke Test

export QUIZ_DB_PATH=/tmp/quiz-smoke.db QUIZ_SECRET_KEY=smoke-secret QUIZ_ADMIN_PASSWORD=smoke-pass QUIZ_PUBLIC_URL=http://127.0.0.1:8001
. .venv/bin/activate
uvicorn app.main:app --host 127.0.0.1 --port 8001
curl http://127.0.0.1:8001/healthz

Expected health response starts with {"ok":true.

Description
No description provided
Readme 226 KiB
Languages
Python 43.7%
JavaScript 33%
CSS 19.3%
Shell 3.1%
Smarty 0.6%
Other 0.3%