import { createHmac } from "node:crypto"; import type { Payload } from "payload"; import type { Event, MeetingSetting } from "@/payload-types"; import { canJoinMeeting, combineDateAndTime, getMeetingStatus } from "./status"; import type { MeetingRole } from "./token"; export function meetingAccessVersion(event: Event): string { const secret = process.env.MEETING_SESSION_SECRET; if (!secret) throw new Error("MEETING_SESSION_SECRET is not set"); return createHmac("sha256", secret).update(JSON.stringify([ event.id, event.slug, event.meetingPassword, event.date, event.startTime, event.endTime, event.isOnline, event._status, event.isPrivateBooking, ])).digest("hex"); } export function meetingWindow(event: Event, settings: MeetingSetting, role: MeetingRole, now = new Date()) { const start = combineDateAndTime(event.date, event.startTime); const end = event.endTime ? combineDateAndTime(event.date, event.endTime) : new Date(start.getTime() + 3600000); const closeAt = end.getTime() + settings.meetingCloseAfterMinutes * 60000; const status = getMeetingStatus({ start, end, joinWindowMinutes: role === "host" ? settings.hostJoinWindowMinutes : settings.participantJoinWindowMinutes, closeAfterMinutes: settings.meetingCloseAfterMinutes, now }); return { allowed: Number.isFinite(closeAt) && end > start && canJoinMeeting(status), closeAt, status }; } /** Shared by every issuer: existing credentials are not a substitute for current access. */ export async function authorizeMeeting(payload: Payload, event: Event, role: MeetingRole) { if (!event.isOnline || (!event.isPrivateBooking && event._status !== "published" && role !== "host")) return null; if (event.isPrivateBooking) { const { docs } = await payload.find({ collection: "booking-requests", depth: 0, limit: 1, where: { and: [ { linkedEvent: { equals: event.id } }, { status: { equals: "confirmed" } }, { appointmentType: { equals: "online" } }, ] }, }); if (!docs[0]) return null; } const settings = await payload.findGlobal({ slug: "meeting-settings" }); const window = meetingWindow(event, settings, role); if (!window.allowed) return null; return { accessVersion: meetingAccessVersion(event), expiresAt: window.closeAt }; }