/events leaks every user's drawings to every signed-in viewer
src/actions.ts emits drawing.added with the whole drawing row and src/draw.ts emits drawing.changed with the whole row. src/live.ts sends every event to every /events listener and replays the last 100 to anyone who connects (since=0). So any signed-in person who can open glyph reads every other person's prompts and SVGs.
Fix it so a listener only learns about its own drawings:
Emit ids and status only (e.g. { id, status }), never prompts or SVG. The page re-reads the drawing through the normal authorised route, which already checks the owner.
Or scope delivery per user: each event carries its owner, and /events only sends a listener events for the signed-in viewer (the replay buffer filtered the same way).
Either is fine; ids-only is simpler.
Acceptance:
A test with two users: B listening on /events (live and with replay since=0) never receives A's prompt or SVG text.
The test fails if the old whole-row emit is put back (prove it).
The owner's own page still updates live when their drawing finishes.
/events leaks every user's drawings to every signed-in viewer
src/actions.tsemitsdrawing.addedwith the whole drawing row andsrc/draw.tsemitsdrawing.changedwith the whole row.src/live.tssends every event to every/eventslistener and replays the last 100 to anyone who connects (since=0). So any signed-in person who can open glyph reads every other person's prompts and SVGs.Fix it so a listener only learns about its own drawings:
{ id, status }), never prompts or SVG. The page re-reads the drawing through the normal authorised route, which already checks the owner./eventsonly sends a listener events for the signed-in viewer (the replay buffer filtered the same way).Either is fine; ids-only is simpler.
Acceptance:
/events(live and with replaysince=0) never receives A's prompt or SVG text.bun testgreen.