frontend: replace UnauthorizedComponent by ErrorComponent and improve error handling in guards
This commit is contained in:
parent
b037edb92b
commit
ab270239b5
@ -1,4 +0,0 @@
|
||||
<div id="unauthorized-content">
|
||||
<h4>The page you are trying to access is restricted.</h4>
|
||||
<h4 id="error-reason">Reason: {{ message }}</h4>
|
||||
</div>
|
||||
@ -1,23 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UnauthorizedComponent } from './unauthorized.component';
|
||||
|
||||
describe('UnauthorizedComponent', () => {
|
||||
let component: UnauthorizedComponent;
|
||||
let fixture: ComponentFixture<UnauthorizedComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [UnauthorizedComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(UnauthorizedComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -1,38 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-unauthorized',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './unauthorized.component.html',
|
||||
styleUrl: './unauthorized.component.scss'
|
||||
})
|
||||
export class UnauthorizedComponent implements OnInit {
|
||||
message = 'Unauthorized access';
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams.subscribe((params) => {
|
||||
const reason = params['reason'];
|
||||
switch (reason) {
|
||||
case 'invalid-token':
|
||||
this.message = 'The token provided is not valid';
|
||||
break;
|
||||
case 'invalid-room':
|
||||
this.message = 'The room name is not valid';
|
||||
break;
|
||||
case 'invalid-participant':
|
||||
this.message = 'The participant name must be provided';
|
||||
break;
|
||||
case 'unauthorized-participant':
|
||||
this.message = 'You are not authorized to join this room';
|
||||
break;
|
||||
|
||||
default:
|
||||
this.message = 'Unauthorized access';
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,14 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivateFn, RedirectCommand, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { AuthService, ContextService, HttpService, SessionStorageService } from '../services';
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivateFn,
|
||||
RedirectCommand,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
UrlTree
|
||||
} from '@angular/router';
|
||||
import { AuthMode, ParticipantRole } from '@lib/typings/ce';
|
||||
import { AuthService, ContextService, HttpService, SessionStorageService } from '../services';
|
||||
|
||||
export const checkUserAuthenticatedGuard: CanActivateFn = async (
|
||||
route: ActivatedRouteSnapshot,
|
||||
@ -64,9 +71,18 @@ export const checkParticipantRoleAndAuthGuard: CanActivateFn = async (
|
||||
const roomRoleAndPermissions = await httpService.getRoomRoleAndPermissions(roomId, storageSecret || secret);
|
||||
participantRole = roomRoleAndPermissions.role;
|
||||
contextService.setParticipantRole(participantRole);
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('Error getting participant role:', error);
|
||||
return router.createUrlTree(['unauthorized'], { queryParams: { reason: 'unauthorized-participant' } });
|
||||
switch (error.status) {
|
||||
case 400:
|
||||
// Invalid secret
|
||||
return redirectToErrorPage(router, 'invalid-secret');
|
||||
case 404:
|
||||
// Room not found
|
||||
return redirectToErrorPage(router, 'invalid-room');
|
||||
default:
|
||||
return redirectToErrorPage(router, 'internal-error');
|
||||
}
|
||||
}
|
||||
|
||||
const authMode = await contextService.getAuthModeToEnterRoom();
|
||||
@ -114,3 +130,7 @@ export const checkUserNotAuthenticatedGuard: CanActivateFn = async (
|
||||
// Allow access to the requested page
|
||||
return true;
|
||||
};
|
||||
|
||||
const redirectToErrorPage = (router: Router, reason: string): UrlTree => {
|
||||
return router.createUrlTree(['error'], { queryParams: { reason } });
|
||||
};
|
||||
|
||||
@ -31,26 +31,29 @@ export const validateRecordingAccessGuard: CanActivateFn = async (
|
||||
contextService.setRecordingPermissionsFromToken(response.token);
|
||||
|
||||
if (!contextService.canRetrieveRecordings()) {
|
||||
// If the user does not have permission to retrieve recordings, redirect to the unauthorized page
|
||||
return redirectToUnauthorized(router, 'unauthorized-recording-access');
|
||||
// If the user does not have permission to retrieve recordings, redirect to the error page
|
||||
return redirectToErrorPage(router, 'unauthorized-recording-access');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
console.error('Error generating recording token:', error);
|
||||
switch (error.status) {
|
||||
case 400:
|
||||
// Invalid secret
|
||||
return redirectToErrorPage(router, 'invalid-secret');
|
||||
case 403:
|
||||
// Recording access is configured for admins only
|
||||
return redirectToUnauthorized(router, 'unauthorized-recording-access');
|
||||
return redirectToErrorPage(router, 'recordings-admin-only-access');
|
||||
case 404:
|
||||
// There are no recordings in the room or the room does not exist
|
||||
return redirectToUnauthorized(router, 'no-recordings');
|
||||
return redirectToErrorPage(router, 'no-recordings');
|
||||
default:
|
||||
return redirectToUnauthorized(router, 'invalid-room');
|
||||
return redirectToErrorPage(router, 'internal-error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const redirectToUnauthorized = (router: Router, reason: string): UrlTree => {
|
||||
return router.createUrlTree(['unauthorized'], { queryParams: { reason } });
|
||||
const redirectToErrorPage = (router: Router, reason: string): UrlTree => {
|
||||
return router.createUrlTree(['error'], { queryParams: { reason } });
|
||||
};
|
||||
|
||||
@ -38,6 +38,12 @@ export const validateRoomAccessGuard: CanActivateFn = async (
|
||||
} catch (error: any) {
|
||||
console.error('Error generating participant token:', error);
|
||||
switch (error.status) {
|
||||
case 400:
|
||||
// Invalid secret
|
||||
return redirectToErrorPage(router, 'invalid-secret');
|
||||
case 404:
|
||||
// Room not found
|
||||
return redirectToErrorPage(router, 'invalid-room');
|
||||
case 409:
|
||||
// Participant already exists.
|
||||
// Send a timestamp to force update the query params and show the error message in participant name input form
|
||||
@ -47,14 +53,12 @@ export const validateRoomAccessGuard: CanActivateFn = async (
|
||||
return new RedirectCommand(participantNameRoute, {
|
||||
skipLocationChange: true
|
||||
});
|
||||
case 406:
|
||||
return redirectToUnauthorized(router, 'unauthorized-participant');
|
||||
default:
|
||||
return redirectToUnauthorized(router, 'invalid-room');
|
||||
return redirectToErrorPage(router, 'internal-error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const redirectToUnauthorized = (router: Router, reason: string): UrlTree => {
|
||||
return router.createUrlTree(['unauthorized'], { queryParams: { reason } });
|
||||
const redirectToErrorPage = (router: Router, reason: string): UrlTree => {
|
||||
return router.createUrlTree(['error'], { queryParams: { reason } });
|
||||
};
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
<div class="container">
|
||||
<mat-card class="card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ errorName }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>{{ message }}</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
@ -0,0 +1,33 @@
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
background-color: var(--ov-background-color);
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 400px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
background-color: var(--ov-surface-color);
|
||||
border-radius: var(--ov-surface-radius);
|
||||
}
|
||||
|
||||
mat-card-header {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
mat-card-title {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
mat-card-content p {
|
||||
font-size: 1em;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
mat-card-actions {
|
||||
margin-top: 20px;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ErrorComponent } from './error.component';
|
||||
|
||||
describe('GenericErrorComponent', () => {
|
||||
let component: ErrorComponent;
|
||||
let fixture: ComponentFixture<ErrorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ErrorComponent]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ErrorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,50 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-error',
|
||||
standalone: true,
|
||||
imports: [MatCardModule],
|
||||
templateUrl: './error.component.html',
|
||||
styleUrl: './error.component.scss'
|
||||
})
|
||||
export class ErrorComponent implements OnInit {
|
||||
errorName = 'Error';
|
||||
message = '';
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams.subscribe((params) => {
|
||||
const reason = params['reason'];
|
||||
switch (reason) {
|
||||
case 'invalid-secret':
|
||||
this.errorName = 'Invalid secret';
|
||||
this.message =
|
||||
'The secret provided to join the room is neither valid for moderators nor publishers';
|
||||
break;
|
||||
case 'invalid-room':
|
||||
this.errorName = 'Invalid room';
|
||||
this.message = 'The room you are trying to join does not exist or has been deleted';
|
||||
break;
|
||||
case 'no-recordings':
|
||||
this.errorName = 'No recordings';
|
||||
this.message = 'There are no recordings in this room or the room does not exist';
|
||||
break;
|
||||
case 'unauthorized-recording-access':
|
||||
this.errorName = 'Unauthorized recording access';
|
||||
this.message = 'You are not authorized to access the recordings in this room';
|
||||
break;
|
||||
case 'recordings-admin-only-access':
|
||||
this.errorName = 'Unauthorized recording access';
|
||||
this.message = 'Recordings access is configured for admins only in this room';
|
||||
break;
|
||||
default:
|
||||
this.errorName = 'Internal error';
|
||||
this.message = 'Something went wrong...';
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { UserRole } from '@lib/typings/ce';
|
||||
import { RoomCreatorDisabledComponent, UnauthorizedComponent } from '../components';
|
||||
import {
|
||||
applicationModeGuard,
|
||||
checkParticipantNameGuard,
|
||||
@ -20,11 +19,13 @@ import {
|
||||
ConsoleComponent,
|
||||
ConsoleLoginComponent,
|
||||
DisconnectedComponent,
|
||||
ErrorComponent,
|
||||
LoginComponent,
|
||||
OverviewComponent,
|
||||
ParticipantNameFormComponent,
|
||||
RecordingsComponent,
|
||||
RoomCreatorComponent,
|
||||
RoomCreatorDisabledComponent,
|
||||
RoomFormComponent,
|
||||
RoomRecordingsComponent,
|
||||
RoomsComponent,
|
||||
@ -51,7 +52,7 @@ export const baseRoutes: Routes = [
|
||||
},
|
||||
{ path: 'room-creator-disabled', component: RoomCreatorDisabledComponent },
|
||||
{ path: 'disconnected', component: DisconnectedComponent },
|
||||
{ path: 'unauthorized', component: UnauthorizedComponent },
|
||||
{ path: 'error', component: ErrorComponent },
|
||||
{
|
||||
path: 'console/login',
|
||||
component: ConsoleLoginComponent,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user