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