43 lines
2.2 KiB
TypeScript
43 lines
2.2 KiB
TypeScript
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 };
|
|
}
|