frontend: implement validate access guards for rooms and update participant name handling

This commit is contained in:
juancarmore 2025-08-05 17:53:29 +02:00
parent 6e9c1743a1
commit bdc3f599f0
5 changed files with 51 additions and 10 deletions

View File

@ -2,4 +2,4 @@ export * from './auth.guard';
export * from './extract-query-params.guard';
export * from './remove-secret.guard';
export * from './run-serially.guard';
export * from './validate-recording-access.guard';
export * from './validate-access.guard';

View File

@ -1,10 +1,10 @@
import { inject } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot } from '@angular/router';
import { ErrorReason } from '@lib/models';
import { NavigationService, RecordingManagerService, RoomService } from '@lib/services';
import { NavigationService, ParticipantTokenService, RecordingManagerService, RoomService } from '@lib/services';
/**
* Guard to validate the access to recordings.
* Guard to validate the access to recordings of a room by generating a recording token.
*/
export const validateRecordingAccessGuard: CanActivateFn = async (
_route: ActivatedRouteSnapshot,
@ -32,7 +32,7 @@ export const validateRecordingAccessGuard: CanActivateFn = async (
switch (error.status) {
case 400:
// Invalid secret
return navigationService.redirectToErrorPage(ErrorReason.INVALID_RECORDING_SECRET);
return navigationService.redirectToErrorPage(ErrorReason.INVALID_ROOM_SECRET);
case 403:
// Recording access is configured for admins only
return navigationService.redirectToErrorPage(ErrorReason.RECORDINGS_ADMIN_ONLY_ACCESS);
@ -44,3 +44,38 @@ export const validateRecordingAccessGuard: CanActivateFn = async (
}
}
};
/**
* Guard to validate access to a room by generating a participant token.
*/
export const validateRoomAccessGuard: CanActivateFn = async (
_route: ActivatedRouteSnapshot,
_state: RouterStateSnapshot
) => {
const roomService = inject(RoomService);
const participantTokenService = inject(ParticipantTokenService);
const navigationService = inject(NavigationService);
const roomId = roomService.getRoomId();
const secret = roomService.getRoomSecret();
try {
await participantTokenService.generateToken({
roomId,
secret
});
return true;
} catch (error: any) {
console.error('Error generating participant token:', error);
switch (error.status) {
case 400:
// Invalid secret
return navigationService.redirectToErrorPage(ErrorReason.INVALID_ROOM_SECRET);
case 404:
// Room not found
return navigationService.redirectToErrorPage(ErrorReason.INVALID_ROOM);
default:
return navigationService.redirectToErrorPage(ErrorReason.INTERNAL_ERROR);
}
}
};

View File

@ -49,7 +49,7 @@ export const httpInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, ne
const secret = roomService.getRoomSecret();
const participantName = participantTokenService.getParticipantName();
return from(participantTokenService.refreshParticipantToken({ roomId, participantName, secret })).pipe(
return from(participantTokenService.refreshParticipantToken({ roomId, secret, participantName })).pipe(
switchMap(() => {
console.log('Participant token refreshed');
return next(req);

View File

@ -8,7 +8,8 @@ import {
extractRoomQueryParamsGuard,
removeRoomSecretGuard,
runGuardsSerially,
validateRecordingAccessGuard
validateRecordingAccessGuard,
validateRoomAccessGuard
} from '@lib/guards';
import {
ConsoleComponent,
@ -16,13 +17,13 @@ import {
EndMeetingComponent,
ErrorComponent,
LoginComponent,
MeetingComponent,
OverviewComponent,
RecordingsComponent,
RoomRecordingsComponent,
RoomsComponent,
RoomWizardComponent,
UsersPermissionsComponent,
MeetingComponent,
ViewRecordingComponent
} from '@lib/pages';
@ -36,7 +37,12 @@ export const baseRoutes: Routes = [
path: 'room/:room-id',
component: MeetingComponent,
canActivate: [
runGuardsSerially(extractRoomQueryParamsGuard, checkParticipantRoleAndAuthGuard, removeRoomSecretGuard)
runGuardsSerially(
extractRoomQueryParamsGuard,
checkParticipantRoleAndAuthGuard,
validateRoomAccessGuard,
removeRoomSecretGuard
)
]
},
{

View File

@ -11,7 +11,7 @@ import { LoggerService } from 'openvidu-components-angular';
export class ParticipantTokenService {
protected readonly PARTICIPANTS_API = `${HttpService.INTERNAL_API_PATH_PREFIX}/participants`;
protected participantName: string = '';
protected participantName?: string;
protected participantRole: ParticipantRole = ParticipantRole.PUBLISHER;
protected currentTokenInfo?: ParticipantTokenInfo;
@ -29,7 +29,7 @@ export class ParticipantTokenService {
this.participantName = participantName;
}
getParticipantName(): string {
getParticipantName(): string | undefined {
return this.participantName;
}