test: refactor authentication in integration tests to use header-based access tokens; add coverage for cookie-based mode
This commit is contained in:
parent
c93306b705
commit
479e94add8
@ -598,19 +598,6 @@ export const expectValidParticipantTokenResponse = (
|
||||
expect(metadata).toHaveProperty('roles');
|
||||
expect(metadata.roles).toEqual(expect.arrayContaining(rolesAndPermissions));
|
||||
expect(metadata).toHaveProperty('selectedRole', participantRole);
|
||||
|
||||
// Check that the token is included in a cookie
|
||||
expect(response.headers['set-cookie']).toBeDefined();
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const participantTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
expect(participantTokenCookie).toBeDefined();
|
||||
expect(participantTokenCookie).toContain(token);
|
||||
expect(participantTokenCookie).toContain('HttpOnly');
|
||||
expect(participantTokenCookie).toContain('SameSite=None');
|
||||
expect(participantTokenCookie).toContain('Secure');
|
||||
expect(participantTokenCookie).toContain('Path=/');
|
||||
};
|
||||
|
||||
export const expectValidRecordingTokenResponse = (
|
||||
@ -636,19 +623,6 @@ export const expectValidRecordingTokenResponse = (
|
||||
canRetrieveRecordings,
|
||||
canDeleteRecordings
|
||||
});
|
||||
|
||||
// Check that the token is included in a cookie
|
||||
expect(response.headers['set-cookie']).toBeDefined();
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const recordingTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.RECORDING_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
expect(recordingTokenCookie).toBeDefined();
|
||||
expect(recordingTokenCookie).toContain(token);
|
||||
expect(recordingTokenCookie).toContain('HttpOnly');
|
||||
expect(recordingTokenCookie).toContain('SameSite=None');
|
||||
expect(recordingTokenCookie).toContain('Secure');
|
||||
expect(recordingTokenCookie).toContain('Path=/');
|
||||
};
|
||||
|
||||
const decodeJWTToken = (token: string) => {
|
||||
|
||||
@ -18,7 +18,6 @@ import { RecordingService, RoomService } from '../../src/services/index.js';
|
||||
import {
|
||||
AuthMode,
|
||||
AuthTransportMode,
|
||||
AuthType,
|
||||
MeetRecordingAccess,
|
||||
MeetRecordingInfo,
|
||||
MeetRecordingStatus,
|
||||
@ -57,10 +56,10 @@ export const startTestServer = (): Express => {
|
||||
export const generateApiKey = async (): Promise<string> => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const adminCookie = await loginUser();
|
||||
const accessToken = await loginUser();
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/auth/api-keys`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send();
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.body).toHaveProperty('key');
|
||||
@ -70,10 +69,10 @@ export const generateApiKey = async (): Promise<string> => {
|
||||
export const getApiKeys = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const adminCookie = await loginUser();
|
||||
const accessToken = await loginUser();
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/auth/api-keys`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send();
|
||||
return response;
|
||||
};
|
||||
@ -90,10 +89,10 @@ export const getRoomsAppearanceConfig = async () => {
|
||||
export const updateRoomsAppearanceConfig = async (config: any) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const adminCookie = await loginUser();
|
||||
const accessToken = await loginUser();
|
||||
const response = await request(app)
|
||||
.put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/rooms/appearance`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send(config);
|
||||
return response;
|
||||
};
|
||||
@ -101,10 +100,10 @@ export const updateRoomsAppearanceConfig = async (config: any) => {
|
||||
export const getWebbhookConfig = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const adminCookie = await loginUser();
|
||||
const accessToken = await loginUser();
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/webhooks`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send();
|
||||
return response;
|
||||
};
|
||||
@ -112,10 +111,10 @@ export const getWebbhookConfig = async () => {
|
||||
export const updateWebbhookConfig = async (config: WebhookConfig) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const adminCookie = await loginUser();
|
||||
const accessToken = await loginUser();
|
||||
const response = await request(app)
|
||||
.put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/webhooks`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send(config);
|
||||
|
||||
return response;
|
||||
@ -133,40 +132,51 @@ export const testWebhookUrl = async (url: string) => {
|
||||
export const getSecurityConfig = async () => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const adminCookie = await loginUser();
|
||||
const response = await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/security`)
|
||||
.set('Cookie', adminCookie)
|
||||
.send();
|
||||
const response = await request(app).get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/security`).send();
|
||||
return response;
|
||||
};
|
||||
|
||||
export const updateSecurityConfig = async (config: any) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const adminCookie = await loginUser();
|
||||
const accessToken = await loginUser();
|
||||
const response = await request(app)
|
||||
.put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config/security`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send(config);
|
||||
return response;
|
||||
};
|
||||
|
||||
export const changeSecurityConfig = async (authMode: AuthMode) => {
|
||||
const response = await updateSecurityConfig({
|
||||
authentication: {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authTransportMode: AuthTransportMode.COOKIE,
|
||||
authModeToAccessRoom: authMode
|
||||
}
|
||||
});
|
||||
// Get current config to avoid overwriting other properties
|
||||
let response = await getSecurityConfig();
|
||||
expect(response.status).toBe(200);
|
||||
const currentConfig = response.body;
|
||||
|
||||
currentConfig.authentication.authModeToAccessRoom = authMode;
|
||||
response = await updateSecurityConfig(currentConfig);
|
||||
expect(response.status).toBe(200);
|
||||
};
|
||||
|
||||
export const changeAuthTransportMode = async (authTransportMode: AuthTransportMode) => {
|
||||
// Get current config to avoid overwriting other properties
|
||||
let response = await getSecurityConfig();
|
||||
expect(response.status).toBe(200);
|
||||
const currentConfig = response.body;
|
||||
|
||||
currentConfig.authentication.authTransportMode = authTransportMode;
|
||||
response = await updateSecurityConfig(currentConfig);
|
||||
expect(response.status).toBe(200);
|
||||
};
|
||||
|
||||
const getAuthTransportMode = async (): Promise<AuthTransportMode> => {
|
||||
const response = await getSecurityConfig();
|
||||
return response.body.authentication.authTransportMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Logs in a user and returns the access token cookie
|
||||
* Logs in a user and returns the access token in the format
|
||||
* "Bearer <token>" or the cookie string if in cookie mode
|
||||
*/
|
||||
export const loginUser = async (): Promise<string> => {
|
||||
checkAppIsRunning();
|
||||
@ -176,28 +186,56 @@ export const loginUser = async (): Promise<string> => {
|
||||
.send(CREDENTIALS.admin)
|
||||
.expect(200);
|
||||
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const accessTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
return accessTokenCookie;
|
||||
const authTransportMode = await getAuthTransportMode();
|
||||
|
||||
// Return token in header or cookie based on transport mode
|
||||
if (authTransportMode === AuthTransportMode.COOKIE) {
|
||||
const cookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
|
||||
return cookie!;
|
||||
}
|
||||
|
||||
expect(response.body).toHaveProperty('accessToken');
|
||||
return `Bearer ${response.body.accessToken}`;
|
||||
};
|
||||
|
||||
export const getProfile = async (cookie: string) => {
|
||||
/**
|
||||
* Extracts cookie from response headers
|
||||
*
|
||||
* @param response - The supertest response
|
||||
* @param cookieName - Name of the cookie to extract
|
||||
* @returns The cookie string
|
||||
*/
|
||||
export const extractCookieFromHeaders = (response: Response, cookieName: string): string | undefined => {
|
||||
expect(response.headers['set-cookie']).toBeDefined();
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
return cookies?.find((cookie) => cookie.startsWith(`${cookieName}=`));
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects the appropriate HTTP header name based on the format of the provided access token.
|
||||
*
|
||||
* If the access token starts with 'Bearer ', the specified header name is returned (typically 'Authorization').
|
||||
* Otherwise, 'Cookie' is returned, indicating that the token should be sent as a cookie.
|
||||
*/
|
||||
const selectHeaderBasedOnToken = (headerName: string, accessToken: string): string => {
|
||||
return accessToken.startsWith('Bearer ') ? headerName : 'Cookie';
|
||||
};
|
||||
|
||||
export const getProfile = async (accessToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
return await request(app)
|
||||
.get(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/users/profile`)
|
||||
.set('Cookie', cookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send();
|
||||
};
|
||||
|
||||
export const changePassword = async (currentPassword: string, newPassword: string, cookie: string) => {
|
||||
export const changePassword = async (currentPassword: string, newPassword: string, accessToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
return await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/users/change-password`)
|
||||
.set('Cookie', cookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, accessToken), accessToken)
|
||||
.send({ currentPassword, newPassword });
|
||||
};
|
||||
|
||||
@ -229,13 +267,16 @@ export const getRooms = async (query: Record<string, any> = {}) => {
|
||||
* @returns A Promise that resolves to the room data
|
||||
* @throws Error if the app instance is not defined
|
||||
*/
|
||||
export const getRoom = async (roomId: string, fields?: string, cookie?: string, role?: ParticipantRole) => {
|
||||
export const getRoom = async (roomId: string, fields?: string, participantToken?: string, role?: ParticipantRole) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const req = request(app).get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}`).query({ fields });
|
||||
|
||||
if (cookie && role) {
|
||||
req.set('Cookie', cookie).set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, role);
|
||||
if (participantToken && role) {
|
||||
req.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, participantToken).set(
|
||||
INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER,
|
||||
role
|
||||
);
|
||||
} else {
|
||||
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||
}
|
||||
@ -372,49 +413,51 @@ export const getRoomRoleBySecret = async (roomId: string, secret: string) => {
|
||||
return response;
|
||||
};
|
||||
|
||||
export const generateParticipantToken = async (participantOptions: any, cookie?: string) => {
|
||||
export const generateParticipantTokenRequest = async (participantOptions: any, previousToken?: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
// Disable authentication to generate the token
|
||||
await changeSecurityConfig(AuthMode.NONE);
|
||||
|
||||
// Generate the participant token
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/participants/token`)
|
||||
.set('Cookie', cookie || '')
|
||||
.send(participantOptions);
|
||||
return response;
|
||||
const req = request(app).post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/participants/token`);
|
||||
|
||||
if (previousToken) {
|
||||
req.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, previousToken), previousToken);
|
||||
}
|
||||
|
||||
req.send(participantOptions);
|
||||
return await req;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a participant token for a room and returns the cookie containing the token
|
||||
* Generates a participant token for a room and returns the JWT token in the format "Bearer <token>"
|
||||
*/
|
||||
export const generateParticipantTokenCookie = async (
|
||||
export const generateParticipantToken = async (
|
||||
roomId: string,
|
||||
secret: string,
|
||||
participantName: string,
|
||||
cookie?: string
|
||||
participantName: string
|
||||
): Promise<string> => {
|
||||
// Generate the participant token
|
||||
const response = await generateParticipantToken(
|
||||
{
|
||||
roomId,
|
||||
secret,
|
||||
participantName
|
||||
},
|
||||
cookie
|
||||
);
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId,
|
||||
secret,
|
||||
participantName
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Return the participant token cookie
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const participantTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
return participantTokenCookie;
|
||||
const authTransportMode = await getAuthTransportMode();
|
||||
|
||||
// Return token in header or cookie based on transport mode
|
||||
if (authTransportMode === AuthTransportMode.COOKIE) {
|
||||
const cookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME);
|
||||
return cookie!;
|
||||
}
|
||||
|
||||
expect(response.body).toHaveProperty('token');
|
||||
return `Bearer ${response.body.token}`;
|
||||
};
|
||||
|
||||
export const refreshParticipantToken = async (participantOptions: any, cookie: string) => {
|
||||
export const refreshParticipantToken = async (participantOptions: any, previousToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
// Disable authentication to generate the token
|
||||
@ -422,7 +465,7 @@ export const refreshParticipantToken = async (participantOptions: any, cookie: s
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/participants/token/refresh`)
|
||||
.set('Cookie', cookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, previousToken), previousToken)
|
||||
.send(participantOptions);
|
||||
return response;
|
||||
};
|
||||
@ -541,42 +584,42 @@ export const updateParticipant = async (
|
||||
roomId: string,
|
||||
participantIdentity: string,
|
||||
newRole: ParticipantRole,
|
||||
moderatorCookie: string
|
||||
moderatorToken: string
|
||||
) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/meetings/${roomId}/participants/${participantIdentity}/role`)
|
||||
.set('Cookie', moderatorCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, moderatorToken), moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send({ role: newRole });
|
||||
return response;
|
||||
};
|
||||
|
||||
export const kickParticipant = async (roomId: string, participantIdentity: string, moderatorCookie: string) => {
|
||||
export const kickParticipant = async (roomId: string, participantIdentity: string, moderatorToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/meetings/${roomId}/participants/${participantIdentity}`)
|
||||
.set('Cookie', moderatorCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, moderatorToken), moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send();
|
||||
return response;
|
||||
};
|
||||
|
||||
export const endMeeting = async (roomId: string, moderatorCookie: string) => {
|
||||
export const endMeeting = async (roomId: string, moderatorToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/meetings/${roomId}`)
|
||||
.set('Cookie', moderatorCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, moderatorToken), moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send();
|
||||
await sleep('1s');
|
||||
return response;
|
||||
};
|
||||
|
||||
export const generateRecordingToken = async (roomId: string, secret: string) => {
|
||||
export const generateRecordingTokenRequest = async (roomId: string, secret: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
// Disable authentication to generate the token
|
||||
@ -591,39 +634,42 @@ export const generateRecordingToken = async (roomId: string, secret: string) =>
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a token for retrieving/deleting recordings from a room and returns the cookie containing the token
|
||||
* Generates a token for retrieving/deleting recordings from a room and returns the JWT token in the format "Bearer <token>"
|
||||
*/
|
||||
export const generateRecordingTokenCookie = async (roomId: string, secret: string) => {
|
||||
// Generate the recording token
|
||||
const response = await generateRecordingToken(roomId, secret);
|
||||
export const generateRecordingToken = async (roomId: string, secret: string) => {
|
||||
const response = await generateRecordingTokenRequest(roomId, secret);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Return the recording token cookie
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const recordingTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.RECORDING_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
return recordingTokenCookie;
|
||||
const authTransportMode = await getAuthTransportMode();
|
||||
|
||||
// Return token in header or cookie based on transport mode
|
||||
if (authTransportMode === AuthTransportMode.COOKIE) {
|
||||
const cookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.RECORDING_TOKEN_COOKIE_NAME);
|
||||
return cookie!;
|
||||
}
|
||||
|
||||
expect(response.body).toHaveProperty('token');
|
||||
return `Bearer ${response.body.token}`;
|
||||
};
|
||||
|
||||
export const startRecording = async (roomId: string, moderatorCookie = '') => {
|
||||
export const startRecording = async (roomId: string, moderatorToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
return await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/recordings`)
|
||||
.set('Cookie', moderatorCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, moderatorToken), moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send({
|
||||
roomId
|
||||
});
|
||||
};
|
||||
|
||||
export const stopRecording = async (recordingId: string, moderatorCookie = '') => {
|
||||
export const stopRecording = async (recordingId: string, moderatorToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/recordings/${recordingId}/stop`)
|
||||
.set('Cookie', moderatorCookie)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, moderatorToken), moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send();
|
||||
await sleep('2.5s');
|
||||
@ -670,15 +716,15 @@ export const deleteRecording = async (recordingId: string) => {
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||
};
|
||||
|
||||
export const bulkDeleteRecordings = async (recordingIds: any[], recordingTokenCookie?: string): Promise<Response> => {
|
||||
export const bulkDeleteRecordings = async (recordingIds: any[], recordingToken?: string): Promise<Response> => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const req = request(app)
|
||||
.delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings`)
|
||||
.query({ recordingIds: recordingIds.join(',') });
|
||||
|
||||
if (recordingTokenCookie) {
|
||||
req.set('Cookie', recordingTokenCookie);
|
||||
if (recordingToken) {
|
||||
req.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken), recordingToken);
|
||||
} else {
|
||||
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||
}
|
||||
@ -689,7 +735,7 @@ export const bulkDeleteRecordings = async (recordingIds: any[], recordingTokenCo
|
||||
export const downloadRecordings = async (
|
||||
recordingIds: string[],
|
||||
asBuffer = true,
|
||||
recordingTokenCookie?: string
|
||||
recordingToken?: string
|
||||
): Promise<Response> => {
|
||||
checkAppIsRunning();
|
||||
|
||||
@ -697,8 +743,8 @@ export const downloadRecordings = async (
|
||||
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/download`)
|
||||
.query({ recordingIds: recordingIds.join(',') });
|
||||
|
||||
if (recordingTokenCookie) {
|
||||
req.set('Cookie', recordingTokenCookie);
|
||||
if (recordingToken) {
|
||||
req.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken), recordingToken);
|
||||
} else {
|
||||
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
|
||||
}
|
||||
@ -714,7 +760,7 @@ export const downloadRecordings = async (
|
||||
return await req;
|
||||
};
|
||||
|
||||
export const stopAllRecordings = async (moderatorCookie: string) => {
|
||||
export const stopAllRecordings = async (moderatorToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
const response = await getAllRecordings();
|
||||
@ -731,8 +777,8 @@ export const stopAllRecordings = async (moderatorCookie: string) => {
|
||||
const tasks = recordingIds.map((recordingId: string) =>
|
||||
request(app)
|
||||
.post(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/recordings/${recordingId}/stop`)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, moderatorToken), moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.set('Cookie', moderatorCookie)
|
||||
.send()
|
||||
);
|
||||
const results = await Promise.all(tasks);
|
||||
@ -753,10 +799,12 @@ export const getAllRecordings = async (query: Record<string, any> = {}) => {
|
||||
.query(query);
|
||||
};
|
||||
|
||||
export const getAllRecordingsFromRoom = async (recordingTokenCookie: string) => {
|
||||
export const getAllRecordingsFromRoom = async (recordingToken: string) => {
|
||||
checkAppIsRunning();
|
||||
|
||||
return await request(app).get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings`).set('Cookie', recordingTokenCookie);
|
||||
return await request(app)
|
||||
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings`)
|
||||
.set(selectHeaderBasedOnToken(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken), recordingToken);
|
||||
};
|
||||
|
||||
export const deleteAllRecordings = async () => {
|
||||
|
||||
@ -6,7 +6,7 @@ import { MeetRoom, MeetRoomConfig } from '../../src/typings/ce';
|
||||
import { expectValidStartRecordingResponse } from './assertion-helpers';
|
||||
import {
|
||||
createRoom,
|
||||
generateParticipantTokenCookie,
|
||||
generateParticipantToken,
|
||||
joinFakeParticipant,
|
||||
sleep,
|
||||
startRecording,
|
||||
@ -18,9 +18,9 @@ let mockWebhookServer: http.Server;
|
||||
export interface RoomData {
|
||||
room: MeetRoom;
|
||||
moderatorSecret: string;
|
||||
moderatorCookie: string;
|
||||
moderatorToken: string;
|
||||
speakerSecret: string;
|
||||
speakerCookie: string;
|
||||
speakerToken: string;
|
||||
recordingId?: string;
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ export interface TestContext {
|
||||
* @param withParticipant Whether to join a fake participant in the room.
|
||||
* @param roomName Name of the room to create.
|
||||
* @param config Optional room config.
|
||||
* @returns Room data including secrets and cookies.
|
||||
* @returns Room data including secrets and tokens.
|
||||
*/
|
||||
export const setupSingleRoom = async (
|
||||
withParticipant = false,
|
||||
@ -48,11 +48,11 @@ export const setupSingleRoom = async (
|
||||
config
|
||||
});
|
||||
|
||||
// Extract the room secrets and generate participant tokens, saved as cookies
|
||||
// Extract the room secrets and generate participant tokens
|
||||
const { moderatorSecret, speakerSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const [moderatorCookie, speakerCookie] = await Promise.all([
|
||||
generateParticipantTokenCookie(room.roomId, moderatorSecret, 'MODERATOR'),
|
||||
generateParticipantTokenCookie(room.roomId, speakerSecret, 'SPEAKER')
|
||||
const [moderatorToken, speakerToken] = await Promise.all([
|
||||
generateParticipantToken(room.roomId, moderatorSecret, 'MODERATOR'),
|
||||
generateParticipantToken(room.roomId, speakerSecret, 'SPEAKER')
|
||||
]);
|
||||
|
||||
// Join participant if needed
|
||||
@ -63,9 +63,9 @@ export const setupSingleRoom = async (
|
||||
return {
|
||||
room,
|
||||
moderatorSecret,
|
||||
moderatorCookie,
|
||||
moderatorToken,
|
||||
speakerSecret,
|
||||
speakerCookie
|
||||
speakerToken
|
||||
};
|
||||
};
|
||||
|
||||
@ -109,7 +109,7 @@ export const setupSingleRoomWithRecording = async (
|
||||
stopDelay?: StringValue
|
||||
): Promise<RoomData> => {
|
||||
const roomData = await setupSingleRoom(true, 'TEST_ROOM');
|
||||
const response = await startRecording(roomData.room.roomId, roomData.moderatorCookie);
|
||||
const response = await startRecording(roomData.room.roomId, roomData.moderatorToken);
|
||||
expectValidStartRecordingResponse(response, roomData.room.roomId, roomData.room.roomName);
|
||||
roomData.recordingId = response.body.recordingId;
|
||||
|
||||
@ -119,7 +119,7 @@ export const setupSingleRoomWithRecording = async (
|
||||
}
|
||||
|
||||
if (stopRecordingCond) {
|
||||
await stopRecording(roomData.recordingId!, roomData.moderatorCookie);
|
||||
await stopRecording(roomData.recordingId!, roomData.moderatorToken);
|
||||
}
|
||||
|
||||
return roomData;
|
||||
@ -154,7 +154,7 @@ export const setupMultiRecordingsTestContext = async (
|
||||
}
|
||||
|
||||
// Send start recording request
|
||||
const response = await startRecording(roomData.room.roomId, roomData.moderatorCookie);
|
||||
const response = await startRecording(roomData.room.roomId, roomData.moderatorToken);
|
||||
expectValidStartRecordingResponse(response, roomData.room.roomId, roomData.room.roomName);
|
||||
|
||||
// Store the recordingId in context
|
||||
@ -171,7 +171,7 @@ export const setupMultiRecordingsTestContext = async (
|
||||
// Stop recordings for the first numStops rooms
|
||||
const stopPromises = startedRooms.slice(0, numStops).map(async (roomData) => {
|
||||
if (roomData.recordingId) {
|
||||
await stopRecording(roomData.recordingId, roomData.moderatorCookie);
|
||||
await stopRecording(roomData.recordingId, roomData.moderatorToken);
|
||||
console.log(`Recording stopped for room ${roomData.room.roomId}`);
|
||||
return roomData.recordingId;
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ const defaultConfig = {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authTransportMode: AuthTransportMode.COOKIE,
|
||||
authTransportMode: AuthTransportMode.HEADER,
|
||||
authModeToAccessRoom: AuthMode.NONE
|
||||
}
|
||||
};
|
||||
@ -36,7 +36,7 @@ describe('Security Config API Tests', () => {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authTransportMode: AuthTransportMode.COOKIE,
|
||||
authTransportMode: AuthTransportMode.HEADER,
|
||||
authModeToAccessRoom: AuthMode.ALL_USERS
|
||||
}
|
||||
};
|
||||
@ -108,7 +108,7 @@ describe('Security Config API Tests', () => {
|
||||
let response = await updateSecurityConfig({
|
||||
authentication: {
|
||||
authMode: AuthMode.NONE,
|
||||
authTransportMode: AuthTransportMode.COOKIE
|
||||
authTransportMode: AuthTransportMode.HEADER
|
||||
}
|
||||
});
|
||||
expectValidationError(response, 'authentication.authMethod', 'Required');
|
||||
@ -128,7 +128,7 @@ describe('Security Config API Tests', () => {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authTransportMode: AuthTransportMode.COOKIE
|
||||
authTransportMode: AuthTransportMode.HEADER
|
||||
}
|
||||
});
|
||||
expectValidationError(response, 'authentication.authModeToAccessRoom', 'Required');
|
||||
|
||||
@ -35,7 +35,7 @@ describe('Meetings API Tests', () => {
|
||||
expect(lkRoom.name).toBe(roomData.room.roomId);
|
||||
|
||||
// End the meeting
|
||||
let response = await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||
let response = await endMeeting(roomData.room.roomId, roomData.moderatorToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Check if the LiveKit room has been removed
|
||||
@ -62,7 +62,7 @@ describe('Meetings API Tests', () => {
|
||||
}
|
||||
|
||||
// End the meeting
|
||||
const response = await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||
const response = await endMeeting(roomData.room.roomId, roomData.moderatorToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Recreate the room with a participant
|
||||
@ -74,7 +74,7 @@ describe('Meetings API Tests', () => {
|
||||
let response = await deleteRoom(roomData.room.roomId, { withMeeting: 'force' });
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
response = await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||
response = await endMeeting(roomData.room.roomId, roomData.moderatorToken);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
@ -39,7 +39,7 @@ describe('Meetings API Tests', () => {
|
||||
expect(participant.identity).toBe(participantIdentity);
|
||||
|
||||
// Delete the participant
|
||||
const response = await kickParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
||||
const response = await kickParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Check if the participant has been removed from LiveKit
|
||||
@ -54,7 +54,7 @@ describe('Meetings API Tests', () => {
|
||||
const response = await kickParticipant(
|
||||
roomData.room.roomId,
|
||||
'NON_EXISTENT_PARTICIPANT',
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.error).toBe('Participant Error');
|
||||
@ -65,7 +65,7 @@ describe('Meetings API Tests', () => {
|
||||
let response = await deleteRoom(roomData.room.roomId, { withMeeting: 'force' });
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
response = await kickParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorCookie);
|
||||
response = await kickParticipant(roomData.room.roomId, participantIdentity, roomData.moderatorToken);
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.error).toBe('Room Error');
|
||||
});
|
||||
|
||||
@ -2,6 +2,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it, jest } from '@je
|
||||
import { container } from '../../../../src/config/index.js';
|
||||
import { LIVEKIT_URL } from '../../../../src/environment.js';
|
||||
import { FrontendEventService, LiveKitService } from '../../../../src/services/index.js';
|
||||
import { MeetSignalType } from '../../../../src/typings/ce/event.model.js';
|
||||
import { MeetTokenMetadata, ParticipantRole } from '../../../../src/typings/ce/index.js';
|
||||
import { getPermissions } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
@ -13,7 +14,6 @@ import {
|
||||
updateParticipantMetadata
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { RoomData, setupSingleRoom } from '../../../helpers/test-scenarios.js';
|
||||
import { MeetSignalType } from '../../../../src/typings/ce/event.model.js';
|
||||
|
||||
const participantIdentity = 'TEST_PARTICIPANT';
|
||||
|
||||
@ -60,7 +60,7 @@ describe('Meetings API Tests', () => {
|
||||
roomData.room.roomId,
|
||||
participantIdentity,
|
||||
ParticipantRole.MODERATOR,
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
@ -76,7 +76,8 @@ describe('Meetings API Tests', () => {
|
||||
// Verify sendSignal method has been called twice
|
||||
expect(sendSignalSpy).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(sendSignalSpy).toHaveBeenNthCalledWith(1,
|
||||
expect(sendSignalSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
roomData.room.roomId,
|
||||
{
|
||||
roomId: roomData.room.roomId,
|
||||
@ -91,7 +92,8 @@ describe('Meetings API Tests', () => {
|
||||
}
|
||||
);
|
||||
|
||||
expect(sendSignalSpy).toHaveBeenNthCalledWith(2,
|
||||
expect(sendSignalSpy).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
roomData.room.roomId,
|
||||
{
|
||||
roomId: roomData.room.roomId,
|
||||
@ -114,7 +116,7 @@ describe('Meetings API Tests', () => {
|
||||
roomData.room.roomId,
|
||||
participantIdentity,
|
||||
ParticipantRole.SPEAKER,
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
@ -133,7 +135,7 @@ describe('Meetings API Tests', () => {
|
||||
roomData.room.roomId,
|
||||
'NON_EXISTENT_PARTICIPANT',
|
||||
ParticipantRole.MODERATOR,
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.error).toBe('Participant Error');
|
||||
@ -148,7 +150,7 @@ describe('Meetings API Tests', () => {
|
||||
roomData.room.roomId,
|
||||
participantIdentity,
|
||||
ParticipantRole.MODERATOR,
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.error).toBe('Room Error');
|
||||
|
||||
@ -1,12 +1,16 @@
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from '@jest/globals';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { AuthTransportMode } from '../../../../src/typings/ce/index.js';
|
||||
import { ParticipantRole } from '../../../../src/typings/ce/participant.js';
|
||||
import { expectValidationError, expectValidParticipantTokenResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
endMeeting,
|
||||
extractCookieFromHeaders,
|
||||
generateParticipantToken,
|
||||
generateParticipantTokenCookie,
|
||||
generateParticipantTokenRequest,
|
||||
startTestServer,
|
||||
updateRoomStatus
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
@ -33,7 +37,7 @@ describe('Participant API 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({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret
|
||||
});
|
||||
@ -41,7 +45,7 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it('should generate a participant token with moderator permissions when using the moderator secret', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName
|
||||
@ -55,7 +59,7 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it('should generate a participant token with speaker permissions when using the speaker secret', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
participantName
|
||||
@ -69,19 +73,22 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it(`should generate a participant token with both speaker and moderator permissions
|
||||
when using the speaker secret after having a moderator token`, async () => {
|
||||
const moderatorCookie = await generateParticipantTokenCookie(
|
||||
when using the speaker secret after having a moderator token in cookie mode`, async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
const moderatorToken = await generateParticipantToken(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret,
|
||||
`${participantName}_MODERATOR`
|
||||
);
|
||||
const speakerResponse = await generateParticipantToken(
|
||||
const speakerResponse = await generateParticipantTokenRequest(
|
||||
{
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
participantName: `${participantName}_SPEAKER`
|
||||
},
|
||||
moderatorCookie
|
||||
moderatorToken
|
||||
);
|
||||
expectValidParticipantTokenResponse(
|
||||
speakerResponse,
|
||||
@ -91,11 +98,47 @@ describe('Participant API Tests', () => {
|
||||
undefined,
|
||||
[ParticipantRole.MODERATOR]
|
||||
);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should generate a participant token and store it in a cookie when in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Generate the participant token
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName
|
||||
});
|
||||
expectValidParticipantTokenResponse(
|
||||
response,
|
||||
roomData.room.roomId,
|
||||
ParticipantRole.MODERATOR,
|
||||
participantName
|
||||
);
|
||||
|
||||
// Check that the token is included in a cookie
|
||||
const participantTokenCookie = extractCookieFromHeaders(
|
||||
response,
|
||||
INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME
|
||||
);
|
||||
expect(participantTokenCookie).toBeDefined();
|
||||
expect(participantTokenCookie).toContain(response.body.token);
|
||||
expect(participantTokenCookie).toContain('HttpOnly');
|
||||
expect(participantTokenCookie).toContain('SameSite=None');
|
||||
expect(participantTokenCookie).toContain('Secure');
|
||||
expect(participantTokenCookie).toContain('Path=/');
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should success when participant already exists in the room', async () => {
|
||||
roomData = await setupSingleRoom(true);
|
||||
let response = await generateParticipantToken({
|
||||
let response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName
|
||||
@ -109,7 +152,7 @@ describe('Participant API Tests', () => {
|
||||
participantName
|
||||
);
|
||||
|
||||
response = await generateParticipantToken({
|
||||
response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName
|
||||
@ -128,9 +171,9 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail with 409 when room is closed', async () => {
|
||||
await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||
await endMeeting(roomData.room.roomId, roomData.moderatorToken);
|
||||
await updateRoomStatus(roomData.room.roomId, 'closed');
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName
|
||||
@ -139,7 +182,7 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail with 404 when room does not exist', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: 'non_existent_room',
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName
|
||||
@ -148,7 +191,7 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail with 400 when secret is invalid', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: 'invalid_secret',
|
||||
participantName
|
||||
@ -159,7 +202,7 @@ describe('Participant API Tests', () => {
|
||||
|
||||
describe('Generate Participant Token Validation Tests', () => {
|
||||
it('should fail when roomId is not provided', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName
|
||||
});
|
||||
@ -167,7 +210,7 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when secret is not provided', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
participantName
|
||||
});
|
||||
@ -175,7 +218,7 @@ describe('Participant API Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail when secret is empty', async () => {
|
||||
const response = await generateParticipantToken({
|
||||
const response = await generateParticipantTokenRequest({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: '',
|
||||
participantName
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { AuthTransportMode } from '../../../../src/typings/ce/index.js';
|
||||
import { ParticipantRole } from '../../../../src/typings/ce/participant.js';
|
||||
import { expectValidationError, expectValidParticipantTokenResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
extractCookieFromHeaders,
|
||||
refreshParticipantToken,
|
||||
sleep,
|
||||
startTestServer
|
||||
@ -44,7 +47,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expectValidParticipantTokenResponse(
|
||||
response,
|
||||
@ -63,7 +66,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.speakerCookie
|
||||
roomData.speakerToken
|
||||
);
|
||||
expectValidParticipantTokenResponse(
|
||||
response,
|
||||
@ -74,6 +77,47 @@ describe('Participant API Tests', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should refresh participant token and store it in a cookie when in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Create a new room to obtain participant token in cookie mode
|
||||
const newRoomData = await setupSingleRoom(true);
|
||||
|
||||
// Refresh the participant token
|
||||
const response = await refreshParticipantToken(
|
||||
{
|
||||
roomId: newRoomData.room.roomId,
|
||||
secret: newRoomData.moderatorSecret,
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
newRoomData.moderatorToken
|
||||
);
|
||||
expectValidParticipantTokenResponse(
|
||||
response,
|
||||
newRoomData.room.roomId,
|
||||
ParticipantRole.MODERATOR,
|
||||
participantName,
|
||||
participantName
|
||||
);
|
||||
|
||||
// Check that the token is included in a cookie
|
||||
const participantTokenCookie = extractCookieFromHeaders(
|
||||
response,
|
||||
INTERNAL_CONFIG.PARTICIPANT_TOKEN_COOKIE_NAME
|
||||
);
|
||||
expect(participantTokenCookie).toBeDefined();
|
||||
expect(participantTokenCookie).toContain(response.body.token);
|
||||
expect(participantTokenCookie).toContain('HttpOnly');
|
||||
expect(participantTokenCookie).toContain('SameSite=None');
|
||||
expect(participantTokenCookie).toContain('Secure');
|
||||
expect(participantTokenCookie).toContain('Path=/');
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail with 400 when secret is invalid', async () => {
|
||||
const response = await refreshParticipantToken(
|
||||
{
|
||||
@ -82,7 +126,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
@ -108,7 +152,7 @@ describe('Participant API Tests', () => {
|
||||
secret: 'invalid_secret',
|
||||
participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
@ -122,7 +166,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
@ -135,7 +179,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
@ -149,7 +193,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expectValidationError(response, 'roomId', 'Required');
|
||||
});
|
||||
@ -161,7 +205,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expectValidationError(response, 'secret', 'Required');
|
||||
});
|
||||
@ -174,7 +218,7 @@ describe('Participant API Tests', () => {
|
||||
participantName,
|
||||
participantIdentity: participantName
|
||||
},
|
||||
roomData.moderatorCookie
|
||||
roomData.moderatorToken
|
||||
);
|
||||
expectValidationError(response, 'secret', 'Secret is required');
|
||||
});
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
deleteAllRecordings,
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
generateRecordingTokenCookie,
|
||||
generateRecordingToken,
|
||||
getAllRecordings,
|
||||
startRecording,
|
||||
startTestServer,
|
||||
@ -73,7 +73,7 @@ describe('Recording API Tests', () => {
|
||||
]
|
||||
});
|
||||
|
||||
await stopRecording(activeRecordingId!, activeRecordingRoom!.moderatorCookie);
|
||||
await stopRecording(activeRecordingId!, activeRecordingRoom!.moderatorToken);
|
||||
|
||||
deleteResponse = await bulkDeleteRecordings([activeRecordingId]);
|
||||
|
||||
@ -102,7 +102,7 @@ describe('Recording API Tests', () => {
|
||||
|
||||
await Promise.all(
|
||||
recordingIds.map((id, index) => {
|
||||
return stopRecording(id!, testContext.getRoomByIndex(index)!.moderatorCookie);
|
||||
return stopRecording(id!, testContext.getRoomByIndex(index)!.moderatorToken);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -122,14 +122,14 @@ describe('Recording API Tests', () => {
|
||||
const recordingId = roomData.recordingId;
|
||||
|
||||
// Generate a recording token for the room
|
||||
const recordingCookie = await generateRecordingTokenCookie(roomId, roomData.moderatorSecret);
|
||||
const recordingToken = await generateRecordingToken(roomId, roomData.moderatorSecret);
|
||||
|
||||
// Create another room and start a recording
|
||||
const otherRoomData = await setupSingleRoomWithRecording(true);
|
||||
const otherRecordingId = otherRoomData.recordingId;
|
||||
|
||||
// Intenta eliminar ambas grabaciones usando el token de la primera sala
|
||||
const deleteResponse = await bulkDeleteRecordings([recordingId, otherRecordingId], recordingCookie);
|
||||
const deleteResponse = await bulkDeleteRecordings([recordingId, otherRecordingId], recordingToken);
|
||||
|
||||
expect(deleteResponse.status).toBe(400);
|
||||
expect(deleteResponse.body).toEqual({
|
||||
@ -181,7 +181,7 @@ describe('Recording API Tests', () => {
|
||||
const meetStorageService = container.get<MeetStorageService>(MeetStorageService);
|
||||
// Create two recordings in the same room
|
||||
const testContext = await setupMultiRecordingsTestContext(1, 1, 1);
|
||||
const { room, recordingId: firstRecordingId, moderatorCookie } = testContext.rooms[0];
|
||||
const { room, recordingId: firstRecordingId, moderatorToken } = testContext.rooms[0];
|
||||
|
||||
let roomMetadata = await meetStorageService.getArchivedRoomMetadata(room.roomId);
|
||||
|
||||
@ -195,11 +195,11 @@ describe('Recording API Tests', () => {
|
||||
expect(roomMetadata!.moderatorUrl).toContain(room.roomId);
|
||||
expect(roomMetadata!.speakerUrl).toContain(room.roomId);
|
||||
|
||||
const response = await startRecording(room.roomId, moderatorCookie);
|
||||
const response = await startRecording(room.roomId, moderatorToken);
|
||||
expectValidStartRecordingResponse(response, room.roomId, room.roomName);
|
||||
const secondRecordingId = response.body.recordingId;
|
||||
|
||||
await stopRecording(secondRecordingId, moderatorCookie);
|
||||
await stopRecording(secondRecordingId, moderatorToken);
|
||||
// Delete first recording - room metadata should remain
|
||||
const bulkResponse = await bulkDeleteRecordings([firstRecordingId, secondRecordingId]);
|
||||
expect(bulkResponse.status).toBe(200);
|
||||
|
||||
@ -27,17 +27,17 @@ describe('Recording API Tests', () => {
|
||||
});
|
||||
|
||||
describe('Delete Recording Tests', () => {
|
||||
let room: MeetRoom, recordingId: string, moderatorCookie: string;
|
||||
let room: MeetRoom, recordingId: string, moderatorToken: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
const testContext = await setupMultiRecordingsTestContext(1, 1, 1);
|
||||
const roomData = testContext.getRoomByIndex(0)!;
|
||||
|
||||
({ room, recordingId = '', moderatorCookie } = roomData);
|
||||
({ room, recordingId = '', moderatorToken } = roomData);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await stopAllRecordings(moderatorCookie);
|
||||
await stopAllRecordings(moderatorToken);
|
||||
await Promise.all([deleteAllRecordings(), deleteAllRooms()]);
|
||||
});
|
||||
|
||||
@ -77,11 +77,11 @@ describe('Recording API Tests', () => {
|
||||
expect(roomMetadata!.speakerUrl).toContain(room.roomId);
|
||||
|
||||
// Generate a new recording
|
||||
const response = await startRecording(room.roomId, moderatorCookie);
|
||||
const response = await startRecording(room.roomId, moderatorToken);
|
||||
console.log('Start recording response:', response.body);
|
||||
expectValidStartRecordingResponse(response, room.roomId, room.roomName);
|
||||
const secondRecordingId = response.body.recordingId;
|
||||
await stopRecording(secondRecordingId, moderatorCookie);
|
||||
await stopRecording(secondRecordingId, moderatorToken);
|
||||
|
||||
// Check that the room metadata still exists after deleteing the first recording
|
||||
let deleteResponse = await deleteRecording(recordingId!);
|
||||
@ -104,17 +104,17 @@ describe('Recording API Tests', () => {
|
||||
});
|
||||
|
||||
describe('Delete Recording Validation', () => {
|
||||
let room: MeetRoom, recordingId: string, moderatorCookie: string;
|
||||
let room: MeetRoom, recordingId: string, moderatorToken: string;
|
||||
beforeAll(async () => {
|
||||
await deleteAllRecordings();
|
||||
const testContext = await setupMultiRecordingsTestContext(1, 1, 1);
|
||||
const roomData = testContext.getRoomByIndex(0)!;
|
||||
|
||||
({ room, recordingId = '', moderatorCookie } = roomData);
|
||||
({ room, recordingId = '', moderatorToken } = roomData);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await stopAllRecordings(moderatorCookie);
|
||||
await stopAllRecordings(moderatorToken);
|
||||
await Promise.all([deleteAllRecordings(), deleteAllRooms()]);
|
||||
});
|
||||
it('should fail when recordingId has incorrect format', async () => {
|
||||
@ -154,13 +154,13 @@ describe('Recording API Tests', () => {
|
||||
|
||||
it('should return 409 when attempting to delete an active recording', async () => {
|
||||
const testContext = await setupMultiRecordingsTestContext(1, 1, 0);
|
||||
const { recordingId: activeRecordingId = '', moderatorCookie } = testContext.rooms[0];
|
||||
const { recordingId: activeRecordingId = '', moderatorToken } = testContext.rooms[0];
|
||||
|
||||
// Attempt to delete the active recording
|
||||
let deleteResponse = await deleteRecording(activeRecordingId);
|
||||
expect(deleteResponse.status).toBe(409);
|
||||
|
||||
await stopRecording(activeRecordingId, moderatorCookie);
|
||||
await stopRecording(activeRecordingId, moderatorToken);
|
||||
// Attempt to delete the recording again
|
||||
deleteResponse = await deleteRecording(activeRecordingId);
|
||||
expect(deleteResponse.status).toBe(200);
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
downloadRecordings,
|
||||
generateRecordingTokenCookie,
|
||||
generateRecordingToken,
|
||||
startTestServer
|
||||
} from '../../../helpers/request-helpers';
|
||||
import { setupMultiRecordingsTestContext, setupSingleRoomWithRecording } from '../../../helpers/test-scenarios';
|
||||
@ -59,12 +59,12 @@ describe('Recording API Tests', () => {
|
||||
const roomData = await setupSingleRoomWithRecording(true);
|
||||
const roomId = roomData.room.roomId;
|
||||
const recordingId = roomData.recordingId!;
|
||||
const recordingCookie = await generateRecordingTokenCookie(roomId, roomData.moderatorSecret);
|
||||
const recordingToken = await generateRecordingToken(roomId, roomData.moderatorSecret);
|
||||
|
||||
const otherRoomData = await setupSingleRoomWithRecording(true);
|
||||
const otherRecordingId = otherRoomData.recordingId!;
|
||||
|
||||
const res = await downloadRecordings([recordingId, otherRecordingId], true, recordingCookie);
|
||||
const res = await downloadRecordings([recordingId, otherRecordingId], true, recordingToken);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
const entries = await getZipEntries(res.body);
|
||||
@ -75,12 +75,12 @@ describe('Recording API Tests', () => {
|
||||
it('should return an error if none of the recordings belong to the room in the token', async () => {
|
||||
const roomData = await setupSingleRoomWithRecording(true);
|
||||
const roomId = roomData.room.roomId;
|
||||
const recordingCookie = await generateRecordingTokenCookie(roomId, roomData.moderatorSecret);
|
||||
const recordingToken = await generateRecordingToken(roomId, roomData.moderatorSecret);
|
||||
|
||||
const otherRoomData = await setupSingleRoomWithRecording(true);
|
||||
const otherRecordingId = otherRoomData.recordingId!;
|
||||
|
||||
const res = await downloadRecordings([otherRecordingId], false, recordingCookie);
|
||||
const res = await downloadRecordings([otherRecordingId], false, recordingToken);
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body).toHaveProperty('error');
|
||||
|
||||
@ -167,7 +167,7 @@ describe('Recording API Tests', () => {
|
||||
|
||||
it('should return a 409 when the recording is in progress', async () => {
|
||||
const testContext = await setupMultiRecordingsTestContext(1, 1, 0);
|
||||
const { recordingId: activeRecordingId = '', moderatorCookie } = testContext.rooms[0];
|
||||
const { recordingId: activeRecordingId = '', moderatorToken } = testContext.rooms[0];
|
||||
|
||||
// Attempt to get the media of an active recording
|
||||
const response = await getRecordingMedia(activeRecordingId);
|
||||
@ -176,7 +176,7 @@ describe('Recording API Tests', () => {
|
||||
expect(response.body).toHaveProperty('message');
|
||||
expect(response.body.message).toContain(`Recording '${activeRecordingId}' is not stopped yet`);
|
||||
|
||||
await stopRecording(activeRecordingId, moderatorCookie);
|
||||
await stopRecording(activeRecordingId, moderatorToken);
|
||||
});
|
||||
|
||||
it('should return 404 when recording not found', async () => {
|
||||
|
||||
@ -50,7 +50,7 @@ describe('Recording API Tests', () => {
|
||||
const {
|
||||
room: roomAux,
|
||||
recordingId: recordingIdAux = '',
|
||||
moderatorCookie: moderatorCookieAux
|
||||
moderatorToken: moderatorTokenAux
|
||||
} = contextAux.getRoomByIndex(0)!;
|
||||
const response = await getRecording(recordingIdAux);
|
||||
|
||||
@ -62,7 +62,7 @@ describe('Recording API Tests', () => {
|
||||
MeetRecordingStatus.ACTIVE
|
||||
);
|
||||
|
||||
await stopAllRecordings(moderatorCookieAux);
|
||||
await stopAllRecordings(moderatorTokenAux);
|
||||
});
|
||||
|
||||
it('should return 404 when recording does not exist', async () => {
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
deleteAllRecordings,
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
generateRecordingTokenCookie,
|
||||
generateRecordingToken,
|
||||
getAllRecordings,
|
||||
getAllRecordingsFromRoom,
|
||||
startTestServer
|
||||
@ -63,12 +63,12 @@ describe('Recordings API Tests', () => {
|
||||
const roomId = roomData.room.roomId;
|
||||
|
||||
// Generate a recording token for the room
|
||||
const recordingCookie = await generateRecordingTokenCookie(roomId, roomData.speakerSecret);
|
||||
const recordingToken = await generateRecordingToken(roomId, roomData.speakerSecret);
|
||||
|
||||
// Create a new room and start a recording
|
||||
roomData = await setupSingleRoomWithRecording(true);
|
||||
|
||||
const response = await getAllRecordingsFromRoom(recordingCookie);
|
||||
const response = await getAllRecordingsFromRoom(recordingToken);
|
||||
expectSuccessListRecordingResponse(response, 1, false, false);
|
||||
expect(response.body.recordings[0].roomId).toBe(roomId);
|
||||
});
|
||||
|
||||
@ -41,10 +41,10 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const moderatorCookie = context?.getRoomByIndex(0)?.moderatorCookie;
|
||||
const moderatorToken = context?.getRoomByIndex(0)?.moderatorToken;
|
||||
|
||||
if (moderatorCookie) {
|
||||
await stopAllRecordings(moderatorCookie);
|
||||
if (moderatorToken) {
|
||||
await stopAllRecordings(moderatorToken);
|
||||
}
|
||||
|
||||
eventController.reset();
|
||||
@ -67,7 +67,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
|
||||
try {
|
||||
// Attempt to start recording
|
||||
const result = await startRecording(roomData.room.roomId, roomData.moderatorCookie);
|
||||
const result = await startRecording(roomData.room.roomId, roomData.moderatorToken);
|
||||
expect(eventServiceOffSpy).toHaveBeenCalledWith(
|
||||
DistributedEventType.RECORDING_ACTIVE,
|
||||
expect.any(Function)
|
||||
@ -122,7 +122,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
|
||||
try {
|
||||
// Start recording with a short timeout
|
||||
const result = await startRecording(roomData.room.roomId, roomData.moderatorCookie);
|
||||
const result = await startRecording(roomData.room.roomId, roomData.moderatorToken);
|
||||
|
||||
expect(eventServiceOffSpy).toHaveBeenCalledWith(
|
||||
DistributedEventType.RECORDING_ACTIVE,
|
||||
@ -182,7 +182,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
|
||||
try {
|
||||
// Start recording in room1 (should timeout)
|
||||
const rec1 = await startRecording(room1.room.roomId, room1.moderatorCookie);
|
||||
const rec1 = await startRecording(room1.room.roomId, room1.moderatorToken);
|
||||
expect(rec1.status).toBe(503);
|
||||
|
||||
setInternalConfig({
|
||||
@ -190,18 +190,18 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
});
|
||||
// ✅ EXPECTED BEHAVIOR: System should remain stable
|
||||
// Recording in different room should work normally
|
||||
const rec2 = await startRecording(room2.room.roomId, room2.moderatorCookie);
|
||||
const rec2 = await startRecording(room2.room.roomId, room2.moderatorToken);
|
||||
expect(rec2.status).toBe(201);
|
||||
expectValidStartRecordingResponse(rec2, room2.room.roomId, room2.room.roomName);
|
||||
|
||||
let response = await stopRecording(rec2.body.recordingId!, room2.moderatorCookie);
|
||||
let response = await stopRecording(rec2.body.recordingId!, room2.moderatorToken);
|
||||
expectValidStopRecordingResponse(response, rec2.body.recordingId!, room2.room.roomId, room2.room.roomName);
|
||||
|
||||
// ✅ EXPECTED BEHAVIOR: After timeout cleanup, room1 should be available again
|
||||
const rec3 = await startRecording(room1.room.roomId, room1.moderatorCookie);
|
||||
const rec3 = await startRecording(room1.room.roomId, room1.moderatorToken);
|
||||
expect(rec3.status).toBe(201);
|
||||
expectValidStartRecordingResponse(rec3, room1.room.roomId, room1.room.roomName);
|
||||
response = await stopRecording(rec3.body.recordingId!, room1.moderatorCookie);
|
||||
response = await stopRecording(rec3.body.recordingId!, room1.moderatorToken);
|
||||
expectValidStopRecordingResponse(response, rec3.body.recordingId!, room1.room.roomId, room1.room.roomName);
|
||||
} finally {
|
||||
startRoomCompositeSpy.mockRestore();
|
||||
@ -226,7 +226,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
try {
|
||||
// Start recordings in all rooms simultaneously (all should timeout)
|
||||
const results = await Promise.all(
|
||||
rooms.map((room) => startRecording(room.room.roomId, room.moderatorCookie))
|
||||
rooms.map((room) => startRecording(room.room.roomId, room.moderatorToken))
|
||||
);
|
||||
|
||||
// All should timeout
|
||||
@ -241,14 +241,14 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
|
||||
// ✅ EXPECTED BEHAVIOR: After timeouts, all rooms should be available again
|
||||
const retryResults = await Promise.all(
|
||||
rooms.map((room) => startRecording(room.room.roomId, room.moderatorCookie))
|
||||
rooms.map((room) => startRecording(room.room.roomId, room.moderatorToken))
|
||||
);
|
||||
|
||||
for (const startResult of retryResults) {
|
||||
expect(startResult.status).toBe(201);
|
||||
const room = rooms.find((r) => r.room.roomId === startResult.body.roomId)!;
|
||||
expectValidStartRecordingResponse(startResult, room.room.roomId, room.room.roomName);
|
||||
const stopResult = await stopRecording(startResult.body.recordingId!, room.moderatorCookie);
|
||||
const stopResult = await stopRecording(startResult.body.recordingId!, room.moderatorToken);
|
||||
expectValidStopRecordingResponse(
|
||||
stopResult,
|
||||
startResult.body.recordingId!,
|
||||
@ -272,18 +272,18 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
eventController.initialize();
|
||||
eventController.pauseEventsForRoom(roomDataA!.room.roomId);
|
||||
|
||||
const recordingPromiseA = startRecording(roomDataA!.room.roomId, roomDataA!.moderatorCookie);
|
||||
const recordingPromiseA = startRecording(roomDataA!.room.roomId, roomDataA!.moderatorToken);
|
||||
|
||||
// Brief delay to ensure both recordings start in the right order
|
||||
await sleep('1s');
|
||||
|
||||
// Step 2: Start recording in roomB (this will complete quickly)
|
||||
const recordingResponseB = await startRecording(roomDataB!.room.roomId, roomDataB!.moderatorCookie);
|
||||
const recordingResponseB = await startRecording(roomDataB!.room.roomId, roomDataB!.moderatorToken);
|
||||
expectValidStartRecordingResponse(recordingResponseB, roomDataB!.room.roomId, roomDataB!.room.roomName);
|
||||
const recordingIdB = recordingResponseB.body.recordingId;
|
||||
|
||||
// Step 3: Stop recording in roomB while roomA is still waiting for its event
|
||||
const stopResponseB = await stopRecording(recordingIdB, roomDataB!.moderatorCookie);
|
||||
const stopResponseB = await stopRecording(recordingIdB, roomDataB!.moderatorToken);
|
||||
expectValidStopRecordingResponse(stopResponseB, recordingIdB, roomDataB!.room.roomId, roomDataB!.room.roomName);
|
||||
|
||||
eventController.releaseEventsForRoom(roomDataA!.room.roomId);
|
||||
@ -303,7 +303,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
const roomDataList = Array.from({ length: 5 }, (_, index) => context!.getRoomByIndex(index)!);
|
||||
|
||||
const startResponses = await Promise.all(
|
||||
roomDataList.map((roomData) => startRecording(roomData.room.roomId, roomData.moderatorCookie))
|
||||
roomDataList.map((roomData) => startRecording(roomData.room.roomId, roomData.moderatorToken))
|
||||
);
|
||||
|
||||
startResponses.forEach((response, index) => {
|
||||
@ -317,7 +317,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
const recordingIds = startResponses.map((res) => res.body.recordingId);
|
||||
|
||||
const stopResponses = await Promise.all(
|
||||
recordingIds.map((recordingId, index) => stopRecording(recordingId, roomDataList[index].moderatorCookie))
|
||||
recordingIds.map((recordingId, index) => stopRecording(recordingId, roomDataList[index].moderatorToken))
|
||||
);
|
||||
|
||||
stopResponses.forEach((response, index) => {
|
||||
@ -334,14 +334,14 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
context = await setupMultiRoomTestContext(2, true);
|
||||
const roomDataA = context.getRoomByIndex(0);
|
||||
const roomDataB = context.getRoomByIndex(1);
|
||||
const responseA = await startRecording(roomDataA!.room.roomId, roomDataA!.moderatorCookie);
|
||||
const responseB = await startRecording(roomDataB!.room.roomId, roomDataB!.moderatorCookie);
|
||||
const responseA = await startRecording(roomDataA!.room.roomId, roomDataA!.moderatorToken);
|
||||
const responseB = await startRecording(roomDataB!.room.roomId, roomDataB!.moderatorToken);
|
||||
const recordingIdA = responseA.body.recordingId;
|
||||
const recordingIdB = responseB.body.recordingId;
|
||||
|
||||
const [stopResponseA, stopResponseB] = await Promise.all([
|
||||
stopRecording(recordingIdA, roomDataA!.moderatorCookie),
|
||||
stopRecording(recordingIdB, roomDataB!.moderatorCookie)
|
||||
stopRecording(recordingIdA, roomDataA!.moderatorToken),
|
||||
stopRecording(recordingIdB, roomDataB!.moderatorToken)
|
||||
]);
|
||||
expectValidStopRecordingResponse(stopResponseA, recordingIdA, roomDataA!.room.roomId, roomDataA!.room.roomName);
|
||||
expectValidStopRecordingResponse(stopResponseB, recordingIdB, roomDataB!.room.roomId, roomDataB!.room.roomName);
|
||||
@ -352,8 +352,8 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
const roomData = context.getRoomByIndex(0)!;
|
||||
|
||||
const [firstRecordingResponse, secondRecordingResponse] = await Promise.all([
|
||||
startRecording(roomData.room.roomId, roomData.moderatorCookie),
|
||||
startRecording(roomData.room.roomId, roomData.moderatorCookie)
|
||||
startRecording(roomData.room.roomId, roomData.moderatorToken),
|
||||
startRecording(roomData.room.roomId, roomData.moderatorToken)
|
||||
]);
|
||||
|
||||
console.log('First recording response:', firstRecordingResponse.body);
|
||||
@ -368,7 +368,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
if (firstRecordingResponse.status === 201) {
|
||||
expectValidStartRecordingResponse(firstRecordingResponse, roomData.room.roomId, roomData.room.roomName);
|
||||
// stop the first recording
|
||||
const stopResponse = await stopRecording(firstRecordingResponse.body.recordingId, roomData.moderatorCookie);
|
||||
const stopResponse = await stopRecording(firstRecordingResponse.body.recordingId, roomData.moderatorToken);
|
||||
expectValidStopRecordingResponse(
|
||||
stopResponse,
|
||||
firstRecordingResponse.body.recordingId,
|
||||
@ -378,10 +378,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
} else {
|
||||
expectValidStartRecordingResponse(secondRecordingResponse, roomData.room.roomId, roomData.room.roomName);
|
||||
// stop the second recording
|
||||
const stopResponse = await stopRecording(
|
||||
secondRecordingResponse.body.recordingId,
|
||||
roomData.moderatorCookie
|
||||
);
|
||||
const stopResponse = await stopRecording(secondRecordingResponse.body.recordingId, roomData.moderatorToken);
|
||||
expectValidStopRecordingResponse(
|
||||
stopResponse,
|
||||
secondRecordingResponse.body.recordingId,
|
||||
@ -397,12 +394,12 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
|
||||
const gcSpy = jest.spyOn(recordingService as any, 'performRecordingLocksGarbageCollection');
|
||||
|
||||
const startResponse = await startRecording(roomData.room.roomId, roomData.moderatorCookie);
|
||||
const startResponse = await startRecording(roomData.room.roomId, roomData.moderatorToken);
|
||||
expectValidStartRecordingResponse(startResponse, roomData.room.roomId, roomData.room.roomName);
|
||||
const recordingId = startResponse.body.recordingId;
|
||||
|
||||
// Execute garbage collection while stopping the recording
|
||||
const stopPromise = stopRecording(recordingId, roomData.moderatorCookie);
|
||||
const stopPromise = stopRecording(recordingId, roomData.moderatorToken);
|
||||
const gcPromise = recordingService['performRecordingLocksGarbageCollection']();
|
||||
|
||||
// Both operations should complete
|
||||
@ -469,18 +466,18 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
const room2 = context.getRoomByIndex(1)!;
|
||||
const room3 = context.getRoomByIndex(2)!;
|
||||
|
||||
const start1 = await startRecording(room1.room.roomId, room1.moderatorCookie);
|
||||
const start2 = await startRecording(room2.room.roomId, room2.moderatorCookie);
|
||||
const start1 = await startRecording(room1.room.roomId, room1.moderatorToken);
|
||||
const start2 = await startRecording(room2.room.roomId, room2.moderatorToken);
|
||||
|
||||
const recordingId1 = start1.body.recordingId;
|
||||
const recordingId2 = start2.body.recordingId;
|
||||
|
||||
await stopRecording(recordingId1, room1.moderatorCookie);
|
||||
await stopRecording(recordingId2, room2.moderatorCookie);
|
||||
await stopRecording(recordingId1, room1.moderatorToken);
|
||||
await stopRecording(recordingId2, room2.moderatorToken);
|
||||
|
||||
// Bulk delete the recordings while starting a new one
|
||||
const bulkDeletePromise = bulkDeleteRecordings([recordingId1, recordingId2]);
|
||||
const startNewRecordingPromise = startRecording(room3.room.roomId, room3.moderatorCookie);
|
||||
const startNewRecordingPromise = startRecording(room3.room.roomId, room3.moderatorToken);
|
||||
|
||||
// Both operations should complete successfully
|
||||
const [bulkDeleteResult, newRecordingResult] = await Promise.all([bulkDeletePromise, startNewRecordingPromise]);
|
||||
@ -490,7 +487,7 @@ describe('Recording API Race Conditions Tests', () => {
|
||||
// Check that the new recording started successfully
|
||||
expectValidStartRecordingResponse(newRecordingResult, room3.room.roomId, room3.room.roomName);
|
||||
|
||||
const newStopResponse = await stopRecording(newRecordingResult.body.recordingId, room3.moderatorCookie);
|
||||
const newStopResponse = await stopRecording(newRecordingResult.body.recordingId, room3.moderatorToken);
|
||||
expectValidStopRecordingResponse(
|
||||
newStopResponse,
|
||||
newRecordingResult.body.recordingId,
|
||||
|
||||
@ -23,7 +23,7 @@ import { setupMultiRoomTestContext, TestContext } from '../../../helpers/test-sc
|
||||
|
||||
describe('Recording API Tests', () => {
|
||||
let context: TestContext | null = null;
|
||||
let room: MeetRoom, moderatorCookie: string;
|
||||
let room: MeetRoom, moderatorToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
startTestServer();
|
||||
@ -39,7 +39,7 @@ describe('Recording API Tests', () => {
|
||||
beforeAll(async () => {
|
||||
// Create a room and join a participant
|
||||
context = await setupMultiRoomTestContext(1, true);
|
||||
({ room, moderatorCookie } = context.getRoomByIndex(0)!);
|
||||
({ room, moderatorToken } = context.getRoomByIndex(0)!);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -49,16 +49,16 @@ describe('Recording API Tests', () => {
|
||||
});
|
||||
|
||||
it('should return 201 with proper response and location header when recording starts successfully', async () => {
|
||||
const response = await startRecording(room.roomId, moderatorCookie);
|
||||
const response = await startRecording(room.roomId, moderatorToken);
|
||||
const recordingId = response.body.recordingId;
|
||||
expectValidStartRecordingResponse(response, room.roomId, room.roomName);
|
||||
|
||||
const stopResponse = await stopRecording(recordingId, moderatorCookie);
|
||||
const stopResponse = await stopRecording(recordingId, moderatorToken);
|
||||
expectValidStopRecordingResponse(stopResponse, recordingId, room.roomId, room.roomName);
|
||||
});
|
||||
|
||||
it('should secrets and archived room files be created when recording starts', async () => {
|
||||
const response = await startRecording(room.roomId, moderatorCookie);
|
||||
const response = await startRecording(room.roomId, moderatorToken);
|
||||
const recordingId = response.body.recordingId;
|
||||
expectValidStartRecordingResponse(response, room.roomId, room.roomName);
|
||||
|
||||
@ -75,24 +75,24 @@ describe('Recording API Tests', () => {
|
||||
expect(archivedRoom?.speakerUrl).toBeDefined();
|
||||
expect(archivedRoom?.config).toBeDefined();
|
||||
|
||||
const secretsResponse = await stopRecording(recordingId, moderatorCookie);
|
||||
const secretsResponse = await stopRecording(recordingId, moderatorToken);
|
||||
expectValidStopRecordingResponse(secretsResponse, recordingId, room.roomId, room.roomName);
|
||||
});
|
||||
|
||||
it('should successfully start recording, stop it, and start again (sequential operations)', async () => {
|
||||
const firstStartResponse = await startRecording(room.roomId, moderatorCookie);
|
||||
const firstStartResponse = await startRecording(room.roomId, moderatorToken);
|
||||
const firstRecordingId = firstStartResponse.body.recordingId;
|
||||
|
||||
expectValidStartRecordingResponse(firstStartResponse, room.roomId, room.roomName);
|
||||
|
||||
const firstStopResponse = await stopRecording(firstRecordingId, moderatorCookie);
|
||||
const firstStopResponse = await stopRecording(firstRecordingId, moderatorToken);
|
||||
expectValidStopRecordingResponse(firstStopResponse, firstRecordingId, room.roomId, room.roomName);
|
||||
|
||||
const secondStartResponse = await startRecording(room.roomId, moderatorCookie);
|
||||
const secondStartResponse = await startRecording(room.roomId, moderatorToken);
|
||||
expectValidStartRecordingResponse(secondStartResponse, room.roomId, room.roomName);
|
||||
const secondRecordingId = secondStartResponse.body.recordingId;
|
||||
|
||||
const secondStopResponse = await stopRecording(secondRecordingId, moderatorCookie);
|
||||
const secondStopResponse = await stopRecording(secondRecordingId, moderatorToken);
|
||||
expectValidStopRecordingResponse(secondStopResponse, secondRecordingId, room.roomId, room.roomName);
|
||||
});
|
||||
|
||||
@ -102,8 +102,8 @@ describe('Recording API Tests', () => {
|
||||
const roomDataA = context.getRoomByIndex(0)!;
|
||||
const roomDataB = context.getRoomByIndex(1)!;
|
||||
|
||||
const firstResponse = await startRecording(roomDataA.room.roomId, roomDataA.moderatorCookie);
|
||||
const secondResponse = await startRecording(roomDataB.room.roomId, roomDataB.moderatorCookie);
|
||||
const firstResponse = await startRecording(roomDataA.room.roomId, roomDataA.moderatorToken);
|
||||
const secondResponse = await startRecording(roomDataB.room.roomId, roomDataB.moderatorToken);
|
||||
|
||||
expectValidStartRecordingResponse(firstResponse, roomDataA.room.roomId, roomDataA.room.roomName);
|
||||
expectValidStartRecordingResponse(secondResponse, roomDataB.room.roomId, roomDataB.room.roomName);
|
||||
@ -112,8 +112,8 @@ describe('Recording API Tests', () => {
|
||||
const secondRecordingId = secondResponse.body.recordingId;
|
||||
|
||||
const [firstStopResponse, secondStopResponse] = await Promise.all([
|
||||
stopRecording(firstRecordingId, roomDataA.moderatorCookie),
|
||||
stopRecording(secondRecordingId, roomDataB.moderatorCookie)
|
||||
stopRecording(firstRecordingId, roomDataA.moderatorToken),
|
||||
stopRecording(secondRecordingId, roomDataB.moderatorToken)
|
||||
]);
|
||||
expectValidStopRecordingResponse(
|
||||
firstStopResponse,
|
||||
@ -134,16 +134,16 @@ describe('Recording API Tests', () => {
|
||||
beforeAll(async () => {
|
||||
// Create a room without participants
|
||||
context = await setupMultiRoomTestContext(1, false);
|
||||
({ room, moderatorCookie } = context.getRoomByIndex(0)!);
|
||||
({ room, moderatorToken } = context.getRoomByIndex(0)!);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await disconnectFakeParticipants();
|
||||
await stopAllRecordings(moderatorCookie);
|
||||
await stopAllRecordings(moderatorToken);
|
||||
});
|
||||
|
||||
it('should accept valid roomId but reject with 409', async () => {
|
||||
const response = await startRecording(room.roomId, moderatorCookie);
|
||||
const response = await startRecording(room.roomId, moderatorToken);
|
||||
// Room exists but it has no participants
|
||||
expect(response.status).toBe(409);
|
||||
expect(response.body.message).toContain(`Room '${room.roomId}' has no participants`);
|
||||
@ -151,7 +151,7 @@ describe('Recording API Tests', () => {
|
||||
|
||||
it('should sanitize roomId and reject the request with 409 due to no participants', async () => {
|
||||
const malformedRoomId = ' .<!?' + room.roomId + ' ';
|
||||
const response = await startRecording(malformedRoomId, moderatorCookie);
|
||||
const response = await startRecording(malformedRoomId, moderatorToken);
|
||||
|
||||
console.log('Response:', response.body);
|
||||
expect(response.status).toBe(409);
|
||||
@ -159,25 +159,25 @@ describe('Recording API Tests', () => {
|
||||
});
|
||||
|
||||
it('should reject request with roomId that becomes empty after sanitization', async () => {
|
||||
const response = await startRecording('!@#$%^&*()', moderatorCookie);
|
||||
const response = await startRecording('!@#$%^&*()', moderatorToken);
|
||||
|
||||
expectValidationError(response, 'roomId', 'cannot be empty after sanitization');
|
||||
});
|
||||
|
||||
it('should reject request with non-string roomId', async () => {
|
||||
const response = await startRecording(123 as unknown as string, moderatorCookie);
|
||||
const response = await startRecording(123 as unknown as string, moderatorToken);
|
||||
expectValidationError(response, 'roomId', 'Expected string');
|
||||
});
|
||||
|
||||
it('should reject request with very long roomId', async () => {
|
||||
const longRoomId = 'a'.repeat(101);
|
||||
const response = await startRecording(longRoomId, moderatorCookie);
|
||||
const response = await startRecording(longRoomId, moderatorToken);
|
||||
|
||||
expectValidationError(response, 'roomId', 'cannot exceed 100 characters');
|
||||
});
|
||||
|
||||
it('should handle room that does not exist', async () => {
|
||||
const response = await startRecording('non-existing-room-id', moderatorCookie);
|
||||
const response = await startRecording('non-existing-room-id', moderatorToken);
|
||||
const error = errorRoomNotFound('non-existing-room-id');
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body).toEqual({
|
||||
@ -188,14 +188,14 @@ describe('Recording API Tests', () => {
|
||||
|
||||
it('should return 409 when recording is already in progress', async () => {
|
||||
await joinFakeParticipant(room.roomId, 'fakeParticipantId');
|
||||
const firstResponse = await startRecording(room.roomId, moderatorCookie);
|
||||
const firstResponse = await startRecording(room.roomId, moderatorToken);
|
||||
const recordingId = firstResponse.body.recordingId;
|
||||
expectValidStartRecordingResponse(firstResponse, room.roomId, room.roomName);
|
||||
|
||||
const secondResponse = await startRecording(room!.roomId, moderatorCookie);
|
||||
const secondResponse = await startRecording(room!.roomId, moderatorToken);
|
||||
expect(secondResponse.status).toBe(409);
|
||||
expect(secondResponse.body.message).toContain('already');
|
||||
const stopResponse = await stopRecording(recordingId, moderatorCookie);
|
||||
const stopResponse = await stopRecording(recordingId, moderatorToken);
|
||||
expectValidStopRecordingResponse(stopResponse, recordingId, room.roomId, room.roomName);
|
||||
});
|
||||
|
||||
@ -204,7 +204,7 @@ describe('Recording API Tests', () => {
|
||||
RECORDING_STARTED_TIMEOUT: '1s'
|
||||
});
|
||||
await joinFakeParticipant(room.roomId, 'fakeParticipantId');
|
||||
const response = await startRecording(room.roomId, moderatorCookie);
|
||||
const response = await startRecording(room.roomId, moderatorToken);
|
||||
expect(response.status).toBe(503);
|
||||
expect(response.body.message).toContain('timed out while starting');
|
||||
setInternalConfig({
|
||||
|
||||
@ -14,7 +14,7 @@ import { setupMultiRoomTestContext, TestContext } from '../../../helpers/test-sc
|
||||
|
||||
describe('Recording API Tests', () => {
|
||||
let context: TestContext | null = null;
|
||||
let room: MeetRoom, moderatorCookie: string;
|
||||
let room: MeetRoom, moderatorToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
startTestServer();
|
||||
@ -22,7 +22,7 @@ describe('Recording API Tests', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await stopAllRecordings(moderatorCookie);
|
||||
await stopAllRecordings(moderatorToken);
|
||||
await disconnectFakeParticipants();
|
||||
await Promise.all([deleteAllRooms(), deleteAllRecordings()]);
|
||||
});
|
||||
@ -32,13 +32,13 @@ describe('Recording API Tests', () => {
|
||||
beforeAll(async () => {
|
||||
// Create a room and join a participant
|
||||
context = await setupMultiRoomTestContext(1, true);
|
||||
({ room, moderatorCookie } = context.getRoomByIndex(0)!);
|
||||
const response = await startRecording(room.roomId, moderatorCookie);
|
||||
({ room, moderatorToken } = context.getRoomByIndex(0)!);
|
||||
const response = await startRecording(room.roomId, moderatorToken);
|
||||
recordingId = response.body.recordingId;
|
||||
});
|
||||
|
||||
it('should stop an active recording and return 202', async () => {
|
||||
const response = await stopRecording(recordingId, moderatorCookie);
|
||||
const response = await stopRecording(recordingId, moderatorToken);
|
||||
expectValidStopRecordingResponse(response, recordingId, room.roomId, room.roomName);
|
||||
});
|
||||
|
||||
@ -46,18 +46,18 @@ describe('Recording API Tests', () => {
|
||||
const context = await setupMultiRoomTestContext(2, true);
|
||||
const roomDataA = context.getRoomByIndex(0);
|
||||
const roomDataB = context.getRoomByIndex(1);
|
||||
const responseA = await startRecording(roomDataA!.room.roomId, roomDataA?.moderatorCookie);
|
||||
const responseB = await startRecording(roomDataB!.room.roomId, roomDataB?.moderatorCookie);
|
||||
const responseA = await startRecording(roomDataA!.room.roomId, roomDataA!.moderatorToken);
|
||||
const responseB = await startRecording(roomDataB!.room.roomId, roomDataB!.moderatorToken);
|
||||
const recordingIdA = responseA.body.recordingId;
|
||||
const recordingIdB = responseB.body.recordingId;
|
||||
const stopResponseA = await stopRecording(recordingIdA, roomDataA?.moderatorCookie);
|
||||
const stopResponseA = await stopRecording(recordingIdA, roomDataA!.moderatorToken);
|
||||
expectValidStopRecordingResponse(
|
||||
stopResponseA,
|
||||
recordingIdA,
|
||||
roomDataA!.room.roomId,
|
||||
roomDataA!.room.roomName
|
||||
);
|
||||
const stopResponseB = await stopRecording(recordingIdB, roomDataB?.moderatorCookie);
|
||||
const stopResponseB = await stopRecording(recordingIdB, roomDataB!.moderatorToken);
|
||||
expectValidStopRecordingResponse(
|
||||
stopResponseB,
|
||||
recordingIdB,
|
||||
@ -68,7 +68,7 @@ describe('Recording API Tests', () => {
|
||||
|
||||
describe('Stop Recording Validation failures', () => {
|
||||
it('should return 404 when recordingId does not exist', async () => {
|
||||
const response = await stopRecording(`${room.roomId}--EG_123--444`, moderatorCookie);
|
||||
const response = await stopRecording(`${room.roomId}--EG_123--444`, moderatorToken);
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.error).toBe('Recording Error');
|
||||
expect(response.body.message).toContain('not found');
|
||||
@ -76,17 +76,17 @@ describe('Recording API Tests', () => {
|
||||
|
||||
it('should return 400 when recording is already stopped', async () => {
|
||||
// First stop the recording
|
||||
await stopRecording(recordingId, moderatorCookie);
|
||||
await stopRecording(recordingId, moderatorToken);
|
||||
|
||||
// Try to stop it again
|
||||
const response = await stopRecording(recordingId, moderatorCookie);
|
||||
const response = await stopRecording(recordingId, moderatorToken);
|
||||
|
||||
console.log('Response:', response.body);
|
||||
expectErrorResponse(response, 409, '', `Recording '${recordingId}' is already stopped`);
|
||||
});
|
||||
|
||||
it('should return 404 when recordingId is not in the correct format', async () => {
|
||||
const response = await stopRecording('invalid-recording-id', moderatorCookie);
|
||||
const response = await stopRecording('invalid-recording-id', moderatorToken);
|
||||
expect(response.status).toBe(422);
|
||||
expect(response.body.error).toBe('Unprocessable Entity');
|
||||
expect(response.body.message).toContain('Invalid request');
|
||||
|
||||
@ -154,13 +154,13 @@ describe('Room API Tests', () => {
|
||||
});
|
||||
|
||||
it('should handle deletion when specifying withMeeting and withRecordings parameters', async () => {
|
||||
const [room1, { room: room2 }, { room: room3 }, { room: room4, moderatorCookie }] = await Promise.all([
|
||||
const [room1, { room: room2 }, { room: room3 }, { room: room4, moderatorToken }] = await Promise.all([
|
||||
createRoom(), // Room without active meeting or recordings
|
||||
setupSingleRoom(true), // Room with active meeting
|
||||
setupSingleRoomWithRecording(true), // Room with active meeting and recordings
|
||||
setupSingleRoomWithRecording(true) // Room with recordings
|
||||
]);
|
||||
await endMeeting(room4.roomId, moderatorCookie);
|
||||
await endMeeting(room4.roomId, moderatorToken);
|
||||
const fakeRoomId = 'fakeRoomId'; // Non-existing room
|
||||
|
||||
const response = await bulkDeleteRooms(
|
||||
|
||||
@ -3,13 +3,14 @@ import { Express } from 'express';
|
||||
import ms from 'ms';
|
||||
import request from 'supertest';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
|
||||
import {
|
||||
MeetRecordingAccess,
|
||||
MeetRoomDeletionPolicyWithMeeting,
|
||||
MeetRoomDeletionPolicyWithRecordings
|
||||
} from '../../../../src/typings/ce/index.js';
|
||||
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
|
||||
import { createRoom, deleteAllRooms, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import { createRoom, deleteAllRooms, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
|
||||
const ROOMS_PATH = `${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`;
|
||||
|
||||
@ -17,11 +18,9 @@ describe('Room API Tests', () => {
|
||||
const validAutoDeletionDate = Date.now() + ms('2h');
|
||||
|
||||
let app: Express;
|
||||
let adminCookie: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -81,7 +80,11 @@ describe('Room API Tests', () => {
|
||||
roomName: 'TestRoom'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
// Check that the error message contains the positive number validation
|
||||
expect(response.body.error).toContain('Unprocessable Entity');
|
||||
@ -94,7 +97,11 @@ describe('Room API Tests', () => {
|
||||
roomName: 'TestRoom'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(response.body.error).toContain('Unprocessable Entity');
|
||||
expect(JSON.stringify(response.body.details)).toContain(
|
||||
@ -108,7 +115,11 @@ describe('Room API Tests', () => {
|
||||
roomName: 'TestRoom'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected number');
|
||||
});
|
||||
@ -119,7 +130,11 @@ describe('Room API Tests', () => {
|
||||
roomName: 'TestRoom'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected number');
|
||||
});
|
||||
@ -130,7 +145,11 @@ describe('Room API Tests', () => {
|
||||
roomName: 'TestRoom'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected number');
|
||||
});
|
||||
@ -142,7 +161,11 @@ describe('Room API Tests', () => {
|
||||
autoDeletionPolicy: 'invalid-policy'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected object');
|
||||
});
|
||||
@ -157,7 +180,11 @@ describe('Room API Tests', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Invalid enum value');
|
||||
});
|
||||
@ -172,7 +199,11 @@ describe('Room API Tests', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain(
|
||||
'FAIL policy is not allowed for withMeeting auto-deletion policy'
|
||||
@ -189,7 +220,11 @@ describe('Room API Tests', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain(
|
||||
'FAIL policy is not allowed for withRecordings auto-deletion policy'
|
||||
@ -202,7 +237,11 @@ describe('Room API Tests', () => {
|
||||
autoDeletionDate: validAutoDeletionDate
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected string');
|
||||
});
|
||||
@ -213,7 +252,11 @@ describe('Room API Tests', () => {
|
||||
autoDeletionDate: validAutoDeletionDate
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected string');
|
||||
});
|
||||
@ -225,7 +268,11 @@ describe('Room API Tests', () => {
|
||||
config: 'invalid-config'
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected object');
|
||||
});
|
||||
@ -246,7 +293,11 @@ describe('Room API Tests', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('Expected boolean');
|
||||
});
|
||||
@ -255,7 +306,7 @@ describe('Room API Tests', () => {
|
||||
// In this case, instead of sending JSON object, send an invalid JSON string.
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send('{"roomName": "TestRoom",') // invalid JSON syntax
|
||||
.expect(400);
|
||||
@ -271,7 +322,11 @@ describe('Room API Tests', () => {
|
||||
autoDeletionDate: validAutoDeletionDate
|
||||
};
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send(payload).expect(422);
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
|
||||
.send(payload)
|
||||
.expect(422);
|
||||
|
||||
expect(JSON.stringify(response.body.details)).toContain('roomName cannot exceed 50 characters');
|
||||
});
|
||||
|
||||
@ -51,14 +51,14 @@ describe('Room API Tests', () => {
|
||||
describe('with active meeting but no recordings', () => {
|
||||
let roomId: string;
|
||||
let roomName: string;
|
||||
let moderatorCookie: string;
|
||||
let moderatorToken: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create a room with an active meeting
|
||||
const { room, moderatorCookie: cookie } = await setupSingleRoom(true);
|
||||
const { room, moderatorToken: token } = await setupSingleRoom(true);
|
||||
roomId = room.roomId;
|
||||
roomName = room.roomName;
|
||||
moderatorCookie = cookie;
|
||||
moderatorToken = token;
|
||||
});
|
||||
|
||||
it('should return 200 with successCode=room_with_active_meeting_deleted when withMeeting=force', async () => {
|
||||
@ -96,7 +96,7 @@ describe('Room API Tests', () => {
|
||||
);
|
||||
|
||||
// End meeting and check the room is deleted
|
||||
await endMeeting(roomId, moderatorCookie);
|
||||
await endMeeting(roomId, moderatorToken);
|
||||
const getResponse = await getRoom(roomId);
|
||||
expect(getResponse.status).toBe(404);
|
||||
});
|
||||
@ -114,10 +114,10 @@ describe('Room API Tests', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create a room with recordings and end the meeting
|
||||
const { room, moderatorCookie } = await setupSingleRoomWithRecording(true);
|
||||
const { room, moderatorToken } = await setupSingleRoomWithRecording(true);
|
||||
roomId = room.roomId;
|
||||
roomName = room.roomName;
|
||||
await endMeeting(roomId, moderatorCookie);
|
||||
await endMeeting(roomId, moderatorToken);
|
||||
});
|
||||
|
||||
it('should return 200 with successCode=room_and_recordings_deleted when withRecording=force', async () => {
|
||||
@ -171,14 +171,14 @@ describe('Room API Tests', () => {
|
||||
describe('with active meeting and recordings', () => {
|
||||
let roomId: string;
|
||||
let roomName: string;
|
||||
let moderatorCookie: string;
|
||||
let moderatorToken: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create a room with recordings, keep the meeting active
|
||||
const { room, moderatorCookie: cookie } = await setupSingleRoomWithRecording(true);
|
||||
const { room, moderatorToken: token } = await setupSingleRoomWithRecording(true);
|
||||
roomId = room.roomId;
|
||||
roomName = room.roomName;
|
||||
moderatorCookie = cookie;
|
||||
moderatorToken = token;
|
||||
});
|
||||
|
||||
it('should return 200 with successCode=room_with_active_meeting_and_recordings_deleted when withMeeting=force and withRecording=force', async () => {
|
||||
@ -269,7 +269,7 @@ describe('Room API Tests', () => {
|
||||
);
|
||||
|
||||
// End meeting and check the room and recordings are deleted
|
||||
await endMeeting(roomId, moderatorCookie);
|
||||
await endMeeting(roomId, moderatorToken);
|
||||
const roomResponse = await getRoom(roomId);
|
||||
expect(roomResponse.status).toBe(404);
|
||||
const recordingsResponse = await getAllRecordings({ roomId, maxItems: 1 });
|
||||
@ -297,7 +297,7 @@ describe('Room API Tests', () => {
|
||||
);
|
||||
|
||||
// End meeting and check that the room is closed and recordings are not deleted
|
||||
await endMeeting(roomId, moderatorCookie);
|
||||
await endMeeting(roomId, moderatorToken);
|
||||
const roomResponse = await getRoom(roomId);
|
||||
expect(roomResponse.status).toBe(200);
|
||||
expectValidRoom(
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
endMeeting,
|
||||
generateParticipantTokenCookie,
|
||||
generateParticipantToken,
|
||||
getRoom,
|
||||
joinFakeParticipant,
|
||||
runRoomGarbageCollector,
|
||||
@ -102,8 +102,8 @@ describe('Room Garbage Collector Tests', () => {
|
||||
|
||||
// End the meeting
|
||||
const { moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const moderatorCookie = await generateParticipantTokenCookie(room.roomId, moderatorSecret, 'moderator');
|
||||
await endMeeting(room.roomId, moderatorCookie);
|
||||
const moderatorToken = await generateParticipantToken(room.roomId, moderatorSecret, 'moderator');
|
||||
await endMeeting(room.roomId, moderatorToken);
|
||||
|
||||
// Verify that the room is deleted
|
||||
response = await getRoom(room.roomId);
|
||||
@ -180,8 +180,8 @@ describe('Room Garbage Collector Tests', () => {
|
||||
|
||||
// Start recording
|
||||
const { moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room1);
|
||||
const moderatorCookie = await generateParticipantTokenCookie(room1.roomId, moderatorSecret, 'moderator');
|
||||
await startRecording(room1.roomId, moderatorCookie);
|
||||
const moderatorToken = await generateParticipantToken(room1.roomId, moderatorSecret, 'moderator');
|
||||
await startRecording(room1.roomId, moderatorToken);
|
||||
|
||||
await runRoomGarbageCollector();
|
||||
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { AuthTransportMode } from '../../../../src/typings/ce/index.js';
|
||||
import { ParticipantRole } from '../../../../src/typings/ce/participant.js';
|
||||
import { MeetRecordingAccess } from '../../../../src/typings/ce/room-config.js';
|
||||
import { expectValidRecordingTokenResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
deleteAllRecordings,
|
||||
deleteAllRooms,
|
||||
deleteRoom,
|
||||
disconnectFakeParticipants,
|
||||
generateRecordingToken,
|
||||
extractCookieFromHeaders,
|
||||
generateRecordingTokenRequest,
|
||||
startTestServer,
|
||||
updateRecordingAccessConfigInRoom
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
@ -30,46 +33,60 @@ describe('Room API Tests', () => {
|
||||
it('should generate a recording token with canRetrieve and canDelete permissions when using the moderator secret and recording access is admin_moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
const response = await generateRecordingTokenRequest(roomData.room.roomId, roomData.moderatorSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.MODERATOR, true, true);
|
||||
});
|
||||
|
||||
it('should generate a recording token with canRetrieve and canDelete permissions when using the moderator secret and recording access is admin_moderator_speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
const response = await generateRecordingTokenRequest(roomData.room.roomId, roomData.moderatorSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.MODERATOR, true, true);
|
||||
});
|
||||
|
||||
it('should generate a recording token without any permissions when using the speaker secret and recording access is admin_moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
const response = await generateRecordingTokenRequest(roomData.room.roomId, roomData.speakerSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.SPEAKER, false, false);
|
||||
});
|
||||
|
||||
it('should generate a recording token with canRetrieve permission but not canDelete when using the speaker secret and recording access is admin_moderator_speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
const response = await generateRecordingTokenRequest(roomData.room.roomId, roomData.speakerSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.SPEAKER, true, false);
|
||||
});
|
||||
|
||||
it('should succeed even if the room is deleted', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
await deleteRoom(roomData.room.roomId);
|
||||
it('should generate a recording token and store it in a cookie when in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
// Generate the recording token
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER);
|
||||
const response = await generateRecordingTokenRequest(roomData.room.roomId, roomData.moderatorSecret);
|
||||
expectValidRecordingTokenResponse(response, roomData.room.roomId, ParticipantRole.MODERATOR, true, true);
|
||||
|
||||
// Recreate the room with recording
|
||||
roomData = await setupSingleRoomWithRecording(true);
|
||||
// Check that the token is included in a cookie
|
||||
const recordingTokenCookie = extractCookieFromHeaders(
|
||||
response,
|
||||
INTERNAL_CONFIG.RECORDING_TOKEN_COOKIE_NAME
|
||||
);
|
||||
expect(recordingTokenCookie).toBeDefined();
|
||||
expect(recordingTokenCookie).toContain(response.body.token);
|
||||
expect(recordingTokenCookie).toContain('HttpOnly');
|
||||
expect(recordingTokenCookie).toContain('SameSite=None');
|
||||
expect(recordingTokenCookie).toContain('Secure');
|
||||
expect(recordingTokenCookie).toContain('Path=/');
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail with a 404 error if there are no recordings in the room', async () => {
|
||||
await deleteAllRecordings();
|
||||
|
||||
const response = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
const response = await generateRecordingTokenRequest(roomData.room.roomId, roomData.moderatorSecret);
|
||||
expect(response.status).toBe(404);
|
||||
|
||||
// Recreate the room with recording
|
||||
@ -77,12 +94,12 @@ describe('Room API Tests', () => {
|
||||
});
|
||||
|
||||
it('should fail with a 404 error if the room does not exist', async () => {
|
||||
const response = await generateRecordingToken('non-existent-room-id', roomData.moderatorSecret);
|
||||
const response = await generateRecordingTokenRequest('non-existent-room-id', roomData.moderatorSecret);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
|
||||
it('should fail with a 400 error if the secret is invalid', async () => {
|
||||
const response = await generateRecordingToken(roomData.room.roomId, 'invalid-secret');
|
||||
const response = await generateRecordingTokenRequest(roomData.room.roomId, 'invalid-secret');
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
});
|
||||
|
||||
@ -102,7 +102,7 @@ describe('Room API Tests', () => {
|
||||
const response = await getRoom(
|
||||
roomData.room.roomId,
|
||||
undefined,
|
||||
roomData.speakerCookie,
|
||||
roomData.speakerToken,
|
||||
ParticipantRole.SPEAKER
|
||||
);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
@ -68,7 +68,7 @@ describe('Room API Tests', () => {
|
||||
expect(getResponse.body.meetingEndAction).toEqual('close');
|
||||
|
||||
// End meeting and verify closed status
|
||||
await endMeeting(roomData.room.roomId, roomData.moderatorCookie);
|
||||
await endMeeting(roomData.room.roomId, roomData.moderatorToken);
|
||||
|
||||
getResponse = await getRoom(roomData.room.roomId);
|
||||
expect(getResponse.status).toBe(200);
|
||||
|
||||
@ -5,7 +5,15 @@ import { container } from '../../../../src/config/dependency-injector.config.js'
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { MeetStorageService } from '../../../../src/services/index.js';
|
||||
import { expectValidationError } from '../../../helpers/assertion-helpers.js';
|
||||
import { generateApiKey, getApiKeys, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
extractCookieFromHeaders,
|
||||
generateApiKey,
|
||||
getApiKeys,
|
||||
loginUser,
|
||||
startTestServer
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
import { AuthTransportMode } from '../../../../src/typings/ce/index.js';
|
||||
|
||||
const AUTH_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/auth`;
|
||||
|
||||
@ -28,17 +36,31 @@ describe('Authentication API Tests', () => {
|
||||
|
||||
expect(response.body).toHaveProperty('message');
|
||||
|
||||
// Check for access token and refresh token cookies
|
||||
expect(response.headers['set-cookie']).toBeDefined();
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const accessTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME}=`)
|
||||
);
|
||||
const refreshTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME}=`)
|
||||
);
|
||||
// Check for access and refresh tokens
|
||||
expect(response.body).toHaveProperty('accessToken');
|
||||
expect(response.body).toHaveProperty('refreshToken');
|
||||
});
|
||||
|
||||
it('should successfully login and set cookies in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${AUTH_PATH}/login`)
|
||||
.send({
|
||||
username: 'admin',
|
||||
password: 'admin'
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
// Check for access and refresh token cookies
|
||||
const accessTokenCookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
|
||||
const refreshTokenCookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME);
|
||||
expect(accessTokenCookie).toBeDefined();
|
||||
expect(refreshTokenCookie).toBeDefined();
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should return 404 for invalid credentials', async () => {
|
||||
@ -107,17 +129,24 @@ describe('Authentication API Tests', () => {
|
||||
|
||||
expect(response.body).toHaveProperty('message');
|
||||
expect(response.body.message).toBe('Logout successful');
|
||||
});
|
||||
|
||||
// Check for cleared cookies
|
||||
const cookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const accessTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME}=;`)
|
||||
);
|
||||
const refreshTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME}=;`)
|
||||
);
|
||||
it('should successfully logout and clear cookies in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
const response = await request(app).post(`${AUTH_PATH}/logout`).expect(200);
|
||||
|
||||
// Check that the access and refresh token cookies are cleared
|
||||
const accessTokenCookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
|
||||
const refreshTokenCookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME);
|
||||
expect(accessTokenCookie).toBeDefined();
|
||||
expect(accessTokenCookie).toContain('Expires=Thu, 01 Jan 1970 00:00:00 GMT');
|
||||
expect(refreshTokenCookie).toBeDefined();
|
||||
expect(refreshTokenCookie).toContain('Expires=Thu, 01 Jan 1970 00:00:00 GMT');
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
});
|
||||
|
||||
@ -132,24 +161,48 @@ describe('Authentication API Tests', () => {
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const cookies = loginResponse.headers['set-cookie'] as unknown as string[];
|
||||
const refreshTokenCookie = cookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME}=`)
|
||||
) as string;
|
||||
expect(loginResponse.body).toHaveProperty('refreshToken');
|
||||
const refreshToken = loginResponse.body.refreshToken;
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${AUTH_PATH}/refresh`)
|
||||
.set('Cookie', [refreshTokenCookie])
|
||||
.set(INTERNAL_CONFIG.REFRESH_TOKEN_HEADER, `Bearer ${refreshToken}`)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toHaveProperty('message');
|
||||
expect(response.body).toHaveProperty('accessToken');
|
||||
});
|
||||
|
||||
// Check for new access token cookie
|
||||
const newCookies = response.headers['set-cookie'] as unknown as string[];
|
||||
const newAccessTokenCookie = newCookies.find((cookie) =>
|
||||
cookie.startsWith(`${INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME}=`)
|
||||
it('should successfully refresh token and set new access token cookie in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// First, login to get a valid refresh token cookie
|
||||
const loginResponse = await request(app)
|
||||
.post(`${AUTH_PATH}/login`)
|
||||
.send({
|
||||
username: 'admin',
|
||||
password: 'admin'
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const refreshTokenCookie = extractCookieFromHeaders(
|
||||
loginResponse,
|
||||
INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME
|
||||
);
|
||||
expect(refreshTokenCookie).toBeDefined();
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${AUTH_PATH}/refresh`)
|
||||
.set('Cookie', refreshTokenCookie!)
|
||||
.expect(200);
|
||||
|
||||
// Check that a new access token cookie is set
|
||||
const newAccessTokenCookie = extractCookieFromHeaders(response, INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
|
||||
expect(newAccessTokenCookie).toBeDefined();
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should return 400 when no refresh token is provided', async () => {
|
||||
@ -162,7 +215,7 @@ describe('Authentication API Tests', () => {
|
||||
it('should return 400 when refresh token is invalid', async () => {
|
||||
const response = await request(app)
|
||||
.post(`${AUTH_PATH}/refresh`)
|
||||
.set('Cookie', `${INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME}=invalidtoken`)
|
||||
.set(INTERNAL_CONFIG.REFRESH_TOKEN_HEADER, 'Bearer invalidtoken')
|
||||
.expect(400);
|
||||
|
||||
expect(response.body).toHaveProperty('message');
|
||||
@ -171,10 +224,10 @@ describe('Authentication API Tests', () => {
|
||||
});
|
||||
|
||||
describe('API Keys Management', () => {
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -190,7 +243,10 @@ describe('Authentication API Tests', () => {
|
||||
};
|
||||
|
||||
it('should create a new API key', async () => {
|
||||
const response = await request(app).post(`${AUTH_PATH}/api-keys`).set('Cookie', adminCookie).expect(201);
|
||||
const response = await request(app)
|
||||
.post(`${AUTH_PATH}/api-keys`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.expect(201);
|
||||
|
||||
expect(response.body).toHaveProperty('key');
|
||||
expect(response.body).toHaveProperty('creationDate');
|
||||
@ -233,7 +289,10 @@ describe('Authentication API Tests', () => {
|
||||
|
||||
it('should delete all API keys', async () => {
|
||||
const apiKey = await generateApiKey();
|
||||
await request(app).delete(`${AUTH_PATH}/api-keys`).set('Cookie', adminCookie).expect(200);
|
||||
await request(app)
|
||||
.delete(`${AUTH_PATH}/api-keys`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.expect(200);
|
||||
|
||||
// Confirm deletion
|
||||
const getResponse = await getApiKeys();
|
||||
@ -246,6 +305,21 @@ describe('Authentication API Tests', () => {
|
||||
expect(apiResponse.status).toBe(401);
|
||||
});
|
||||
|
||||
it('should succeed API key endpoints for authenticated admin user in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
await request(app).post(`${AUTH_PATH}/api-keys`).set('Cookie', adminCookie).expect(201);
|
||||
await request(app).get(`${AUTH_PATH}/api-keys`).set('Cookie', adminCookie).expect(200);
|
||||
await request(app).delete(`${AUTH_PATH}/api-keys`).set('Cookie', adminCookie).expect(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should reject API key endpoints for unauthenticated users', async () => {
|
||||
await request(app).post(`${AUTH_PATH}/api-keys`).expect(401);
|
||||
await request(app).get(`${AUTH_PATH}/api-keys`).expect(401);
|
||||
|
||||
@ -6,7 +6,7 @@ import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
|
||||
import { MeetStorageService } from '../../../../src/services/index.js';
|
||||
import { AuthMode, AuthTransportMode, AuthType, MeetRoomThemeMode } from '../../../../src/typings/ce/index.js';
|
||||
import { loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import { changeAuthTransportMode, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
|
||||
const CONFIG_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config`;
|
||||
|
||||
@ -17,11 +17,11 @@ const restoreGlobalConfig = async () => {
|
||||
|
||||
describe('Global Config API Security Tests', () => {
|
||||
let app: Express;
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
describe('Update Webhook Config Tests', () => {
|
||||
@ -39,12 +39,29 @@ describe('Global Config API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${CONFIG_PATH}/webhooks`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send(webhookConfig);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
await restoreGlobalConfig();
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${CONFIG_PATH}/webhooks`)
|
||||
.set('Cookie', adminCookie)
|
||||
.send(webhookConfig);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// This method already restores the config to default (header mode)
|
||||
await restoreGlobalConfig();
|
||||
});
|
||||
|
||||
@ -63,8 +80,24 @@ describe('Global Config API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${CONFIG_PATH}/webhooks`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app).get(`${CONFIG_PATH}/webhooks`).set('Cookie', adminCookie);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -79,7 +112,7 @@ describe('Global Config API Security Tests', () => {
|
||||
authMethod: {
|
||||
type: AuthType.SINGLE_USER
|
||||
},
|
||||
authTransportMode: AuthTransportMode.COOKIE,
|
||||
authTransportMode: AuthTransportMode.HEADER,
|
||||
authModeToAccessRoom: AuthMode.ALL_USERS
|
||||
}
|
||||
};
|
||||
@ -93,12 +126,29 @@ describe('Global Config API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${CONFIG_PATH}/security`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send(securityConfig);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
await restoreGlobalConfig();
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${CONFIG_PATH}/security`)
|
||||
.set('Cookie', adminCookie)
|
||||
.send(securityConfig);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// This method already restores the config to default (header mode)
|
||||
await restoreGlobalConfig();
|
||||
});
|
||||
|
||||
@ -137,6 +187,22 @@ describe('Global Config API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${CONFIG_PATH}/rooms/appearance`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send(appearanceConfig);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
await restoreGlobalConfig();
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin in cookie mode', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${CONFIG_PATH}/rooms/appearance`)
|
||||
.set('Cookie', adminCookie)
|
||||
|
||||
@ -3,9 +3,10 @@ import { Express } from 'express';
|
||||
import request from 'supertest';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { LIVEKIT_URL, MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
|
||||
import { MeetTokenMetadata, ParticipantRole } from '../../../../src/typings/ce';
|
||||
import { AuthTransportMode, MeetTokenMetadata, ParticipantRole } from '../../../../src/typings/ce';
|
||||
import { getPermissions } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
loginUser,
|
||||
@ -18,12 +19,12 @@ const MEETINGS_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/meetings`;
|
||||
|
||||
describe('Meeting API Security Tests', () => {
|
||||
let app: Express;
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
let roomData: RoomData;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
@ -46,24 +47,41 @@ describe('Meeting API Security Tests', () => {
|
||||
it('should fail when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator and token is sent in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Create a new room to obtain participant token in cookie mode
|
||||
const newRoomData = await setupSingleRoom(true);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${newRoomData.room.roomId}`)
|
||||
.set('Cookie', newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when participant is moderator of a different room', async () => {
|
||||
const newRoomData = await setupSingleRoom();
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}`)
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -71,7 +89,7 @@ describe('Meeting API Security Tests', () => {
|
||||
it('should fail when participant is speaker', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -106,7 +124,7 @@ describe('Meeting API Security Tests', () => {
|
||||
it('should fail when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_NAME}/role`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({ role });
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
@ -114,18 +132,46 @@ describe('Meeting API Security Tests', () => {
|
||||
it('should succeed when participant is moderator', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_NAME}/role`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send({ role });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator and token is sent in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Create a new room to obtain participant token in cookie mode
|
||||
const newRoomData = await setupSingleRoom(true);
|
||||
await updateParticipantMetadata(newRoomData.room.roomId, PARTICIPANT_NAME, {
|
||||
livekitUrl: LIVEKIT_URL,
|
||||
roles: [
|
||||
{
|
||||
role: ParticipantRole.SPEAKER,
|
||||
permissions: getPermissions(newRoomData.room.roomId, ParticipantRole.SPEAKER).openvidu
|
||||
}
|
||||
],
|
||||
selectedRole: ParticipantRole.SPEAKER
|
||||
});
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${MEETINGS_PATH}/${newRoomData.room.roomId}/participants/${PARTICIPANT_NAME}/role`)
|
||||
.set('Cookie', newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send({ role });
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when participant is moderator of a different room', async () => {
|
||||
const newRoomData = await setupSingleRoom();
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_NAME}/role`)
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR)
|
||||
.send({ role });
|
||||
expect(response.status).toBe(403);
|
||||
@ -134,7 +180,7 @@ describe('Meeting API Security Tests', () => {
|
||||
it('should fail when participant is speaker', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_NAME}/role`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER)
|
||||
.send({ role });
|
||||
expect(response.status).toBe(403);
|
||||
@ -154,24 +200,41 @@ describe('Meeting API Security Tests', () => {
|
||||
it('should fail when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_IDENTITY}`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_IDENTITY}`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator and token is sent in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Create a new room to obtain participant token in cookie mode
|
||||
const newRoomData = await setupSingleRoom(true);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${newRoomData.room.roomId}/participants/${PARTICIPANT_IDENTITY}`)
|
||||
.set('Cookie', newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when participant is moderator of a different room', async () => {
|
||||
const newRoomData = await setupSingleRoom();
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_IDENTITY}`)
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -179,7 +242,7 @@ describe('Meeting API Security Tests', () => {
|
||||
it('should fail when participant is speaker', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_IDENTITY}`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
@ -2,8 +2,9 @@ import { afterAll, beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { Express } from 'express';
|
||||
import request from 'supertest';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { AuthMode } from '../../../../src/typings/ce/index.js';
|
||||
import { AuthMode, AuthTransportMode } from '../../../../src/typings/ce/index.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
changeSecurityConfig,
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
@ -19,11 +20,11 @@ describe('Participant API Security Tests', () => {
|
||||
const PARTICIPANT_NAME = 'TEST_PARTICIPANT';
|
||||
|
||||
let app: Express;
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -74,12 +75,33 @@ describe('Participant API Security Tests', () => {
|
||||
it('should succeed when authentication is required for moderator, participant is moderator and authenticated', async () => {
|
||||
await changeSecurityConfig(AuthMode.MODERATORS_ONLY);
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName: PARTICIPANT_NAME
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when authentication is required for moderator, participant is moderator and authenticated via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName: PARTICIPANT_NAME
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when authentication is required for moderator and participant is moderator but not authenticated', async () => {
|
||||
@ -96,11 +118,14 @@ describe('Participant API Security Tests', () => {
|
||||
it('should succeed when authentication is required for all users, participant is speaker and authenticated', async () => {
|
||||
await changeSecurityConfig(AuthMode.ALL_USERS);
|
||||
|
||||
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
participantName: PARTICIPANT_NAME
|
||||
});
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
participantName: PARTICIPANT_NAME
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -118,11 +143,14 @@ describe('Participant API Security Tests', () => {
|
||||
it('should succeed when authentication is required for all users, participant is moderator and authenticated', async () => {
|
||||
await changeSecurityConfig(AuthMode.ALL_USERS);
|
||||
|
||||
const response = await request(app).post(`${PARTICIPANTS_PATH}/token`).set('Cookie', adminCookie).send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName: PARTICIPANT_NAME
|
||||
});
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
participantName: PARTICIPANT_NAME
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -158,7 +186,7 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
@ -173,7 +201,7 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
@ -188,7 +216,7 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
@ -203,7 +231,8 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', [adminCookie, roomData.moderatorCookie])
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
@ -213,12 +242,38 @@ describe('Participant API Security Tests', () => {
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when authentication is required for moderator, participant is moderator and authenticated via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
// Create a new room to obtain participant token in cookie mode
|
||||
const newRoomData = await setupSingleRoom(true);
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set('Cookie', newRoomData.moderatorToken)
|
||||
.send({
|
||||
roomId: newRoomData.room.roomId,
|
||||
secret: newRoomData.moderatorSecret,
|
||||
participantName: PARTICIPANT_NAME,
|
||||
participantIdentity: PARTICIPANT_NAME
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when authentication is required for moderator and participant is moderator but not authenticated', async () => {
|
||||
await changeSecurityConfig(AuthMode.MODERATORS_ONLY);
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
@ -233,7 +288,8 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', [adminCookie, roomData.speakerCookie])
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
@ -248,7 +304,7 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.speakerSecret,
|
||||
@ -263,7 +319,8 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', [adminCookie, roomData.moderatorCookie])
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
@ -278,7 +335,7 @@ describe('Participant API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${PARTICIPANTS_PATH}/token/refresh`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.send({
|
||||
roomId: roomData.room.roomId,
|
||||
secret: roomData.moderatorSecret,
|
||||
|
||||
@ -3,13 +3,14 @@ import { Express } from 'express';
|
||||
import request from 'supertest';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
|
||||
import { MeetRecordingAccess, ParticipantRole } from '../../../../src/typings/ce/index.js';
|
||||
import { AuthTransportMode, MeetRecordingAccess, ParticipantRole } from '../../../../src/typings/ce/index.js';
|
||||
import { expectValidStopRecordingResponse } from '../../../helpers/assertion-helpers.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
deleteAllRecordings,
|
||||
deleteAllRooms,
|
||||
disconnectFakeParticipants,
|
||||
generateRecordingTokenCookie,
|
||||
generateRecordingToken,
|
||||
getRecordingUrl,
|
||||
loginUser,
|
||||
startTestServer,
|
||||
@ -24,11 +25,11 @@ const INTERNAL_RECORDINGS_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/r
|
||||
|
||||
describe('Recording API Security Tests', () => {
|
||||
let app: Express;
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -55,7 +56,7 @@ describe('Recording API Security Tests', () => {
|
||||
const response = await request(app)
|
||||
.post(INTERNAL_RECORDINGS_PATH)
|
||||
.send({ roomId: roomData.room.roomId })
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
|
||||
@ -63,23 +64,51 @@ describe('Recording API Security Tests', () => {
|
||||
const response = await request(app)
|
||||
.post(INTERNAL_RECORDINGS_PATH)
|
||||
.send({ roomId: roomData.room.roomId })
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
// Stop recording to clean up
|
||||
const recordingId = response.body.recordingId;
|
||||
const stopResponse = await stopRecording(recordingId, roomData.moderatorCookie);
|
||||
const stopResponse = await stopRecording(recordingId, roomData.moderatorToken);
|
||||
expectValidStopRecordingResponse(stopResponse, recordingId, roomData.room.roomId, roomData.room.roomName);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator and token is sent in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Create a new room to obtain participant token in cookie mode
|
||||
const newRoomData = await setupSingleRoom(true);
|
||||
|
||||
const response = await request(app)
|
||||
.post(INTERNAL_RECORDINGS_PATH)
|
||||
.send({ roomId: newRoomData.room.roomId })
|
||||
.set('Cookie', newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
// Stop recording to clean up
|
||||
const recordingId = response.body.recordingId;
|
||||
const stopResponse = await stopRecording(recordingId, newRoomData.moderatorToken);
|
||||
expectValidStopRecordingResponse(
|
||||
stopResponse,
|
||||
recordingId,
|
||||
newRoomData.room.roomId,
|
||||
newRoomData.room.roomName
|
||||
);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when participant is moderator of a different room', async () => {
|
||||
const newRoomData = await setupSingleRoom();
|
||||
|
||||
const response = await request(app)
|
||||
.post(INTERNAL_RECORDINGS_PATH)
|
||||
.send({ roomId: roomData.room.roomId })
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -88,7 +117,7 @@ describe('Recording API Security Tests', () => {
|
||||
const response = await request(app)
|
||||
.post(INTERNAL_RECORDINGS_PATH)
|
||||
.send({ roomId: roomData.room.roomId })
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -102,7 +131,7 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await stopAllRecordings(roomData.moderatorCookie);
|
||||
await stopAllRecordings(roomData.moderatorToken);
|
||||
});
|
||||
|
||||
it('should fail when request includes API key', async () => {
|
||||
@ -116,24 +145,41 @@ describe('Recording API Security Tests', () => {
|
||||
it('should fail when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_RECORDINGS_PATH}/${roomData.recordingId}/stop`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(401);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator', async () => {
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_RECORDINGS_PATH}/${roomData.recordingId}/stop`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(202);
|
||||
});
|
||||
|
||||
it('should succeed when participant is moderator and token is sent in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Create a new room to obtain participant token in cookie mode
|
||||
const newRoomData = await setupSingleRoomWithRecording();
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_RECORDINGS_PATH}/${newRoomData.recordingId}/stop`)
|
||||
.set('Cookie', newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(202);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when participant is moderator of a different room', async () => {
|
||||
const newRoomData = await setupSingleRoom();
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_RECORDINGS_PATH}/${roomData.recordingId}/stop`)
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -141,7 +187,7 @@ describe('Recording API Security Tests', () => {
|
||||
it('should fail when participant is speaker', async () => {
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_RECORDINGS_PATH}/${roomData.recordingId}/stop`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -165,7 +211,9 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app).get(RECORDINGS_PATH).set('Cookie', adminCookie);
|
||||
const response = await request(app)
|
||||
.get(RECORDINGS_PATH)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -174,48 +222,61 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app).get(RECORDINGS_PATH).set('Cookie', recordingCookie);
|
||||
const response = await request(app)
|
||||
.get(RECORDINGS_PATH)
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker, token in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app).get(RECORDINGS_PATH).set('Cookie', recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app).get(RECORDINGS_PATH).set('Cookie', recordingCookie);
|
||||
const response = await request(app)
|
||||
.get(RECORDINGS_PATH)
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app).get(RECORDINGS_PATH).set('Cookie', recordingCookie);
|
||||
const response = await request(app)
|
||||
.get(RECORDINGS_PATH)
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app).get(RECORDINGS_PATH).set('Cookie', recordingCookie);
|
||||
const response = await request(app)
|
||||
.get(RECORDINGS_PATH)
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
@ -229,7 +290,9 @@ describe('Recording API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app).get(`${RECORDINGS_PATH}/${recordingId}`).set('Cookie', adminCookie);
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -238,56 +301,61 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker, token in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app).get(RECORDINGS_PATH).set('Cookie', recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -331,7 +399,7 @@ describe('Recording API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}?secret=${secret}`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
@ -358,7 +426,7 @@ describe('Recording API Security Tests', () => {
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${RECORDINGS_PATH}/${fakeRecordingId}`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
|
||||
@ -367,14 +435,11 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${RECORDINGS_PATH}/${fakeRecordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
@ -383,40 +448,50 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${RECORDINGS_PATH}/${fakeRecordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator, token in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${RECORDINGS_PATH}/${fakeRecordingId}`)
|
||||
.set('Cookie', recordingToken);
|
||||
expect(response.status).toBe(404);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${RECORDINGS_PATH}/${fakeRecordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(`${RECORDINGS_PATH}/${fakeRecordingId}`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
});
|
||||
@ -445,7 +520,7 @@ describe('Recording API Security Tests', () => {
|
||||
const response = await request(app)
|
||||
.delete(RECORDINGS_PATH)
|
||||
.query({ recordingIds: fakeRecordingId })
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
|
||||
@ -454,15 +529,12 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(RECORDINGS_PATH)
|
||||
.query({ recordingIds: fakeRecordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
@ -471,43 +543,54 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(RECORDINGS_PATH)
|
||||
.query({ recordingIds: fakeRecordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator, token in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(RECORDINGS_PATH)
|
||||
.query({ recordingIds: fakeRecordingId })
|
||||
.set('Cookie', recordingToken);
|
||||
expect(response.status).toBe(400);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(RECORDINGS_PATH)
|
||||
.query({ recordingIds: fakeRecordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.delete(RECORDINGS_PATH)
|
||||
.query({ recordingIds: fakeRecordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
});
|
||||
@ -523,7 +606,7 @@ describe('Recording API Security Tests', () => {
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -532,14 +615,48 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker, token in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
|
||||
.set('Cookie', recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker, token in query param', async () => {
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
let recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
// Remove the "Bearer " prefix if present
|
||||
if (recordingToken.startsWith('Bearer ')) {
|
||||
recordingToken = recordingToken.slice(7);
|
||||
}
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
|
||||
.query({ recordingToken });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -548,40 +665,31 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -625,7 +733,7 @@ describe('Recording API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/media?secret=${secret}`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -647,7 +755,7 @@ describe('Recording API Security Tests', () => {
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/url`)
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -656,56 +764,63 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/url`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker, token in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/url`)
|
||||
.set('Cookie', recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/url`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/url`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/${recordingId}/url`)
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
@ -723,7 +838,7 @@ describe('Recording API Security Tests', () => {
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/download`)
|
||||
.query({ recordingIds: recordingId })
|
||||
.set('Cookie', adminCookie);
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -732,15 +847,50 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/download`)
|
||||
.query({ recordingIds: recordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker, token in cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/download`)
|
||||
.query({ recordingIds: recordingId })
|
||||
.set('Cookie', recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator_speaker and participant is speaker, token in query param', async () => {
|
||||
await updateRecordingAccessConfigInRoom(
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
let recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
// Remove the "Bearer " prefix if present
|
||||
if (recordingToken.startsWith('Bearer ')) {
|
||||
recordingToken = recordingToken.slice(7);
|
||||
}
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/download`)
|
||||
.query({ recordingIds: recordingId, recordingToken });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -749,43 +899,34 @@ describe('Recording API Security Tests', () => {
|
||||
roomData.room.roomId,
|
||||
MeetRecordingAccess.ADMIN_MODERATOR_SPEAKER
|
||||
);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/download`)
|
||||
.query({ recordingIds: recordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should fail when recording access is admin_moderator and participant is speaker', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.speakerSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.speakerSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/download`)
|
||||
.query({ recordingIds: recordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
it('should succeed when recording access is admin_moderator and participant is moderator', async () => {
|
||||
await updateRecordingAccessConfigInRoom(roomData.room.roomId, MeetRecordingAccess.ADMIN_MODERATOR);
|
||||
const recordingCookie = await generateRecordingTokenCookie(
|
||||
roomData.room.roomId,
|
||||
roomData.moderatorSecret
|
||||
);
|
||||
const recordingToken = await generateRecordingToken(roomData.room.roomId, roomData.moderatorSecret);
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${RECORDINGS_PATH}/download`)
|
||||
.query({ recordingIds: recordingId })
|
||||
.set('Cookie', recordingCookie);
|
||||
.set(INTERNAL_CONFIG.RECORDING_TOKEN_HEADER, recordingToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,8 +3,9 @@ import { Express } from 'express';
|
||||
import request from 'supertest';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
|
||||
import { AuthMode, MeetRecordingAccess, ParticipantRole } from '../../../../src/typings/ce/index.js';
|
||||
import { AuthMode, AuthTransportMode, MeetRecordingAccess, ParticipantRole } from '../../../../src/typings/ce/index.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
changeSecurityConfig,
|
||||
createRoom,
|
||||
deleteAllRecordings,
|
||||
@ -21,11 +22,11 @@ const INTERNAL_ROOMS_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/rooms`
|
||||
|
||||
describe('Room API Security Tests', () => {
|
||||
let app: Express;
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -43,8 +44,25 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.post(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({});
|
||||
expect(response.status).toBe(201);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send({});
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -62,10 +80,26 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app).get(ROOMS_PATH).set('Cookie', adminCookie);
|
||||
const response = await request(app)
|
||||
.get(ROOMS_PATH)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app).post(ROOMS_PATH).set('Cookie', adminCookie).send({});
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
const response = await request(app).get(ROOMS_PATH);
|
||||
expect(response.status).toBe(401);
|
||||
@ -89,11 +123,28 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.delete(ROOMS_PATH)
|
||||
.query({ roomIds: roomId })
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.delete(ROOMS_PATH)
|
||||
.query({ roomIds: roomId })
|
||||
.set('Cookie', adminCookie);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -117,8 +168,24 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app).get(`${ROOMS_PATH}/${roomData.room.roomId}`).set('Cookie', adminCookie);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -129,7 +196,7 @@ describe('Room API Security Tests', () => {
|
||||
it('should succeed when participant is moderator', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
@ -139,7 +206,7 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}`)
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -147,7 +214,7 @@ describe('Room API Security Tests', () => {
|
||||
it('should succeed when participant is speaker', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
@ -169,8 +236,24 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.delete(`${ROOMS_PATH}/${roomId}`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app).delete(`${ROOMS_PATH}/${roomId}`).set('Cookie', adminCookie);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -194,10 +277,26 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', adminCookie);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -208,7 +307,7 @@ describe('Room API Security Tests', () => {
|
||||
it('should succeed when participant is moderator', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', roomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
@ -218,7 +317,7 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', newRoomData.moderatorCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.moderatorToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.MODERATOR);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -226,7 +325,7 @@ describe('Room API Security Tests', () => {
|
||||
it('should succeed when participant is speaker', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', roomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, roomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
@ -236,7 +335,7 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
|
||||
.set('Cookie', newRoomData.speakerCookie)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_TOKEN_HEADER, newRoomData.speakerToken)
|
||||
.set(INTERNAL_CONFIG.PARTICIPANT_ROLE_HEADER, ParticipantRole.SPEAKER);
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
@ -268,11 +367,28 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/config`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({ config: roomConfig });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/config`)
|
||||
.set('Cookie', adminCookie)
|
||||
.send({ config: roomConfig });
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -298,11 +414,28 @@ describe('Room API Security Tests', () => {
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/status`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({ status: 'open' });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.put(`${ROOMS_PATH}/${roomId}/status`)
|
||||
.set('Cookie', adminCookie)
|
||||
.send({ status: 'open' });
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -352,11 +485,30 @@ describe('Room API Security Tests', () => {
|
||||
it('should succeed when authentication is required for moderator, participant is moderator and authenticated', async () => {
|
||||
await changeSecurityConfig(AuthMode.MODERATORS_ONLY);
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({ secret: roomData.moderatorSecret });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when authentication is required for moderator, participant is moderator and authenticated via cookie', async () => {
|
||||
await changeSecurityConfig(AuthMode.MODERATORS_ONLY);
|
||||
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`)
|
||||
.set('Cookie', adminCookie)
|
||||
.send({ secret: roomData.moderatorSecret });
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when authentication is required for moderator and participant is moderator but not authenticated', async () => {
|
||||
@ -373,7 +525,7 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({ secret: roomData.speakerSecret });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
@ -392,7 +544,7 @@ describe('Room API Security Tests', () => {
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${INTERNAL_ROOMS_PATH}/${roomData.room.roomId}/recording-token`)
|
||||
.set('Cookie', adminCookie)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send({ secret: roomData.moderatorSecret });
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
@ -3,7 +3,13 @@ import { Express } from 'express';
|
||||
import request from 'supertest';
|
||||
import INTERNAL_CONFIG from '../../../../src/config/internal-config.js';
|
||||
import { MEET_INITIAL_ADMIN_PASSWORD } from '../../../../src/environment.js';
|
||||
import { changePassword, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
import { AuthTransportMode } from '../../../../src/typings/ce/index.js';
|
||||
import {
|
||||
changeAuthTransportMode,
|
||||
changePassword,
|
||||
loginUser,
|
||||
startTestServer
|
||||
} from '../../../helpers/request-helpers.js';
|
||||
|
||||
const USERS_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/users`;
|
||||
|
||||
@ -15,15 +21,31 @@ describe('User API Security Tests', () => {
|
||||
});
|
||||
|
||||
describe('Profile Tests', () => {
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.get(`${USERS_PATH}/profile`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app).get(`${USERS_PATH}/profile`).set('Cookie', adminCookie);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
@ -38,13 +60,30 @@ describe('User API Security Tests', () => {
|
||||
newPassword: 'newpassword123'
|
||||
};
|
||||
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin', async () => {
|
||||
const response = await request(app)
|
||||
.post(`${USERS_PATH}/change-password`)
|
||||
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, adminAccessToken)
|
||||
.send(changePasswordRequest);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Reset password
|
||||
await changePassword(changePasswordRequest.newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminAccessToken);
|
||||
});
|
||||
|
||||
it('should succeed when user is authenticated as admin via cookie', async () => {
|
||||
// Set auth transport mode to cookie
|
||||
await changeAuthTransportMode(AuthTransportMode.COOKIE);
|
||||
|
||||
// Login as admin to get access token cookie
|
||||
const adminCookie = await loginUser();
|
||||
|
||||
const response = await request(app)
|
||||
.post(`${USERS_PATH}/change-password`)
|
||||
.set('Cookie', adminCookie)
|
||||
@ -53,6 +92,9 @@ describe('User API Security Tests', () => {
|
||||
|
||||
// Reset password
|
||||
await changePassword(changePasswordRequest.newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminCookie);
|
||||
|
||||
// Revert auth transport mode to header
|
||||
await changeAuthTransportMode(AuthTransportMode.HEADER);
|
||||
});
|
||||
|
||||
it('should fail when user is not authenticated', async () => {
|
||||
|
||||
@ -4,31 +4,31 @@ import { expectValidationError } from '../../../helpers/assertion-helpers.js';
|
||||
import { changePassword, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
|
||||
describe('Users API Tests', () => {
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
describe('Change Password Tests', () => {
|
||||
it('should successfully change password', async () => {
|
||||
const newPassword = 'newpassword123';
|
||||
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, newPassword, adminCookie);
|
||||
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, newPassword, adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// Reset password
|
||||
await changePassword(newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminCookie);
|
||||
await changePassword(newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminAccessToken);
|
||||
});
|
||||
|
||||
it('should fail when current password is incorrect', async () => {
|
||||
const response = await changePassword('wrongpassword', 'newpassword123', adminCookie);
|
||||
const response = await changePassword('wrongpassword', 'newpassword123', adminAccessToken);
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body).toHaveProperty('message', 'Invalid current password');
|
||||
});
|
||||
|
||||
it('should fail when new password is not 5 characters long', async () => {
|
||||
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, '1234', adminCookie);
|
||||
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, '1234', adminAccessToken);
|
||||
expectValidationError(response, 'newPassword', 'New password must be at least 5 characters long');
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,16 +2,16 @@ import { beforeAll, describe, expect, it } from '@jest/globals';
|
||||
import { getProfile, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
|
||||
|
||||
describe('Users API Tests', () => {
|
||||
let adminCookie: string;
|
||||
let adminAccessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
startTestServer();
|
||||
adminCookie = await loginUser();
|
||||
adminAccessToken = await loginUser();
|
||||
});
|
||||
|
||||
describe('Profile Tests', () => {
|
||||
it('should return 200 and admin profile', async () => {
|
||||
const response = await getProfile(adminCookie);
|
||||
const response = await getProfile(adminAccessToken);
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toHaveProperty('username');
|
||||
expect(response.body.username).toBe('admin');
|
||||
|
||||
@ -91,10 +91,10 @@ describe('Webhook Integration Tests', () => {
|
||||
it('should send meeting_ended webhook when meeting is closed', async () => {
|
||||
const context = await setupSingleRoom(true);
|
||||
const roomData = context.room;
|
||||
const moderatorCookie = context.moderatorCookie;
|
||||
const moderatorToken = context.moderatorToken;
|
||||
|
||||
// Close the room
|
||||
await endMeeting(roomData.roomId, moderatorCookie);
|
||||
await endMeeting(roomData.roomId, moderatorToken);
|
||||
|
||||
// Wait for the room to be closed
|
||||
await sleep('1s');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user