backend: update participant handling to make participantName optional and adjust related logic

This commit is contained in:
juancarmore 2025-08-05 17:52:13 +02:00
parent 5637c56f44
commit 6e9c1743a1
12 changed files with 165 additions and 183 deletions

View File

@ -1,18 +1,17 @@
type: object type: object
required: required:
- roomId - roomId
- participantName
- secret - secret
properties: properties:
roomId: roomId:
type: string type: string
description: The unique identifier of the room where the participant will join. description: The unique identifier of the room where the participant will join.
example: 'room-123' example: 'room-123'
participantName:
type: string
description: The name of the participant.
example: 'Alice'
secret: secret:
type: string type: string
description: The secret token from the room Url description: The secret token from the room Url
example: 'abc123456' example: 'abc123456'
participantName:
type: string
description: The name of the participant.
example: 'Alice'

View File

@ -40,9 +40,13 @@ export const generateParticipantToken = async (req: Request, res: Response) => {
try { try {
logger.verbose(`Generating participant token for room '${roomId}'`); logger.verbose(`Generating participant token for room '${roomId}'`);
await roomService.createLivekitRoom(roomId);
const token = await participantService.generateOrRefreshParticipantToken(participantOptions, currentRoles);
// If participantName is provided, create the Livekit room if it doesn't exist
if (participantOptions.participantName) {
await roomService.createLivekitRoom(roomId);
}
const token = await participantService.generateOrRefreshParticipantToken(participantOptions, currentRoles);
res.cookie(INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME, token, getCookieOptions('/')); res.cookie(INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME, token, getCookieOptions('/'));
return res.status(200).json({ token }); return res.status(200).json({ token });
} catch (error) { } catch (error) {

View File

@ -6,8 +6,8 @@ import { nonEmptySanitizedRoomId } from './room-validator.middleware.js';
const ParticipantTokenRequestSchema: z.ZodType<ParticipantOptions> = z.object({ const ParticipantTokenRequestSchema: z.ZodType<ParticipantOptions> = z.object({
roomId: nonEmptySanitizedRoomId('roomId'), roomId: nonEmptySanitizedRoomId('roomId'),
participantName: z.string().nonempty('Participant name is required'), secret: z.string().nonempty('Secret is required'),
secret: z.string().nonempty('Secret is required') participantName: z.string().optional()
}); });
export const validateParticipantTokenRequest = (req: Request, res: Response, next: NextFunction) => { export const validateParticipantTokenRequest = (req: Request, res: Response, next: NextFunction) => {

View File

@ -20,17 +20,19 @@ export class ParticipantService {
): Promise<string> { ): Promise<string> {
const { roomId, participantName, secret } = participantOptions; const { roomId, participantName, secret } = participantOptions;
// Check if participant with same participantName exists in the room if (participantName) {
const participantExists = await this.participantExists(roomId, participantName); // Check if participant with same participantName exists in the room
const participantExists = await this.participantExists(roomId, participantName);
if (!refresh && participantExists) { if (!refresh && participantExists) {
this.logger.verbose(`Participant '${participantName}' already exists in room '${roomId}'`); this.logger.verbose(`Participant '${participantName}' already exists in room '${roomId}'`);
throw errorParticipantAlreadyExists(participantName, roomId); throw errorParticipantAlreadyExists(participantName, roomId);
} }
if (refresh && !participantExists) { if (refresh && !participantExists) {
this.logger.verbose(`Participant '${participantName}' does not exist in room '${roomId}'`); this.logger.verbose(`Participant '${participantName}' does not exist in room '${roomId}'`);
throw errorParticipantNotFound(participantName, roomId); throw errorParticipantNotFound(participantName, roomId);
}
} }
const role = await this.roomService.getRoomRoleBySecret(roomId, secret); const role = await this.roomService.getRoomRoleBySecret(roomId, secret);
@ -44,7 +46,8 @@ export class ParticipantService {
role: ParticipantRole, role: ParticipantRole,
currentRoles: { role: ParticipantRole; permissions: OpenViduMeetPermissions }[] currentRoles: { role: ParticipantRole; permissions: OpenViduMeetPermissions }[]
): Promise<string> { ): Promise<string> {
const permissions = this.getParticipantPermissions(participantOptions.roomId, role); const { roomId, participantName } = participantOptions;
const permissions = this.getParticipantPermissions(roomId, role, !!participantName);
if (!currentRoles.some((r) => r.role === role)) { if (!currentRoles.some((r) => r.role === role)) {
currentRoles.push({ role, permissions: permissions.openvidu }); currentRoles.push({ role, permissions: permissions.openvidu });
@ -75,21 +78,21 @@ export class ParticipantService {
return this.livekitService.deleteParticipant(participantName, roomId); return this.livekitService.deleteParticipant(participantName, roomId);
} }
getParticipantPermissions(roomId: string, role: ParticipantRole): ParticipantPermissions { getParticipantPermissions(roomId: string, role: ParticipantRole, addJoinPermission = true): ParticipantPermissions {
switch (role) { switch (role) {
case ParticipantRole.MODERATOR: case ParticipantRole.MODERATOR:
return this.generateModeratorPermissions(roomId); return this.generateModeratorPermissions(roomId, addJoinPermission);
case ParticipantRole.PUBLISHER: case ParticipantRole.PUBLISHER:
return this.generatePublisherPermissions(roomId); return this.generatePublisherPermissions(roomId, addJoinPermission);
default: default:
throw new Error(`Role ${role} not supported`); throw new Error(`Role ${role} not supported`);
} }
} }
protected generateModeratorPermissions(roomId: string): ParticipantPermissions { protected generateModeratorPermissions(roomId: string, addJoinPermission = true): ParticipantPermissions {
return { return {
livekit: { livekit: {
roomJoin: true, roomJoin: addJoinPermission,
room: roomId, room: roomId,
canPublish: true, canPublish: true,
canSubscribe: true, canSubscribe: true,
@ -104,10 +107,10 @@ export class ParticipantService {
}; };
} }
protected generatePublisherPermissions(roomId: string): ParticipantPermissions { protected generatePublisherPermissions(roomId: string, addJoinPermission = true): ParticipantPermissions {
return { return {
livekit: { livekit: {
roomJoin: true, roomJoin: addJoinPermission,
room: roomId, room: roomId,
canPublish: true, canPublish: true,
canSubscribe: true, canSubscribe: true,

View File

@ -45,7 +45,7 @@ export class TokenService {
roles: { role: ParticipantRole; permissions: OpenViduMeetPermissions }[] roles: { role: ParticipantRole; permissions: OpenViduMeetPermissions }[]
): Promise<string> { ): Promise<string> {
const { roomId, participantName } = participantOptions; const { roomId, participantName } = participantOptions;
this.logger.info(`Generating token for ${participantName} in room ${roomId}`); this.logger.info(`Generating token for room '${roomId}'`);
const tokenOptions: AccessTokenOptions = { const tokenOptions: AccessTokenOptions = {
identity: participantName, identity: participantName,

View File

@ -480,12 +480,12 @@ export const expectValidRoomRoleAndPermissionsResponse = (
}); });
}; };
const getPermissions = (roomId: string, role: ParticipantRole): ParticipantPermissions => { const getPermissions = (roomId: string, role: ParticipantRole, addJoinPermission = true): ParticipantPermissions => {
switch (role) { switch (role) {
case ParticipantRole.MODERATOR: case ParticipantRole.MODERATOR:
return { return {
livekit: { livekit: {
roomJoin: true, roomJoin: addJoinPermission,
room: roomId, room: roomId,
canPublish: true, canPublish: true,
canSubscribe: true, canSubscribe: true,
@ -501,7 +501,7 @@ const getPermissions = (roomId: string, role: ParticipantRole): ParticipantPermi
case ParticipantRole.PUBLISHER: case ParticipantRole.PUBLISHER:
return { return {
livekit: { livekit: {
roomJoin: true, roomJoin: addJoinPermission,
room: roomId, room: roomId,
canPublish: true, canPublish: true,
canSubscribe: true, canSubscribe: true,
@ -522,8 +522,8 @@ const getPermissions = (roomId: string, role: ParticipantRole): ParticipantPermi
export const expectValidParticipantTokenResponse = ( export const expectValidParticipantTokenResponse = (
response: any, response: any,
roomId: string, roomId: string,
participantName: string,
participantRole: ParticipantRole, participantRole: ParticipantRole,
participantName?: string,
otherRoles: ParticipantRole[] = [] otherRoles: ParticipantRole[] = []
) => { ) => {
expect(response.status).toBe(200); expect(response.status).toBe(200);
@ -532,10 +532,10 @@ export const expectValidParticipantTokenResponse = (
const token = response.body.token; const token = response.body.token;
const decodedToken = decodeJWTToken(token); const decodedToken = decodeJWTToken(token);
const permissions = getPermissions(roomId, participantRole); const permissions = getPermissions(roomId, participantRole, !!participantName);
const rolesAndPermissions = otherRoles.map((role) => ({ const rolesAndPermissions = otherRoles.map((role) => ({
role, role,
permissions: getPermissions(roomId, role).openvidu permissions: getPermissions(roomId, role, !!participantName).openvidu
})); }));
if (!rolesAndPermissions.some((r) => r.role === participantRole)) { if (!rolesAndPermissions.some((r) => r.role === participantRole)) {
@ -545,7 +545,12 @@ export const expectValidParticipantTokenResponse = (
}); });
} }
expect(decodedToken).toHaveProperty('sub', participantName); if (participantName) {
expect(decodedToken).toHaveProperty('sub', participantName);
} else {
expect(decodedToken).not.toHaveProperty('sub');
}
expect(decodedToken).toHaveProperty('video', permissions.livekit); expect(decodedToken).toHaveProperty('video', permissions.livekit);
expect(decodedToken).toHaveProperty('metadata'); expect(decodedToken).toHaveProperty('metadata');
const metadata = JSON.parse(decodedToken.metadata || '{}'); const metadata = JSON.parse(decodedToken.metadata || '{}');

View File

@ -227,13 +227,18 @@ export const getRooms = async (query: Record<string, any> = {}) => {
* @returns A Promise that resolves to the room data * @returns A Promise that resolves to the room data
* @throws Error if the app instance is not defined * @throws Error if the app instance is not defined
*/ */
export const getRoom = async (roomId: string, fields?: string) => { export const getRoom = async (roomId: string, fields?: string, cookie?: string, role?: ParticipantRole) => {
checkAppIsRunning(); checkAppIsRunning();
return await request(app) const req = request(app).get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}`).query({ fields });
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_API_KEY) if (cookie && role) {
.query({ fields }); req.set('Cookie', cookie).set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, role);
} else {
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_API_KEY);
}
return await req;
}; };
export const getRoomPreferences = async (roomId: string, cookie: string, role: ParticipantRole) => { export const getRoomPreferences = async (roomId: string, cookie: string, role: ParticipantRole) => {
@ -380,16 +385,16 @@ export const generateParticipantToken = async (participantOptions: any, cookie?:
*/ */
export const generateParticipantTokenCookie = async ( export const generateParticipantTokenCookie = async (
roomId: string, roomId: string,
participantName: string,
secret: string, secret: string,
participantName: string,
cookie?: string cookie?: string
): Promise<string> => { ): Promise<string> => {
// Generate the participant token // Generate the participant token
const response = await generateParticipantToken( const response = await generateParticipantToken(
{ {
roomId, roomId,
participantName, secret,
secret participantName
}, },
cookie cookie
); );

View File

@ -51,8 +51,8 @@ export const setupSingleRoom = async (
// Extract the room secrets and generate participant tokens, saved as cookies // Extract the room secrets and generate participant tokens, saved as cookies
const { moderatorSecret, publisherSecret } = MeetRoomHelper.extractSecretsFromRoom(room); const { moderatorSecret, publisherSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
const [moderatorCookie, publisherCookie] = await Promise.all([ const [moderatorCookie, publisherCookie] = await Promise.all([
generateParticipantTokenCookie(room.roomId, 'MODERATOR', moderatorSecret), generateParticipantTokenCookie(room.roomId, moderatorSecret, 'MODERATOR'),
generateParticipantTokenCookie(room.roomId, 'PUBLISHER', publisherSecret) generateParticipantTokenCookie(room.roomId, publisherSecret, 'PUBLISHER')
]); ]);
// Join participant if needed // Join participant if needed

View File

@ -26,31 +26,39 @@ describe('Participant API Tests', () => {
}); });
describe('Generate Participant Token Tests', () => { describe('Generate Participant Token Tests', () => {
it('should generate a participant token without join permissions when not specifying participant name', async () => {
const response = await generateParticipantToken({
roomId: roomData.room.roomId,
secret: roomData.moderatorSecret
});
expectValidParticipantTokenResponse(response, roomData.room.roomId, ParticipantRole.MODERATOR);
});
it('should generate a participant token with moderator permissions when using the moderator secret', async () => { it('should generate a participant token with moderator permissions when using the moderator secret', async () => {
const response = await generateParticipantToken({ const response = await generateParticipantToken({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}); });
expectValidParticipantTokenResponse( expectValidParticipantTokenResponse(
response, response,
roomData.room.roomId, roomData.room.roomId,
participantName, ParticipantRole.MODERATOR,
ParticipantRole.MODERATOR participantName
); );
}); });
it('should generate a participant token with publisher permissions when using the publisher secret', async () => { it('should generate a participant token with publisher permissions when using the publisher secret', async () => {
const response = await generateParticipantToken({ const response = await generateParticipantToken({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName
}); });
expectValidParticipantTokenResponse( expectValidParticipantTokenResponse(
response, response,
roomData.room.roomId, roomData.room.roomId,
participantName, ParticipantRole.PUBLISHER,
ParticipantRole.PUBLISHER participantName
); );
}); });
@ -58,22 +66,22 @@ describe('Participant API Tests', () => {
when using the publisher secret after having a moderator token`, async () => { when using the publisher secret after having a moderator token`, async () => {
const moderatorCookie = await generateParticipantTokenCookie( const moderatorCookie = await generateParticipantTokenCookie(
roomData.room.roomId, roomData.room.roomId,
`${participantName}_MODERATOR`, roomData.moderatorSecret,
roomData.moderatorSecret `${participantName}_MODERATOR`
); );
const publisherResponse = await generateParticipantToken( const publisherResponse = await generateParticipantToken(
{ {
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: `${participantName}_PUBLISHER`, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: `${participantName}_PUBLISHER`
}, },
moderatorCookie moderatorCookie
); );
expectValidParticipantTokenResponse( expectValidParticipantTokenResponse(
publisherResponse, publisherResponse,
roomData.room.roomId, roomData.room.roomId,
`${participantName}_PUBLISHER`,
ParticipantRole.PUBLISHER, ParticipantRole.PUBLISHER,
`${participantName}_PUBLISHER`,
[ParticipantRole.MODERATOR] [ParticipantRole.MODERATOR]
); );
}); });
@ -82,8 +90,8 @@ describe('Participant API Tests', () => {
roomData = await setupSingleRoom(true); roomData = await setupSingleRoom(true);
const response = await generateParticipantToken({ const response = await generateParticipantToken({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}); });
expect(response.status).toBe(409); expect(response.status).toBe(409);
@ -94,8 +102,8 @@ describe('Participant API Tests', () => {
it('should fail with 404 when room does not exist', async () => { it('should fail with 404 when room does not exist', async () => {
const response = await generateParticipantToken({ const response = await generateParticipantToken({
roomId: 'non_existent_room', roomId: 'non_existent_room',
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}); });
expect(response.status).toBe(404); expect(response.status).toBe(404);
}); });
@ -103,8 +111,8 @@ describe('Participant API Tests', () => {
it('should fail with 400 when secret is invalid', async () => { it('should fail with 400 when secret is invalid', async () => {
const response = await generateParticipantToken({ const response = await generateParticipantToken({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: 'invalid_secret',
secret: 'invalid_secret' participantName
}); });
expect(response.status).toBe(400); expect(response.status).toBe(400);
}); });
@ -113,20 +121,12 @@ describe('Participant API Tests', () => {
describe('Generate Participant Token Validation Tests', () => { describe('Generate Participant Token Validation Tests', () => {
it('should fail when roomId is not provided', async () => { it('should fail when roomId is not provided', async () => {
const response = await generateParticipantToken({ const response = await generateParticipantToken({
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}); });
expectValidationError(response, 'roomId', 'Required'); expectValidationError(response, 'roomId', 'Required');
}); });
it('should fail when participantName is not provided', async () => {
const response = await generateParticipantToken({
roomId: roomData.room.roomId,
secret: roomData.moderatorSecret
});
expectValidationError(response, 'participantName', 'Required');
});
it('should fail when secret is not provided', async () => { it('should fail when secret is not provided', async () => {
const response = await generateParticipantToken({ const response = await generateParticipantToken({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
@ -135,20 +135,11 @@ describe('Participant API Tests', () => {
expectValidationError(response, 'secret', 'Required'); expectValidationError(response, 'secret', 'Required');
}); });
it('should fail when participantName is empty', async () => {
const response = await generateParticipantToken({
roomId: roomData.room.roomId,
participantName: '',
secret: roomData.moderatorSecret
});
expectValidationError(response, 'participantName', 'Participant name is required');
});
it('should fail when secret is empty', async () => { it('should fail when secret is empty', async () => {
const response = await generateParticipantToken({ const response = await generateParticipantToken({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: '',
secret: '' participantName
}); });
expectValidationError(response, 'secret', 'Secret is required'); expectValidationError(response, 'secret', 'Secret is required');
}); });

View File

@ -40,16 +40,16 @@ describe('Participant API Tests', () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}, },
roomData.moderatorCookie roomData.moderatorCookie
); );
expectValidParticipantTokenResponse( expectValidParticipantTokenResponse(
response, response,
roomData.room.roomId, roomData.room.roomId,
participantName, ParticipantRole.MODERATOR,
ParticipantRole.MODERATOR participantName
); );
}); });
@ -57,16 +57,16 @@ describe('Participant API Tests', () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName
}, },
roomData.publisherCookie roomData.publisherCookie
); );
expectValidParticipantTokenResponse( expectValidParticipantTokenResponse(
response, response,
roomData.room.roomId, roomData.room.roomId,
participantName, ParticipantRole.PUBLISHER,
ParticipantRole.PUBLISHER participantName
); );
}); });
@ -74,8 +74,8 @@ describe('Participant API Tests', () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: 'invalid_secret',
secret: 'invalid_secret' participantName
}, },
roomData.moderatorCookie roomData.moderatorCookie
); );
@ -86,8 +86,8 @@ describe('Participant API Tests', () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}, },
'' ''
); );
@ -100,8 +100,8 @@ describe('Participant API Tests', () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: newRoomData.room.roomId, roomId: newRoomData.room.roomId,
participantName, secret: newRoomData.moderatorSecret,
secret: newRoomData.moderatorSecret participantName
}, },
roomData.moderatorCookie roomData.moderatorCookie
); );
@ -112,8 +112,8 @@ describe('Participant API Tests', () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: 'non_existent_room', roomId: 'non_existent_room',
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}, },
roomData.moderatorCookie roomData.moderatorCookie
); );
@ -125,8 +125,8 @@ describe('Participant API Tests', () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: newRoomData.room.roomId, roomId: newRoomData.room.roomId,
participantName, secret: newRoomData.moderatorSecret,
secret: newRoomData.moderatorSecret participantName
}, },
newRoomData.moderatorCookie newRoomData.moderatorCookie
); );
@ -139,25 +139,14 @@ describe('Participant API Tests', () => {
it('should fail when roomId is not provided', async () => { it('should fail when roomId is not provided', async () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
participantName, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName
}, },
roomData.moderatorCookie roomData.moderatorCookie
); );
expectValidationError(response, 'roomId', 'Required'); expectValidationError(response, 'roomId', 'Required');
}); });
it('should fail when participantName is not provided', async () => {
const response = await refreshParticipantToken(
{
roomId: roomData.room.roomId,
secret: roomData.moderatorSecret
},
roomData.moderatorCookie
);
expectValidationError(response, 'participantName', 'Required');
});
it('should fail when secret is not provided', async () => { it('should fail when secret is not provided', async () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
@ -169,24 +158,12 @@ describe('Participant API Tests', () => {
expectValidationError(response, 'secret', 'Required'); expectValidationError(response, 'secret', 'Required');
}); });
it('should fail when participantName is empty', async () => {
const response = await refreshParticipantToken(
{
roomId: roomData.room.roomId,
participantName: '',
secret: roomData.moderatorSecret
},
roomData.moderatorCookie
);
expectValidationError(response, 'participantName', 'Participant name is required');
});
it('should fail when secret is empty', async () => { it('should fail when secret is empty', async () => {
const response = await refreshParticipantToken( const response = await refreshParticipantToken(
{ {
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName, secret: '',
secret: '' participantName
}, },
roomData.moderatorCookie roomData.moderatorCookie
); );

View File

@ -43,8 +43,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -54,8 +54,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -65,8 +65,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -76,8 +76,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -87,8 +87,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(401); expect(response.status).toBe(401);
}); });
@ -98,8 +98,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -109,8 +109,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(401); expect(response.status).toBe(401);
}); });
@ -120,8 +120,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -131,8 +131,8 @@ describe('Participant API Security Tests', () => {
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({ const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(401); expect(response.status).toBe(401);
}); });
@ -161,8 +161,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', roomData.publisherCookie) .set('Cookie', roomData.publisherCookie)
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -175,8 +175,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', roomData.moderatorCookie) .set('Cookie', roomData.moderatorCookie)
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -189,8 +189,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', roomData.publisherCookie) .set('Cookie', roomData.publisherCookie)
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -203,8 +203,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', [adminCookie, roomData.moderatorCookie]) .set('Cookie', [adminCookie, roomData.moderatorCookie])
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -217,8 +217,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', roomData.moderatorCookie) .set('Cookie', roomData.moderatorCookie)
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(401); expect(response.status).toBe(401);
}); });
@ -231,8 +231,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', [adminCookie, roomData.publisherCookie]) .set('Cookie', [adminCookie, roomData.publisherCookie])
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -245,8 +245,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', roomData.publisherCookie) .set('Cookie', roomData.publisherCookie)
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.publisherSecret,
secret: roomData.publisherSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(401); expect(response.status).toBe(401);
}); });
@ -259,8 +259,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', [adminCookie, roomData.moderatorCookie]) .set('Cookie', [adminCookie, roomData.moderatorCookie])
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
}); });
@ -273,8 +273,8 @@ describe('Participant API Security Tests', () => {
.set('Cookie', roomData.moderatorCookie) .set('Cookie', roomData.moderatorCookie)
.send({ .send({
roomId: roomData.room.roomId, roomId: roomData.room.roomId,
participantName: PARTICIPANT_NAME, secret: roomData.moderatorSecret,
secret: roomData.moderatorSecret participantName: PARTICIPANT_NAME
}); });
expect(response.status).toBe(401); expect(response.status).toBe(401);
}); });

View File

@ -5,34 +5,32 @@ import { OpenViduMeetPermissions } from './permissions/openvidu-permissions.js';
* Options for a participant to join a room. * Options for a participant to join a room.
*/ */
export interface ParticipantOptions { export interface ParticipantOptions {
/** /**
* The unique identifier for the room. * The unique identifier for the room.
*/ */
roomId: string; roomId: string;
/**
/** * A secret key for room access.
* The name of the participant. */
*/ secret: string;
participantName: string; /**
* The name of the participant.
/** */
* A secret key for room access. participantName?: string;
*/
secret: string;
} }
/** /**
* Represents the permissions for an individual participant. * Represents the permissions for an individual participant.
*/ */
export interface ParticipantPermissions { export interface ParticipantPermissions {
livekit: LiveKitPermissions; livekit: LiveKitPermissions;
openvidu: OpenViduMeetPermissions; openvidu: OpenViduMeetPermissions;
} }
/** /**
* Represents the role of a participant in a room. * Represents the role of a participant in a room.
*/ */
export const enum ParticipantRole { export const enum ParticipantRole {
MODERATOR = 'moderator', MODERATOR = 'moderator',
PUBLISHER = 'publisher', PUBLISHER = 'publisher'
} }