Fix security and correctness issues found in full-codebase audit
- Restrict meetingPassword field so it isn't leaked via the public REST/GraphQL API - Fix booking slot computation to use Europe/Berlin time instead of the server's UTC clock - Reset email verification when a customer changes their email address - Fix ICS calendar injection via unescaped carriage returns in event descriptions - Bind WebRTC meeting kicks to a persistent client id so they survive a rejoin - Move the meeting signaling token out of the WebSocket query string into the first message - Prevent duplicate signaling connections from leaking when the same participant reconnects - Use the rightmost X-Forwarded-For entry for rate limiting (single trusted reverse proxy) - Use constant-time comparison for the cron endpoint's bearer token - Remove SVG from allowed Media upload types (stored-XSS risk, unused anyway) - Add baseline security headers and a CSP to next.config.ts - Fix CI/CD script injection via unsanitized git ref names in release.yml
This commit is contained in:
@@ -5,6 +5,16 @@ export type MeetingRole = "host" | "participant";
|
||||
export type MeetingTokenPayload = {
|
||||
eventSlug: string;
|
||||
participantId: string;
|
||||
// Self-declared, persisted client-side (localStorage, not sessionStorage)
|
||||
// identity for participants — participantId is fresh per /join call, so
|
||||
// without this a kick could always be undone by simply rejoining. Only
|
||||
// used to make a kick stick across a rejoin (see rooms.ts kickedClientIds);
|
||||
// never used to key live room membership, so a client choosing an
|
||||
// arbitrary/colliding value can only affect their own future kick status,
|
||||
// never another participant's connection. Still bypassable by clearing
|
||||
// localStorage or joining from a different browser — there's no real
|
||||
// identity to anchor to for an unauthenticated participant.
|
||||
clientId?: string;
|
||||
name: string;
|
||||
role: MeetingRole;
|
||||
exp: number; // unix ms
|
||||
@@ -29,12 +39,18 @@ export function createMeetingToken(args: {
|
||||
eventSlug: string;
|
||||
name: string;
|
||||
role: MeetingRole;
|
||||
clientId?: string;
|
||||
ttlMs?: number;
|
||||
}): { token: string; participantId: string } {
|
||||
const participantId = randomUUID();
|
||||
const clientId =
|
||||
typeof args.clientId === "string" && args.clientId.length > 0 && args.clientId.length <= 100
|
||||
? args.clientId
|
||||
: undefined;
|
||||
const payload: MeetingTokenPayload = {
|
||||
eventSlug: args.eventSlug,
|
||||
participantId,
|
||||
clientId,
|
||||
name: args.name,
|
||||
role: args.role,
|
||||
exp: Date.now() + (args.ttlMs ?? 6 * 60 * 60 * 1000), // 6h default
|
||||
|
||||
Reference in New Issue
Block a user