import { assert, assertEquals, assertExists } from "jsr:@std/assert"; import { stub } from "jsr:@std/testing/mock"; import { app } from "../main.ts"; import { sqlWrapper } from "../db.ts"; import { valkey } from "../valkey.ts"; import { rateLimitWrapper } from "../ratelimit.ts"; rateLimitWrapper.checkRateLimit = () => Promise.resolve(true); Deno.test("Multi-Claim Event Passes & Join Endpoints", async (t) => { await t.step("POST /api/events creates an event pass", async () => { const valkeyStub = stub(valkey, "get", (key: any) => { if (String(key) === "admin-session") { return Promise.resolve( JSON.stringify({ uuid: "admin-uuid", username: "tylerg" }), ); } return Promise.resolve(null); }); const originalSql = sqlWrapper.sql; sqlWrapper.sql = ((strings: any, ..._values: any[]) => { const query = Array.isArray(strings) ? strings.join("?") : String(strings); if (query.includes("INSERT INTO event_passes")) { return Promise.resolve([{ id: "event-uuid-1", slug: "deno-lab", pin_code: "749-123", name: "Deno Workshop", max_seats: 50, seats_claimed: 0, lifespan_hours: 3, }]); } return Promise.resolve([]); }) as any; try { const res = await app.request("/api/events", { method: "POST", headers: { Authorization: "Bearer admin-session", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Deno Workshop", slug: "deno-lab", pinCode: "749-123", maxSeats: 50, lifespanHours: 3, }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assertEquals(json.event.slug, "deno-lab"); assertEquals(json.event.pin_code, "749-123"); } finally { sqlWrapper.sql = originalSql; valkeyStub.restore(); } }); await t.step( "POST /api/join normalizes PIN without hyphens and mints guest session", async () => { const originalSql = sqlWrapper.sql; let updateCalled = false; let selectCalled = false; sqlWrapper.sql = ((strings: any, ...values: any[]) => { const query = Array.isArray(strings) ? strings.join("?") : String(strings); if (query.includes("SELECT * FROM event_passes")) { selectCalled = true; // Verify pinNormalized parameter value assert(values.includes("749123")); return Promise.resolve([{ id: "event-uuid-1", slug: "deno-lab", pin_code: "749-123", name: "Deno Workshop", max_seats: 50, seats_claimed: 0, lifespan_hours: 3, app_id: null, }]); } if (query.includes("UPDATE event_passes")) { updateCalled = true; return Promise.resolve([{ id: "event-uuid-1", slug: "deno-lab", pin_code: "749-123", name: "Deno Workshop", max_seats: 50, seats_claimed: 1, lifespan_hours: 3, app_id: null, }]); } return Promise.resolve([]); }) as any; const valkeySetexStub = stub( valkey, "setex", () => Promise.resolve("OK" as any), ); const { auditWrapper } = await import("../audit.ts"); let auditCalled = false; let auditPayload: any = null; const auditStub = stub( auditWrapper, "auditLog", (_userId, action, resource, metadata, _ip) => { if (action === "event_seat_claimed") { auditCalled = true; auditPayload = { resource, metadata }; } }, ); try { const res = await app.request("/api/join", { method: "POST", headers: { "Content-Type": "application/json", "X-Forwarded-For": "192.168.1.1", }, body: JSON.stringify({ code: "749-123" }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assert(json.token.startsWith("ay_sess_")); assertEquals(json.username, "guest_deno-lab_1"); const cookies = res.headers.get("set-cookie"); assertExists(cookies); assert(cookies.includes(`session_id=${json.token};`)); assert(selectCalled); assert(updateCalled); assert(auditCalled); assertEquals(auditPayload.resource, "event-uuid-1"); assertEquals(auditPayload.metadata.slug, "deno-lab"); assertEquals(auditPayload.metadata.method, "web"); } finally { sqlWrapper.sql = originalSql; valkeySetexStub.restore(); auditStub.restore(); } }, ); await t.step( "POST /api/join idempotent re-entry returns existing session without burning a seat", async () => { const valkeyGetStub = stub(valkey, "get", (key: any) => { if (String(key) === "existing-guest-session") { return Promise.resolve( JSON.stringify({ uuid: "guest-uuid", username: "guest_deno-lab_1", sessionId: "existing-guest-session", }), ); } return Promise.resolve(null); }); const originalSql = sqlWrapper.sql; let updateCalled = false; sqlWrapper.sql = ((strings: any, ..._values: any[]) => { const query = Array.isArray(strings) ? strings.join("?") : String(strings); if (query.includes("SELECT * FROM event_passes")) { return Promise.resolve([{ id: "event-uuid-1", slug: "deno-lab", pin_code: "749-123", name: "Deno Workshop", max_seats: 50, seats_claimed: 1, lifespan_hours: 3, app_id: null, }]); } if (query.includes("UPDATE event_passes")) { updateCalled = true; return Promise.resolve([]); } return Promise.resolve([]); }) as any; const valkeyExpireStub = stub( valkey, "expire", () => Promise.resolve(1 as any), ); try { const res = await app.request("/api/join", { method: "POST", headers: { "Content-Type": "application/json", "X-Forwarded-For": "192.168.1.1", "Cookie": "session_id=existing-guest-session", }, body: JSON.stringify({ code: "deno-lab" }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assert(json.reused === true); assertEquals(json.sessionId, "existing-guest-session"); assert(!updateCalled); // verify seat was not burned } finally { sqlWrapper.sql = originalSql; valkeyGetStub.restore(); valkeyExpireStub.restore(); } }, ); await t.step( "POST /api/join enforces 5 failed attempts rate limit per IP", async () => { let isRateLimitedCalled = false; let checkRateLimitCalled = false; rateLimitWrapper.isRateLimited = ( key: string, limit: number, _window: number, ) => { if (key === "ratelimit:join:fail:192.168.1.99" && limit === 5) { isRateLimitedCalled = true; return Promise.resolve(true); } return Promise.resolve(false); }; rateLimitWrapper.checkRateLimit = () => { checkRateLimitCalled = true; return Promise.resolve(false); }; try { const res = await app.request("/api/join", { method: "POST", headers: { "Content-Type": "application/json", "X-Forwarded-For": "192.168.1.99", }, body: JSON.stringify({ code: "invalid-code" }), }); assertEquals(res.status, 429); const json = await res.json(); assertEquals(json.error, "Too Many Requests"); assert(isRateLimitedCalled); assert(!checkRateLimitCalled); // didn't reach failure branch } finally { rateLimitWrapper.isRateLimited = () => Promise.resolve(false); rateLimitWrapper.checkRateLimit = () => Promise.resolve(true); } }, ); await t.step( "POST /api/join normalizes slug case-insensitively while preserving hyphens", async () => { const originalSql = sqlWrapper.sql; sqlWrapper.sql = ((strings: any, ...values: any[]) => { const query = Array.isArray(strings) ? strings.join("?") : String(strings); if (query.includes("SELECT * FROM event_passes")) { assert(values.includes("deno-lab-workshop")); return Promise.resolve([{ id: "event-uuid-2", slug: "deno-lab-workshop", pin_code: "111-222", name: "Deno Workshop 2", max_seats: 50, seats_claimed: 0, lifespan_hours: 3, app_id: null, }]); } if (query.includes("UPDATE event_passes")) { return Promise.resolve([{ id: "event-uuid-2", slug: "deno-lab-workshop", pin_code: "111-222", name: "Deno Workshop 2", max_seats: 50, seats_claimed: 1, lifespan_hours: 3, app_id: null, }]); } return Promise.resolve([]); }) as any; const valkeySetexStub = stub( valkey, "setex", () => Promise.resolve("OK" as any), ); try { const res = await app.request("/api/join", { method: "POST", headers: { "Content-Type": "application/json", "X-Forwarded-For": "192.168.1.1", }, body: JSON.stringify({ code: " Deno-Lab-Workshop " }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assertEquals(json.username, "guest_deno-lab-workshop_1"); } finally { sqlWrapper.sql = originalSql; valkeySetexStub.restore(); } }, ); await t.step( "GET /join/:slug?format=env returns CLI export string", async () => { const originalSql = sqlWrapper.sql; sqlWrapper.sql = ((strings: any, ..._values: any[]) => { const query = Array.isArray(strings) ? strings.join("?") : String(strings); if (query.includes("UPDATE event_passes")) { return Promise.resolve([{ id: "event-uuid-1", slug: "deno-lab", pin_code: "749-123", name: "Deno Workshop", max_seats: 50, seats_claimed: 2, lifespan_hours: 3, app_id: null, }]); } return Promise.resolve([]); }) as any; const valkeySetexStub = stub( valkey, "setex", () => Promise.resolve("OK" as any), ); const { auditWrapper } = await import("../audit.ts"); let auditCalled = false; let auditPayload: any = null; const auditStub = stub( auditWrapper, "auditLog", (_userId, action, resource, metadata, _ip) => { if (action === "event_seat_claimed") { auditCalled = true; auditPayload = { resource, metadata }; } }, ); try { const res = await app.request("/join/deno-lab?format=env", { method: "GET", headers: { "X-Forwarded-For": "192.168.1.2" }, }); assertEquals(res.status, 200); const text = await res.text(); assert(text.includes('export AUTH_YES_TOKEN="ay_sess_')); assert(text.includes('export AUTH_YES_USER="guest_deno-lab_2"')); assert(auditCalled); assertEquals(auditPayload.resource, "event-uuid-1"); assertEquals(auditPayload.metadata.slug, "deno-lab"); assertEquals(auditPayload.metadata.method, "cli"); } finally { sqlWrapper.sql = originalSql; valkeySetexStub.restore(); auditStub.restore(); } }, ); await t.step( "POST /api/events/:id/end master kill switch revokes sessions", async () => { const valkeyGetStub = stub(valkey, "get", (key: any) => { if (String(key) === "admin-session") { return Promise.resolve( JSON.stringify({ uuid: "admin-uuid", username: "tylerg" }), ); } return Promise.resolve(null); }); const originalSql = sqlWrapper.sql; let updateEventCalled = false; let deleteSessionsCalled = false; sqlWrapper.sql = ((strings: any, ..._values: any[]) => { const query = Array.isArray(strings) ? strings.join("?") : String(strings); if ( query.includes("UPDATE event_passes") && query.includes("is_active = FALSE") ) { updateEventCalled = true; return Promise.resolve([{ slug: "deno-lab" }]); } if (query.includes("DELETE FROM sessions")) { deleteSessionsCalled = true; return Promise.resolve([{ id: "sess-1" }, { id: "sess-2" }]); } return Promise.resolve([]); }) as any; const valkeyDelStub = stub( valkey, "del", () => Promise.resolve(2 as any), ); try { const res = await app.request("/api/events/evt-123/end", { method: "POST", headers: { Authorization: "Bearer admin-session", }, }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assertEquals(json.revokedCount, 2); assert(updateEventCalled); assert(deleteSessionsCalled); } finally { sqlWrapper.sql = originalSql; valkeyGetStub.restore(); valkeyDelStub.restore(); } }, ); await t.step( "POST /api/events/:id/extend adds time to event and sessions", async () => { const valkeyGetStub = stub(valkey, "get", (key: any) => { if (String(key) === "admin-session") { return Promise.resolve( JSON.stringify({ uuid: "admin-uuid", username: "tylerg" }), ); } return Promise.resolve(null); }); const futureDate = new Date(Date.now() + 7200000).toISOString(); const originalSql = sqlWrapper.sql; let updateEventCalled = false; let updateSessionsCalled = false; sqlWrapper.sql = ((strings: any, ..._values: any[]) => { const query = Array.isArray(strings) ? strings.join("?") : String(strings); if ( query.includes("UPDATE event_passes") && query.includes("expires_at = expires_at + interval") ) { updateEventCalled = true; return Promise.resolve([{ slug: "deno-lab", expires_at: futureDate, }]); } if ( query.includes("UPDATE sessions") && query.includes("expires_at = expires_at + interval") ) { updateSessionsCalled = true; return Promise.resolve([{ id: "sess-1" }, { id: "sess-2" }]); } return Promise.resolve([]); }) as any; let expireCallCount = 0; const valkeyExpireStub = stub(valkey, "expire", () => { expireCallCount++; return Promise.resolve(1 as any); }); try { const res = await app.request("/api/events/evt-123/extend", { method: "POST", headers: { Authorization: "Bearer admin-session", "Content-Type": "application/json", }, body: JSON.stringify({ extendHours: 2 }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assertEquals(json.expiresAt, futureDate); assert(updateEventCalled); assert(updateSessionsCalled); assertEquals(expireCallCount, 2); } finally { sqlWrapper.sql = originalSql; valkeyGetStub.restore(); valkeyExpireStub.restore(); } }, ); });