backend: update security preferences structure to remove unused attributes and refactor associated code
This commit is contained in:
parent
dd3a2939e4
commit
55bc8726d0
@ -1,4 +1,4 @@
|
||||
import { SecurityPreferencesDTO, UpdateSecurityPreferencesDTO } from '@typings-ce';
|
||||
import { SecurityPreferences } from '@typings-ce';
|
||||
import { Request, Response } from 'express';
|
||||
import { container } from '../../config/index.js';
|
||||
import { handleError } from '../../models/error.model.js';
|
||||
@ -9,29 +9,15 @@ export const updateSecurityPreferences = async (req: Request, res: Response) =>
|
||||
const globalPrefService = container.get(MeetStorageService);
|
||||
|
||||
logger.verbose(`Updating security preferences: ${JSON.stringify(req.body)}`);
|
||||
const securityPreferences = req.body as UpdateSecurityPreferencesDTO;
|
||||
const securityPreferences = req.body as SecurityPreferences;
|
||||
|
||||
try {
|
||||
const globalPreferences = await globalPrefService.getGlobalPreferences();
|
||||
const currentAuth = globalPreferences.securityPreferences.authentication;
|
||||
const newAuth = securityPreferences.authentication;
|
||||
|
||||
if (securityPreferences.roomCreationPolicy) {
|
||||
globalPreferences.securityPreferences.roomCreationPolicy = {
|
||||
allowRoomCreation: securityPreferences.roomCreationPolicy.allowRoomCreation,
|
||||
requireAuthentication:
|
||||
securityPreferences.roomCreationPolicy.requireAuthentication === undefined
|
||||
? globalPreferences.securityPreferences.roomCreationPolicy.requireAuthentication
|
||||
: securityPreferences.roomCreationPolicy.requireAuthentication
|
||||
};
|
||||
}
|
||||
|
||||
if (securityPreferences.authentication) {
|
||||
const currentAuth = globalPreferences.securityPreferences.authentication;
|
||||
const newAuth = securityPreferences.authentication;
|
||||
|
||||
currentAuth.authMode = newAuth.authMode;
|
||||
currentAuth.method.type = newAuth.method.type;
|
||||
}
|
||||
|
||||
currentAuth.authMethod = newAuth.authMethod;
|
||||
currentAuth.authModeToAccessRoom = newAuth.authModeToAccessRoom;
|
||||
await globalPrefService.saveGlobalPreferences(globalPreferences);
|
||||
|
||||
return res.status(200).json({ message: 'Security preferences updated successfully' });
|
||||
@ -48,19 +34,8 @@ export const getSecurityPreferences = async (_req: Request, res: Response) => {
|
||||
|
||||
try {
|
||||
const preferences = await preferenceService.getGlobalPreferences();
|
||||
|
||||
// Convert the preferences to the DTO format by removing credentials
|
||||
const securityPreferences = preferences.securityPreferences;
|
||||
const securityPreferencesDTO: SecurityPreferencesDTO = {
|
||||
roomCreationPolicy: securityPreferences.roomCreationPolicy,
|
||||
authentication: {
|
||||
authMode: securityPreferences.authentication.authMode,
|
||||
method: {
|
||||
type: securityPreferences.authentication.method.type
|
||||
}
|
||||
}
|
||||
};
|
||||
return res.status(200).json(securityPreferencesDTO);
|
||||
return res.status(200).json(securityPreferences);
|
||||
} catch (error) {
|
||||
handleError(res, error, 'getting security preferences');
|
||||
}
|
||||
|
||||
@ -25,22 +25,22 @@ export const configureParticipantTokenAuth = async (req: Request, res: Response,
|
||||
return handleError(res, error, 'getting room role by secret');
|
||||
}
|
||||
|
||||
let authMode: AuthMode;
|
||||
let authModeToAccessRoom: AuthMode;
|
||||
|
||||
try {
|
||||
const { securityPreferences } = await globalPrefService.getGlobalPreferences();
|
||||
authMode = securityPreferences.authentication.authMode;
|
||||
authModeToAccessRoom = securityPreferences.authentication.authModeToAccessRoom;
|
||||
} catch (error) {
|
||||
return handleError(res, error, 'checking authentication preferences');
|
||||
}
|
||||
|
||||
const authValidators = [];
|
||||
|
||||
if (authMode === AuthMode.NONE) {
|
||||
if (authModeToAccessRoom === AuthMode.NONE) {
|
||||
authValidators.push(allowAnonymous);
|
||||
} else {
|
||||
const isModeratorsOnlyMode = authMode === AuthMode.MODERATORS_ONLY && role === ParticipantRole.MODERATOR;
|
||||
const isAllUsersMode = authMode === AuthMode.ALL_USERS;
|
||||
const isModeratorsOnlyMode = authModeToAccessRoom === AuthMode.MODERATORS_ONLY && role === ParticipantRole.MODERATOR;
|
||||
const isAllUsersMode = authModeToAccessRoom === AuthMode.ALL_USERS;
|
||||
|
||||
if (isModeratorsOnlyMode || isAllUsersMode) {
|
||||
authValidators.push(tokenAndRoleValidator(UserRole.USER));
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import {
|
||||
AuthenticationPreferencesDTO,
|
||||
AuthenticationPreferences,
|
||||
AuthMode,
|
||||
AuthType,
|
||||
RoomCreationPolicy,
|
||||
SingleUserAuthDTO,
|
||||
UpdateSecurityPreferencesDTO,
|
||||
ValidAuthMethodDTO,
|
||||
SecurityPreferences,
|
||||
SingleUserAuth,
|
||||
ValidAuthMethod,
|
||||
WebhookPreferences
|
||||
} from '@typings-ce';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
@ -36,41 +35,20 @@ const AuthModeSchema: z.ZodType<AuthMode> = z.enum([AuthMode.NONE, AuthMode.MODE
|
||||
|
||||
const AuthTypeSchema: z.ZodType<AuthType> = z.enum([AuthType.SINGLE_USER]);
|
||||
|
||||
const SingleUserAuthDTOSchema: z.ZodType<SingleUserAuthDTO> = z.object({
|
||||
const SingleUserAuthSchema: z.ZodType<SingleUserAuth> = z.object({
|
||||
type: AuthTypeSchema
|
||||
});
|
||||
|
||||
const ValidAuthMethodDTOSchema: z.ZodType<ValidAuthMethodDTO> = SingleUserAuthDTOSchema;
|
||||
const ValidAuthMethodSchema: z.ZodType<ValidAuthMethod> = SingleUserAuthSchema;
|
||||
|
||||
const AuthenticationPreferencesDTOSchema: z.ZodType<AuthenticationPreferencesDTO> = z.object({
|
||||
authMode: AuthModeSchema,
|
||||
method: ValidAuthMethodDTOSchema
|
||||
const AuthenticationPreferencesSchema: z.ZodType<AuthenticationPreferences> = z.object({
|
||||
authMethod: ValidAuthMethodSchema,
|
||||
authModeToAccessRoom: AuthModeSchema
|
||||
});
|
||||
|
||||
const RoomCreationPolicySchema: z.ZodType<RoomCreationPolicy> = z
|
||||
.object({
|
||||
allowRoomCreation: z.boolean(),
|
||||
requireAuthentication: z.boolean().optional()
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
// If allowRoomCreation is true, requireAuthentication must be provided
|
||||
return !data.allowRoomCreation || data.requireAuthentication !== undefined;
|
||||
},
|
||||
{
|
||||
message: 'requireAuthentication is required when allowRoomCreation is true',
|
||||
path: ['requireAuthentication']
|
||||
}
|
||||
);
|
||||
|
||||
const UpdateSecurityPreferencesDTOSchema: z.ZodType<UpdateSecurityPreferencesDTO> = z
|
||||
.object({
|
||||
authentication: AuthenticationPreferencesDTOSchema.optional(),
|
||||
roomCreationPolicy: RoomCreationPolicySchema.optional()
|
||||
})
|
||||
.refine((data) => Object.keys(data).length > 0, {
|
||||
message: 'At least one field must be provided for the update'
|
||||
});
|
||||
const SecurityPreferencesSchema: z.ZodType<SecurityPreferences> = z.object({
|
||||
authentication: AuthenticationPreferencesSchema
|
||||
});
|
||||
|
||||
export const validateWebhookPreferences = (req: Request, res: Response, next: NextFunction) => {
|
||||
const { success, error, data } = WebhookPreferencesSchema.safeParse(req.body);
|
||||
@ -84,7 +62,7 @@ export const validateWebhookPreferences = (req: Request, res: Response, next: Ne
|
||||
};
|
||||
|
||||
export const validateSecurityPreferences = (req: Request, res: Response, next: NextFunction) => {
|
||||
const { success, error, data } = UpdateSecurityPreferencesDTOSchema.safeParse(req.body);
|
||||
const { success, error, data } = SecurityPreferencesSchema.safeParse(req.body);
|
||||
|
||||
if (!success) {
|
||||
return rejectUnprocessableRequest(res, error);
|
||||
|
||||
@ -8,39 +8,7 @@ import {
|
||||
rejectRequestFromMeetError
|
||||
} from '../models/error.model.js';
|
||||
import { MeetStorageService, RoomService } from '../services/index.js';
|
||||
import { allowAnonymous, apiKeyValidator, tokenAndRoleValidator, withAuth } from './auth.middleware.js';
|
||||
|
||||
/**
|
||||
* Middleware that configures authentication for creating a room based on global settings.
|
||||
*
|
||||
* - Admin role and API key authentication methods are always allowed.
|
||||
* - If room creation is allowed and requires authentication, the user must have a valid token.
|
||||
* - If room creation is allowed and does not require authentication, anonymous users are allowed.
|
||||
*/
|
||||
export const configureCreateRoomAuth = async (req: Request, res: Response, next: NextFunction) => {
|
||||
const globalPrefService = container.get(MeetStorageService);
|
||||
let allowRoomCreation: boolean;
|
||||
let requireAuthentication: boolean | undefined;
|
||||
|
||||
try {
|
||||
const { securityPreferences } = await globalPrefService.getGlobalPreferences();
|
||||
({ allowRoomCreation, requireAuthentication } = securityPreferences.roomCreationPolicy);
|
||||
} catch (error) {
|
||||
return handleError(res, error, 'checking room creation policy');
|
||||
}
|
||||
|
||||
const authValidators = [apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN)];
|
||||
|
||||
if (allowRoomCreation) {
|
||||
if (requireAuthentication) {
|
||||
authValidators.push(tokenAndRoleValidator(UserRole.USER));
|
||||
} else {
|
||||
authValidators.push(allowAnonymous);
|
||||
}
|
||||
}
|
||||
|
||||
return withAuth(...authValidators)(req, res, next);
|
||||
};
|
||||
import { allowAnonymous, tokenAndRoleValidator, withAuth } from './auth.middleware.js';
|
||||
|
||||
/**
|
||||
* Middleware that configures authorization for accessing a specific room.
|
||||
@ -79,7 +47,7 @@ export const configureRoomAuthorization = async (req: Request, res: Response, ne
|
||||
};
|
||||
|
||||
/**
|
||||
* Middleware to configure authentication based on participant role and authentication mode
|
||||
* 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.
|
||||
@ -114,22 +82,22 @@ export const configureRecordingTokenAuth = async (req: Request, res: Response, n
|
||||
return handleError(res, error, 'getting room role by secret');
|
||||
}
|
||||
|
||||
let authMode: AuthMode;
|
||||
let authModeToAccessRoom: AuthMode;
|
||||
|
||||
try {
|
||||
const { securityPreferences } = await storageService.getGlobalPreferences();
|
||||
authMode = securityPreferences.authentication.authMode;
|
||||
authModeToAccessRoom = securityPreferences.authentication.authModeToAccessRoom;
|
||||
} catch (error) {
|
||||
return handleError(res, error, 'checking authentication preferences');
|
||||
}
|
||||
|
||||
const authValidators = [];
|
||||
|
||||
if (authMode === AuthMode.NONE) {
|
||||
if (authModeToAccessRoom === AuthMode.NONE) {
|
||||
authValidators.push(allowAnonymous);
|
||||
} else {
|
||||
const isModeratorsOnlyMode = authMode === AuthMode.MODERATORS_ONLY && role === ParticipantRole.MODERATOR;
|
||||
const isAllUsersMode = authMode === AuthMode.ALL_USERS;
|
||||
const isModeratorsOnlyMode = authModeToAccessRoom === AuthMode.MODERATORS_ONLY && role === ParticipantRole.MODERATOR;
|
||||
const isAllUsersMode = authModeToAccessRoom === AuthMode.ALL_USERS;
|
||||
|
||||
if (isModeratorsOnlyMode || isAllUsersMode) {
|
||||
authValidators.push(tokenAndRoleValidator(UserRole.USER));
|
||||
|
||||
@ -3,8 +3,8 @@ import bodyParser from 'body-parser';
|
||||
import { Router } from 'express';
|
||||
import * as roomCtrl from '../controllers/room.controller.js';
|
||||
import {
|
||||
allowAnonymous,
|
||||
apiKeyValidator,
|
||||
configureCreateRoomAuth,
|
||||
configureRecordingTokenAuth,
|
||||
configureRoomAuthorization,
|
||||
participantTokenValidator,
|
||||
@ -24,7 +24,12 @@ roomRouter.use(bodyParser.urlencoded({ extended: true }));
|
||||
roomRouter.use(bodyParser.json());
|
||||
|
||||
// Room Routes
|
||||
roomRouter.post('/', configureCreateRoomAuth, withValidRoomOptions, roomCtrl.createRoom);
|
||||
roomRouter.post(
|
||||
'/',
|
||||
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN)),
|
||||
withValidRoomOptions,
|
||||
roomCtrl.createRoom
|
||||
);
|
||||
roomRouter.get(
|
||||
'/',
|
||||
withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN)),
|
||||
@ -56,7 +61,6 @@ export const internalRoomRouter = Router();
|
||||
internalRoomRouter.use(bodyParser.urlencoded({ extended: true }));
|
||||
internalRoomRouter.use(bodyParser.json());
|
||||
|
||||
// Room preferences
|
||||
internalRoomRouter.put(
|
||||
'/:roomId',
|
||||
withAuth(tokenAndRoleValidator(UserRole.ADMIN)),
|
||||
@ -64,7 +68,6 @@ internalRoomRouter.put(
|
||||
withValidRoomPreferences,
|
||||
roomCtrl.updateRoomPreferences
|
||||
);
|
||||
|
||||
internalRoomRouter.post(
|
||||
'/:roomId/recording-token',
|
||||
configureRecordingTokenAuth,
|
||||
@ -72,7 +75,15 @@ internalRoomRouter.post(
|
||||
withValidRoomSecret,
|
||||
roomCtrl.generateRecordingToken
|
||||
);
|
||||
|
||||
// Roles and permissions
|
||||
internalRoomRouter.get('/:roomId/roles', withValidRoomId, roomCtrl.getRoomRolesAndPermissions);
|
||||
internalRoomRouter.get('/:roomId/roles/:secret', withValidRoomId, roomCtrl.getRoomRoleAndPermissions);
|
||||
internalRoomRouter.get(
|
||||
'/:roomId/roles',
|
||||
withAuth(allowAnonymous),
|
||||
withValidRoomId,
|
||||
roomCtrl.getRoomRolesAndPermissions
|
||||
);
|
||||
internalRoomRouter.get(
|
||||
'/:roomId/roles/:secret',
|
||||
withAuth(allowAnonymous),
|
||||
withValidRoomId,
|
||||
roomCtrl.getRoomRoleAndPermissions
|
||||
);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export interface AuthenticationPreferences {
|
||||
authMode: AuthMode;
|
||||
method: ValidAuthMethod;
|
||||
authMethod: ValidAuthMethod;
|
||||
authModeToAccessRoom: AuthMode;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,7 +33,6 @@ export const enum AuthType {
|
||||
*/
|
||||
export interface SingleUserAuth extends AuthMethod {
|
||||
type: AuthType.SINGLE_USER;
|
||||
credentials: SingleUserCredentials;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,14 +56,6 @@ export interface SingleUserAuth extends AuthMethod {
|
||||
*/
|
||||
export type ValidAuthMethod = SingleUserAuth /* | MultiUserAuth | OAuthOnlyAuth */;
|
||||
|
||||
/**
|
||||
* Configuration for a single user login method.
|
||||
*/
|
||||
export interface SingleUserCredentials {
|
||||
username: string;
|
||||
passwordHash: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for OAuth authentication.
|
||||
*/
|
||||
@ -82,13 +73,3 @@ export interface SingleUserCredentials {
|
||||
// GOOGLE = 'google',
|
||||
// GITHUB = 'github'
|
||||
// }
|
||||
|
||||
// DTOs
|
||||
export interface AuthenticationPreferencesDTO {
|
||||
authMode: AuthMode;
|
||||
method: ValidAuthMethodDTO;
|
||||
}
|
||||
|
||||
export type ValidAuthMethodDTO = SingleUserAuthDTO;
|
||||
|
||||
export type SingleUserAuthDTO = Omit<SingleUserAuth, 'credentials'>;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AuthenticationPreferences, AuthenticationPreferencesDTO } from './auth-preferences.js';
|
||||
import { AuthenticationPreferences } from './auth-preferences.js';
|
||||
|
||||
/**
|
||||
* Represents global preferences for OpenVidu Meet.
|
||||
@ -18,19 +18,4 @@ export interface WebhookPreferences {
|
||||
|
||||
export interface SecurityPreferences {
|
||||
authentication: AuthenticationPreferences;
|
||||
roomCreationPolicy: RoomCreationPolicy;
|
||||
// e2eEncryption: {};
|
||||
}
|
||||
|
||||
export interface RoomCreationPolicy {
|
||||
allowRoomCreation: boolean;
|
||||
requireAuthentication?: boolean;
|
||||
}
|
||||
|
||||
// DTOs
|
||||
export interface SecurityPreferencesDTO {
|
||||
authentication: AuthenticationPreferencesDTO;
|
||||
roomCreationPolicy: RoomCreationPolicy;
|
||||
}
|
||||
|
||||
export type UpdateSecurityPreferencesDTO = Partial<SecurityPreferencesDTO>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user