frontend: refactor code to always remove room secret from URL instead of switching moderator secret with publisher secret
This commit is contained in:
parent
51a379af33
commit
ed6af7a7ff
@ -8,13 +8,16 @@ export const extractRoomQueryParamsGuard: CanActivateFn = (route: ActivatedRoute
|
||||
const navigationService = inject(NavigationService);
|
||||
const roomService = inject(RoomService);
|
||||
const participantService = inject(ParticipantTokenService);
|
||||
const sessionStorageService = inject(SessionStorageService);
|
||||
|
||||
const { roomId, participantName, secret, leaveRedirectUrl, showOnlyRecordings } = extractParams(route);
|
||||
const storedSecret = sessionStorageService.getRoomSecret(roomId);
|
||||
|
||||
if (isValidUrl(leaveRedirectUrl)) {
|
||||
navigationService.setLeaveRedirectUrl(leaveRedirectUrl);
|
||||
}
|
||||
|
||||
if (!secret) {
|
||||
if (!secret && !storedSecret) {
|
||||
// If no secret is provided, redirect to the error page
|
||||
return navigationService.redirectToErrorPage(ErrorReason.MISSING_ROOM_SECRET);
|
||||
}
|
||||
@ -40,7 +43,7 @@ export const extractRecordingQueryParamsGuard: CanActivateFn = (route: Activated
|
||||
const sessionStorageService = inject(SessionStorageService);
|
||||
|
||||
const { roomId, secret } = extractParams(route);
|
||||
const storedSecret = sessionStorageService.getModeratorSecret(roomId);
|
||||
const storedSecret = sessionStorageService.getRoomSecret(roomId);
|
||||
|
||||
if (!secret && !storedSecret) {
|
||||
// If no secret is provided, redirect to the error page
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export * from './auth.guard';
|
||||
export * from './extract-query-params.guard';
|
||||
export * from './moderator-secret.guard';
|
||||
export * from './remove-secret.guard';
|
||||
export * from './run-serially.guard';
|
||||
export * from './validate-recording-access.guard';
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { CanActivateFn, NavigationEnd, Router } from '@angular/router';
|
||||
import { NavigationService, ParticipantTokenService, RoomService, SessionStorageService } from '@lib/services';
|
||||
import { filter, take } from 'rxjs';
|
||||
|
||||
/**
|
||||
* Guard that intercepts navigation to remove the 'secret' query parameter from the URL
|
||||
* when a moderator participant is detected. The secret is stored in session storage
|
||||
* for the current room, and the URL is updated without the 'secret' parameter to
|
||||
* enhance security.
|
||||
*/
|
||||
export const removeModeratorSecretGuard: CanActivateFn = (route, _state) => {
|
||||
const roomService = inject(RoomService);
|
||||
const participantService = inject(ParticipantTokenService);
|
||||
const navigationService = inject(NavigationService);
|
||||
const router = inject(Router);
|
||||
const sessionStorageService = inject(SessionStorageService);
|
||||
|
||||
router.events
|
||||
.pipe(
|
||||
filter((event) => event instanceof NavigationEnd),
|
||||
take(1)
|
||||
)
|
||||
.subscribe(async () => {
|
||||
if (participantService.isModeratorParticipant()) {
|
||||
const roomId = roomService.getRoomId();
|
||||
const moderatorSecret = roomService.getRoomSecret();
|
||||
|
||||
// Store the moderator secret in session storage for the current room and remove it from the URL
|
||||
sessionStorageService.setModeratorSecret(roomId, moderatorSecret);
|
||||
navigationService.removeQueryParamFromUrl(route.queryParams, 'secret');
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { CanActivateFn, NavigationEnd, Router } from '@angular/router';
|
||||
import { NavigationService, RoomService, SessionStorageService } from '@lib/services';
|
||||
import { filter, take } from 'rxjs';
|
||||
|
||||
/**
|
||||
* Guard that intercepts navigation to remove the 'secret' query parameter from the URL
|
||||
* when a participant joins a room. The secret is stored in session storage for the current room,
|
||||
* and the URL is updated without the 'secret' parameter to enhance security.
|
||||
*/
|
||||
export const removeRoomSecretGuard: CanActivateFn = (route, _state) => {
|
||||
const router = inject(Router);
|
||||
const roomService = inject(RoomService);
|
||||
const navigationService = inject(NavigationService);
|
||||
const sessionStorageService = inject(SessionStorageService);
|
||||
|
||||
router.events
|
||||
.pipe(
|
||||
filter((event) => event instanceof NavigationEnd),
|
||||
take(1)
|
||||
)
|
||||
.subscribe(async () => {
|
||||
const roomId = roomService.getRoomId();
|
||||
const secret = roomService.getRoomSecret();
|
||||
|
||||
// Store the secret in session storage for the current room and remove it from the URL
|
||||
sessionStorageService.setRoomSecret(roomId, secret);
|
||||
await navigationService.removeQueryParamFromUrl(route.queryParams, 'secret');
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -229,7 +229,7 @@ export class VideoRoomComponent implements OnInit {
|
||||
|
||||
try {
|
||||
await this.generateParticipantToken();
|
||||
await this.replaceUrlQueryParams();
|
||||
await this.addParticipantNameToUrl();
|
||||
await this.roomService.loadPreferences(this.roomId);
|
||||
this.showRoom = true;
|
||||
} catch (error) {
|
||||
@ -277,24 +277,11 @@ export class VideoRoomComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private async replaceUrlQueryParams() {
|
||||
let secretQueryParam = this.roomSecret;
|
||||
|
||||
// If participant is moderator, store the moderator secret in session storage
|
||||
// and replace the secret in the URL with the publisher secret
|
||||
if (this.participantRole === ParticipantRole.MODERATOR) {
|
||||
try {
|
||||
const { moderatorSecret, publisherSecret } = await this.roomService.getSecrets(this.roomId);
|
||||
this.sessionStorageService.setModeratorSecret(this.roomId, moderatorSecret);
|
||||
secretQueryParam = publisherSecret;
|
||||
} catch (error) {
|
||||
console.error('error', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace secret and participant name in the URL query parameters
|
||||
this.navigationService.updateQueryParamsFromUrl(this.route.snapshot.queryParams, {
|
||||
secret: secretQueryParam,
|
||||
/**
|
||||
* Add participant name as a query parameter to the URL
|
||||
*/
|
||||
private async addParticipantNameToUrl() {
|
||||
await this.navigationService.updateQueryParamsFromUrl(this.route.snapshot.queryParams, {
|
||||
'participant-name': this.participantName
|
||||
});
|
||||
}
|
||||
@ -302,7 +289,7 @@ export class VideoRoomComponent implements OnInit {
|
||||
onRoomCreated(room: Room) {
|
||||
room.on(
|
||||
RoomEvent.DataReceived,
|
||||
(payload: Uint8Array, participant?: RemoteParticipant, _?: DataPacket_Kind, topic?: string) => {
|
||||
(payload: Uint8Array, _participant?: RemoteParticipant, _kind?: DataPacket_Kind, topic?: string) => {
|
||||
const event = JSON.parse(new TextDecoder().decode(payload));
|
||||
if (topic === MeetSignalType.MEET_ROOM_PREFERENCES_UPDATED) {
|
||||
const roomPreferences: MeetRoomPreferences = event.preferences;
|
||||
@ -342,7 +329,7 @@ export class VideoRoomComponent implements OnInit {
|
||||
|
||||
// Remove the moderator secret from session storage if the participant left for a reason other than browser unload
|
||||
if (event.reason !== ParticipantLeftReason.BROWSER_UNLOAD) {
|
||||
this.sessionStorageService.removeModeratorSecret(event.roomName);
|
||||
this.sessionStorageService.removeRoomSecret(event.roomName);
|
||||
}
|
||||
|
||||
// Navigate to the disconnected page with the reason
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
checkUserNotAuthenticatedGuard,
|
||||
extractRecordingQueryParamsGuard,
|
||||
extractRoomQueryParamsGuard,
|
||||
removeModeratorSecretGuard,
|
||||
removeRoomSecretGuard,
|
||||
runGuardsSerially,
|
||||
validateRecordingAccessGuard
|
||||
} from '@lib/guards';
|
||||
@ -35,7 +35,9 @@ export const baseRoutes: Routes = [
|
||||
{
|
||||
path: 'room/:room-id',
|
||||
component: VideoRoomComponent,
|
||||
canActivate: [runGuardsSerially(extractRoomQueryParamsGuard, checkParticipantRoleAndAuthGuard)]
|
||||
canActivate: [
|
||||
runGuardsSerially(extractRoomQueryParamsGuard, checkParticipantRoleAndAuthGuard, removeRoomSecretGuard)
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'room/:room-id/recordings',
|
||||
@ -45,7 +47,7 @@ export const baseRoutes: Routes = [
|
||||
extractRecordingQueryParamsGuard,
|
||||
checkParticipantRoleAndAuthGuard,
|
||||
validateRecordingAccessGuard,
|
||||
removeModeratorSecretGuard
|
||||
removeRoomSecretGuard
|
||||
)
|
||||
]
|
||||
},
|
||||
|
||||
@ -148,17 +148,17 @@ export class NavigationService {
|
||||
* @param oldParams - The existing query parameters
|
||||
* @param newParams - The new query parameters to merge with the existing ones
|
||||
*/
|
||||
updateQueryParamsFromUrl(oldParams: Params, newParams: Params): void {
|
||||
async updateQueryParamsFromUrl(oldParams: Params, newParams: Params): Promise<void> {
|
||||
const queryParams = {
|
||||
...oldParams,
|
||||
...newParams
|
||||
};
|
||||
const urlTree = this.router.createUrlTree([], {
|
||||
|
||||
await this.router.navigate([], {
|
||||
queryParams,
|
||||
replaceUrl: true,
|
||||
queryParamsHandling: 'merge'
|
||||
});
|
||||
const newUrl = this.router.serializeUrl(urlTree);
|
||||
this.location.replaceState(newUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,11 +167,14 @@ export class NavigationService {
|
||||
* @param queryParams - The current query parameters
|
||||
* @param param - The parameter to remove
|
||||
*/
|
||||
removeQueryParamFromUrl(queryParams: Params, param: string): void {
|
||||
async removeQueryParamFromUrl(queryParams: Params, param: string): Promise<void> {
|
||||
const updatedParams = { ...queryParams };
|
||||
delete updatedParams[param];
|
||||
const urlTree = this.router.createUrlTree([], { queryParams: updatedParams });
|
||||
const newUrl = this.router.serializeUrl(urlTree);
|
||||
this.location.replaceState(newUrl);
|
||||
|
||||
await this.router.navigate([], {
|
||||
queryParams: updatedParams,
|
||||
replaceUrl: true,
|
||||
queryParamsHandling: 'replace'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,10 +46,14 @@ export class RoomService {
|
||||
return this.roomId;
|
||||
}
|
||||
|
||||
setRoomSecret(secret: string) {
|
||||
// If a secret is stored in session storage for the current room, use it instead of the provided secret
|
||||
const storedSecret = this.sessionStorageService.getModeratorSecret(this.roomId);
|
||||
this.roomSecret = storedSecret || secret;
|
||||
setRoomSecret(secret?: string) {
|
||||
// If no secret is provided, check session storage for the current room's secret
|
||||
if (!secret) {
|
||||
const storedSecret = this.sessionStorageService.getRoomSecret(this.roomId);
|
||||
this.roomSecret = storedSecret || '';
|
||||
} else {
|
||||
this.roomSecret = secret;
|
||||
}
|
||||
}
|
||||
|
||||
getRoomSecret(): string {
|
||||
|
||||
@ -11,32 +11,32 @@ export class SessionStorageService {
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Stores a moderator secret for a specific room.
|
||||
* Stores a secret associated with a participant role for a specific room.
|
||||
*
|
||||
* @param roomId The room ID.
|
||||
* @param secret The secret string.
|
||||
* @param secret The secret to store.
|
||||
*/
|
||||
public setModeratorSecret(roomId: string, secret: string): void {
|
||||
this.set(`moderator_secret_${roomId}`, secret);
|
||||
public setRoomSecret(roomId: string, secret: string): void {
|
||||
this.set(`room_secret_${roomId}`, secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the moderator secret for a specific room.
|
||||
* Retrieves the room secret for a specific room.
|
||||
*
|
||||
* @param roomId The room ID.
|
||||
* @returns The stored secret or null if not found.
|
||||
*/
|
||||
public getModeratorSecret(roomId: string): string | null {
|
||||
return this.get<string>(`moderator_secret_${roomId}`) ?? null;
|
||||
public getRoomSecret(roomId: string): string | null {
|
||||
return this.get<string>(`room_secret_${roomId}`) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the moderator secret for a specific room.
|
||||
* Removes the room secret for a specific room.
|
||||
*
|
||||
* @param roomId The room ID.
|
||||
*/
|
||||
public removeModeratorSecret(roomId: string): void {
|
||||
this.remove(`moderator_secret_${roomId}`);
|
||||
public removeRoomSecret(roomId: string): void {
|
||||
this.remove(`room_secret_${roomId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user