104 lines
3.6 KiB
TypeScript
104 lines
3.6 KiB
TypeScript
import { AuthMode, MeetRecordingAccess, MeetRoom, ParticipantRole, UserRole } from '@typings-ce';
|
|
import { NextFunction, Request, Response } from 'express';
|
|
import { container } from '../config/index.js';
|
|
import {
|
|
errorInsufficientPermissions,
|
|
errorRoomMetadataNotFound,
|
|
handleError,
|
|
rejectRequestFromMeetError
|
|
} from '../models/error.model.js';
|
|
import { MeetStorageService, RoomService } from '../services/index.js';
|
|
import { allowAnonymous, tokenAndRoleValidator, withAuth } from './auth.middleware.js';
|
|
|
|
/**
|
|
* Middleware that configures authorization for accessing a specific room.
|
|
*
|
|
* - If there is no token in the session, the user is granted access (admin or API key).
|
|
* - If the user does not belong to the requested room, access is denied.
|
|
* - Otherwise, the user is allowed to access the room.
|
|
*/
|
|
export const configureRoomAuthorization = async (req: Request, res: Response, next: NextFunction) => {
|
|
const roomId = req.params.roomId as string;
|
|
const payload = req.session?.tokenClaims;
|
|
|
|
// If there is no token, the user is admin or it is invoked using the API key
|
|
// In this case, the user is allowed to access the resource
|
|
if (!payload) {
|
|
return next();
|
|
}
|
|
|
|
const sameRoom = payload.video?.room === roomId;
|
|
|
|
// If the user does not belong to the requested room, access is denied
|
|
if (!sameRoom) {
|
|
const error = errorInsufficientPermissions();
|
|
return rejectRequestFromMeetError(res, error);
|
|
}
|
|
|
|
return next();
|
|
};
|
|
|
|
/**
|
|
* Middleware to configure authentication based on participant role and authentication mode to access a room
|
|
* for generating a token for retrieving/deleting recordings.
|
|
*
|
|
* - If the authentication mode is MODERATORS_ONLY and the participant role is MODERATOR, configure user authentication.
|
|
* - If the authentication mode is ALL_USERS, configure user authentication.
|
|
* - Otherwise, allow anonymous access.
|
|
*/
|
|
export const configureRecordingTokenAuth = async (req: Request, res: Response, next: NextFunction) => {
|
|
const storageService = container.get(MeetStorageService);
|
|
const roomService = container.get(RoomService);
|
|
|
|
let role: ParticipantRole;
|
|
|
|
try {
|
|
const roomId = req.params.roomId;
|
|
const { secret } = req.body;
|
|
const room = await storageService.getArchivedRoomMetadata(roomId);
|
|
|
|
if (!room) {
|
|
// If the room is not found, it means that there are no recordings for that room or the room doesn't exist
|
|
throw errorRoomMetadataNotFound(roomId);
|
|
}
|
|
|
|
const recordingAccess = room.preferences!.recordingPreferences.allowAccessTo;
|
|
|
|
if (!recordingAccess || recordingAccess === MeetRecordingAccess.ADMIN) {
|
|
// Deny request if the room is configured to allow access to recordings only for admins
|
|
throw errorInsufficientPermissions();
|
|
}
|
|
|
|
role = roomService.getRoomRoleBySecretFromRoom(room as MeetRoom, secret);
|
|
} catch (error) {
|
|
return handleError(res, error, 'getting room role by secret');
|
|
}
|
|
|
|
let authModeToAccessRoom: AuthMode;
|
|
|
|
try {
|
|
const { securityPreferences } = await storageService.getGlobalPreferences();
|
|
authModeToAccessRoom = securityPreferences.authentication.authModeToAccessRoom;
|
|
} catch (error) {
|
|
return handleError(res, error, 'checking authentication preferences');
|
|
}
|
|
|
|
const authValidators = [];
|
|
|
|
if (authModeToAccessRoom === AuthMode.NONE) {
|
|
authValidators.push(allowAnonymous);
|
|
} else {
|
|
const isModeratorsOnlyMode =
|
|
authModeToAccessRoom === AuthMode.MODERATORS_ONLY && role === ParticipantRole.MODERATOR;
|
|
const isAllUsersMode = authModeToAccessRoom === AuthMode.ALL_USERS;
|
|
|
|
if (isModeratorsOnlyMode || isAllUsersMode) {
|
|
authValidators.push(tokenAndRoleValidator(UserRole.USER));
|
|
} else {
|
|
authValidators.push(allowAnonymous);
|
|
}
|
|
}
|
|
|
|
return withAuth(...authValidators)(req, res, next);
|
|
};
|