backend: update participant handling to make participantName optional and adjust related logic
This commit is contained in:
parent
5637c56f44
commit
6e9c1743a1
@ -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'
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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) => {
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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 || '{}');
|
||||||
|
|||||||
@ -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
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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');
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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'
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user