diff --git a/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts b/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts index 15a1820..00d196b 100644 --- a/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts +++ b/frontend/projects/shared-meet-components/src/lib/guards/auth.guard.ts @@ -98,3 +98,42 @@ export const checkParticipantRoleAndAuthGuard: CanActivateFn = async ( // Allow access to the room return true; }; + +export const checkRecordingAuthGuard: CanActivateFn = async ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot +) => { + const httpService = inject(HttpService); + const navigationService = inject(NavigationService); + + const recordingId = route.params['recording-id']; + const secret = route.queryParams['secret']; + + if (!secret) { + // If no secret is provided, redirect to the error page + return navigationService.createRedirectionToErrorPage(ErrorReason.MISSING_RECORDING_SECRET); + } + + try { + // Attempt to access the recording to check if the secret is valid + await httpService.getRecording(recordingId, secret); + return true; + } catch (error: any) { + console.error('Error checking recording access:', error); + switch (error.status) { + case 400: + // Invalid secret + return navigationService.createRedirectionToErrorPage(ErrorReason.INVALID_RECORDING_SECRET); + case 401: + // Unauthorized access + // Redirect to the login page with query param to redirect back to the recording + return navigationService.createRedirectionToLoginPage(state.url); + case 404: + // Recording not found + return navigationService.createRedirectionToErrorPage(ErrorReason.INVALID_RECORDING); + default: + // Internal error + return navigationService.createRedirectionToErrorPage(ErrorReason.INTERNAL_ERROR); + } + } +}; diff --git a/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts b/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts index c18e9b5..feb4f18 100644 --- a/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts +++ b/frontend/projects/shared-meet-components/src/lib/routes/base-routes.ts @@ -2,6 +2,7 @@ import { Routes } from '@angular/router'; import { applicationModeGuard, checkParticipantRoleAndAuthGuard, + checkRecordingAuthGuard, checkUserAuthenticatedGuard, checkUserNotAuthenticatedGuard, extractRecordingQueryParamsGuard, @@ -20,7 +21,8 @@ import { RoomFormComponent, RoomRecordingsComponent, RoomsComponent, - VideoRoomComponent + VideoRoomComponent, + ViewRecordingComponent } from '../pages'; export const baseRoutes: Routes = [ @@ -95,6 +97,11 @@ export const baseRoutes: Routes = [ ) ] }, + { + path: 'recording/:recording-id', + component: ViewRecordingComponent, + canActivate: [runGuardsSerially(applicationModeGuard, checkRecordingAuthGuard)] + }, { path: 'disconnected', component: DisconnectedComponent }, { path: 'error', component: ErrorComponent }, diff --git a/frontend/projects/shared-meet-components/src/lib/services/http/http.service.ts b/frontend/projects/shared-meet-components/src/lib/services/http/http.service.ts index b35a3b2..e8a85e1 100644 --- a/frontend/projects/shared-meet-components/src/lib/services/http/http.service.ts +++ b/frontend/projects/shared-meet-components/src/lib/services/http/http.service.ts @@ -110,10 +110,6 @@ export class HttpService { return this.postRequest(`${this.INTERNAL_API_PATH_PREFIX}/rooms/${roomId}/recording-token`, { secret }); } - getRecordingMediaUrl(recordingId: string): string { - return `${this.API_PATH_PREFIX}/recordings/${recordingId}/media`; - } - getRecordings(filters?: MeetRecordingFilters): Promise<{ recordings: MeetRecordingInfo[]; pagination: { @@ -145,6 +141,18 @@ export class HttpService { return this.getRequest(path); } + getRecording(recordingId: string, secret?: string): Promise { + let path = `${this.API_PATH_PREFIX}/recordings/${recordingId}`; + if (secret) { + path += `?secret=${secret}`; + } + return this.getRequest(path); + } + + getRecordingMediaUrl(recordingId: string): string { + return `${this.API_PATH_PREFIX}/recordings/${recordingId}/media`; + } + startRecording(roomId: string): Promise { return this.postRequest(`${this.INTERNAL_API_PATH_PREFIX}/recordings`, { roomId }); }