import { Socket } from "socket.io"; import UserController from "../../../controllers/UserController"; type SecureSocket = Socket & { data: { user?: UserController; [key: string]: unknown; }; }; export const attachSocketEventPermissions = ( socket: Socket, eventPermissions: Record, ): boolean => { const user = (socket.data?.user as UserController | undefined) ?? undefined; if (!user) return false; socket.use(async (packet, packetNext) => { const eventName = packet[0]; if (typeof eventName !== "string") return packetNext(); const eventRequiredPermissions = eventPermissions[eventName] ?? []; if (eventRequiredPermissions.length === 0) return packetNext(); const eventChecks = await Promise.all( eventRequiredPermissions.map((permission) => user.hasPermission(permission), ), ); if (eventChecks.includes(false)) { return packetNext(new Error("Forbidden: insufficient permissions")); } return packetNext(); }); return true; }; export const socketAuthMiddleware = (permParams?: { permissions?: string[]; eventPermissions?: Record; }) => { return async (socket: SecureSocket, next: (err?: Error) => void) => { const user = socket.data.user; if (!user) return next(new Error("Unauthorized")); const requiredPermissions = permParams?.permissions ?? []; if (requiredPermissions.length > 0) { const permissionChecks = await Promise.all( requiredPermissions.map((permission) => user.hasPermission(permission)), ); if (permissionChecks.includes(false)) { return next(new Error("Forbidden: insufficient permissions")); } } const eventPermissions = permParams?.eventPermissions; if (eventPermissions) { const attached = attachSocketEventPermissions(socket, eventPermissions); if (!attached) return next(new Error("Unauthorized")); } return next(); }; };