6.8 KiB
6.8 KiB
TASK METADATA
- Target Files:
server/db.tsserver/routes/events.tsserver/routes/sessions.tsserver/routes/forward_auth.tsui/components/events/VouchingModal.tsxui/components/sessions/EventGuestsDrawer.tsxui/components/sessions/SessionsScript.tsxserver/tests/vouching.test.ts
- Core Objective: Implement a decentralized Peer-to-Peer (P2P) Vouching Web of Trust for high-security events, where joining guests enter a quarantined read-only state until verified by a peer or host via QR/Emoji pairing, with recursive cascade revocation.
- Dependencies:
- Existing
event_passesschema andusers.event_pass_idrelational linking. - Valkey L1/L2 cache for real-time session state propagation.
- Existing
- Additional Important Notes:
- Must remain opt-in per event via
require_vouching BOOLEAN DEFAULT FALSE. - UI must remain 100% React-free Hono SSR JSX with vanilla JavaScript DOM state manipulation.
- Must remain opt-in per event via
2. Architectural Considerations & Risks
Risks
- Vouching Graph Cycles & Endless Loops: If attendee A vouches for B, B
vouches for C, and C attempts to vouch for A, cyclical graphs could corrupt
hierarchy metrics or create infinite loops during cascade revocation.
- Mitigation: Enforce an acyclic tree constraint. A user can only be
vouched for once (setting an immutable
vouched_by UUIDpointing to their verified parent). Vouchers must already be in anactive(non-quarantined) state.
- Mitigation: Enforce an acyclic tree constraint. A user can only be
vouched for once (setting an immutable
- Cascade Revocation Overhead & Blast Radius: If an organizer revokes a
rogue voucher at the root of a large subtree, revoking dozens of downstream
guest sessions could block the event loop or leave orphaned cache records.
- Mitigation: Use a PostgreSQL Recursive Common Table Expression (CTE) to
fetch all downstream descendant session IDs in a single atomic query
(
WITH RECURSIVE subordinates AS (...)), followed by bulk atomic cache eviction in Valkey using pipelinedUNLINK.
- Mitigation: Use a PostgreSQL Recursive Common Table Expression (CTE) to
fetch all downstream descendant session IDs in a single atomic query
(
- UX Friction in Standard Workshops: Mandating vouching for open public
demos or casual workshops adds unnecessary friction.
- Mitigation: Make P2P vouching an opt-in toggle (
require_vouching) in the[ Delegate Session ]creation drawer.
- Mitigation: Make P2P vouching an opt-in toggle (
Alternatives
- Centralized Host-Only Approval Queue: Instead of P2P vouching, all attendees could wait in a lobby for the host to click "Approve". While simpler, this creates an operational bottleneck for workshops with 50+ attendees. P2P vouching allows any already-admitted participant to onboard their neighbor, enabling rapid, distributed verification.
- WebRTC / Bluetooth Proximity: We considered WebRTC or WebBluetooth for physical co-location verification. However, browser support and permission prompts make this fragile. A 3-emoji visual sequence + 1-click QR code camera scan provides instant, high-friction-to-bots physical co-presence verification with zero native permission dependencies.
3. Proposed Implementation
Phase 1: Database Schema & Entity Relationships (server/db.ts)
- Add vouching metadata columns to
event_passes:require_vouching BOOLEAN DEFAULT FALSEvouch_depth_limit INT DEFAULT 2(0 = host-only, 1 = direct guests only, 2+ = transitive)
- Add verification tracking to
users:is_quarantined BOOLEAN DEFAULT FALSEvouched_by UUID REFERENCES users(id) ON DELETE SET NULLvouched_at TIMESTAMP WITH TIME ZONE
- Add ephemeral vouching challenge table
vouch_challenges:id UUID PRIMARY KEY DEFAULT gen_random_uuid()target_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADEevent_id UUID NOT NULL REFERENCES event_passes(id) ON DELETE CASCADEemoji_sequence TEXT NOT NULL(e.g.🚀-🦊-⚡)pairing_code TEXT UNIQUE NOT NULL(6-char alphanumeric code or QR token)created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()expires_at TIMESTAMP WITH TIME ZONE NOT NULL
Phase 2: Ingress Quarantine & Verification API (server/routes/events.ts)
- Quarantined Ingress:
- In
POST /api/joinandGET /join/:slug, ifevent.require_vouching = TRUE, setusers.is_quarantined = TRUEand tag the session with custom scope['guest:quarantined']. - Issue a
vouch_challengereturning the 3-emoji sequence, QR payload, and pairing code.
- In
- ForwardAuth Guard:
- In
server/routes/forward_auth.ts, check if the session containsguest:quarantined. If quarantined, block access to internal apps (return 403 or redirect to/vouch/pending).
- In
- Vouching Endpoints:
POST /api/events/:id/vouch/verify:- Authenticated voucher submits the 3-emoji sequence or scans the QR pairing token.
- Verify the voucher is an active (non-quarantined) participant of the same event.
- Check
vouch_depth_limit. - Atomically update
users.is_quarantined = FALSE, setusers.vouched_by = voucher.id, delete the challenge, and broadcast session upgrade to Valkey.
Phase 3: Recursive Cascade Revocation (server/routes/sessions.ts)
- Refactor
DELETE /api/sessions/:id:- If the target session belongs to a guest user who has vouched for others,
execute a recursive CTE query:
WITH RECURSIVE tree AS ( SELECT id, event_pass_id FROM users WHERE id = ${targetUserId} UNION ALL SELECT u.id, u.event_pass_id FROM users u INNER JOIN tree t ON u.vouched_by = t.id ) SELECT s.id as session_id, t.id as user_id FROM sessions s JOIN tree t ON s.user_id = t.id; - Delete all discovered sessions in PostgreSQL and evict all matching keys from Valkey.
- If the target session belongs to a guest user who has vouched for others,
execute a recursive CTE query:
Phase 4: UI & Mobile Pairing Interface
- Attendee Waiting Screen (
ui/components/events/QuarantineLobby.tsx):- Render large high-contrast 3-emoji sequence and QR code: "Show this to the workshop host or an admitted attendee to unlock full access".
- Poll or listen for activation event via SSE/fetch.
- Voucher Action Modal (
ui/components/events/VouchingModal.tsx):- Admitted attendees see a
[ 🤝 Vouch for Peer ]button in their top bar or Guest Drawer. - Opens simple camera QR scanner or 3-emoji selector grid to confirm the peer in front of them.
- Admitted attendees see a
- Guest Drawer Web of Trust Tree:
- In
EventGuestsDrawer.tsx, show vouching tree indentation / badge (Vouched by Tyler G).
- In
Phase 5: Quality Gates & Integration Testing
- Authored unit and integration tests in
server/tests/vouching.test.ts:- Verify unvouched attendees cannot access ForwardAuth-protected endpoints.
- Verify valid emoji/QR verification lifts quarantine immediately.
- Verify cascading revocation cleans up all child and grandchild sessions recursively.
- Run
deno fmt,deno task lint,deno task check, anddeno test -A --no-check.