The template's seat endpoints answer only this site's own pages, in JSON

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
This commit is contained in:
Eric WagonerandClaude Fable 5.1 committed 2026-11-10 21:24:21 -05:00
1 parent e3f8a03215
commit 11a206e97d
1 file changed
+16
+16
View File
@@ -138,6 +138,21 @@ function addrOf(req: IncomingMessage): string {
return createHmac('sha256', salt).update(clientOf(req)).digest('hex').slice(0, 16); return createHmac('sha256', salt).update(clientOf(req)).digest('hex').slice(0, 16);
} }
/**
* Whether the request was sent by this site's own pages. A page elsewhere could have a visitor's browser post here
* on its behalf; the browser names that page's origin, and the request is refused. The cookie is not sent across
* sites in any case, so what such a page could do is re-key a visitor's own seats under a name, to no end but nuisance.
*/
function fromThisSite(req: IncomingMessage): boolean {
const origin = req.headers.origin;
if (!origin) return true;
try {
return new URL(origin).host === req.headers.host;
} catch {
return false;
}
}
/** The seats the browser's cookie banks, as room and token; a cookie this server never wrote reads as none. */ /** The seats the browser's cookie banks, as room and token; a cookie this server never wrote reads as none. */
function bankedSeats(req: IncomingMessage): { roomId: string; token: string }[] { function bankedSeats(req: IncomingMessage): { roomId: string; token: string }[] {
const header = req.headers.cookie ?? ''; const header = req.headers.cookie ?? '';
@@ -324,6 +339,7 @@ async function handle(req: IncomingMessage, res: ServerResponse): Promise<void>
return send(res, 200, rooms.claim(body.phrase)); return send(res, 200, rooms.claim(body.phrase));
} }
if (parts[0] === 'api' && parts[1] === 'seats' && req.method === 'POST') { if (parts[0] === 'api' && parts[1] === 'seats' && req.method === 'POST') {
if (!fromThisSite(req) || !String(req.headers['content-type'] ?? '').startsWith('application/json')) throw new RoomError('Not from here.', 403);
const body = await readBody(req); const body = await readBody(req);
if (parts.length === 2) { if (parts.length === 2) {
const seats = provenBank(req, body.seats, body.forget); const seats = provenBank(req, body.seats, body.forget);