diff --git a/api/src/exam-environment/routes/exam-environment.test.ts b/api/src/exam-environment/routes/exam-environment.test.ts index da4a1e02ec4..c153a045173 100644 --- a/api/src/exam-environment/routes/exam-environment.test.ts +++ b/api/src/exam-environment/routes/exam-environment.test.ts @@ -1,4 +1,6 @@ import { Static } from '@fastify/type-provider-typebox'; +import jwt from 'jsonwebtoken'; + import { createSuperRequest, defaultUserId, @@ -11,6 +13,7 @@ import { } from '../schemas'; import * as mock from '../../../__mocks__/env-exam'; import { constructUserExam } from '../utils/exam'; +import { JWT_SECRET } from '../../utils/env'; jest.mock('../../utils/env', () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-return @@ -639,7 +642,7 @@ describe('/exam-environment/', () => { }); describe('GET /exam-environment/token-meta', () => { - it('should allow a valid request', async () => { + it('should reject invalid tokens', async () => { const res = await superGet('/exam-environment/token-meta').set( 'exam-environment-authorization-token', 'invalid-token' @@ -652,6 +655,24 @@ describe('/exam-environment/', () => { } }); }); + + it('should tell the requester if the token does not exist', async () => { + const validToken = jwt.sign( + { examEnvironmentAuthorizationToken: 'does-not-exist' }, + JWT_SECRET + ); + const res = await superGet('/exam-environment/token-meta').set( + 'exam-environment-authorization-token', + validToken + ); + + expect(res).toMatchObject({ + status: 418, + body: { + code: 'FCC_EINVAL_EXAM_ENVIRONMENT_AUTHORIZATION_TOKEN' + } + }); + }); }); describe('GET /exam-environment/exams', () => { diff --git a/api/src/exam-environment/routes/exam-environment.ts b/api/src/exam-environment/routes/exam-environment.ts index ba310a9b749..a9484e9c334 100644 --- a/api/src/exam-environment/routes/exam-environment.ts +++ b/api/src/exam-environment/routes/exam-environment.ts @@ -14,6 +14,7 @@ import { validateAttempt } from '../utils/exam'; import { ERRORS } from '../utils/errors'; +import { isObjectID } from '../../utils/validation'; /** * Wrapper for endpoints related to the exam environment desktop app. @@ -91,8 +92,9 @@ async function tokenMetaHandler( ) { const { 'exam-environment-authorization-token': encodedToken } = req.headers; + let payload: JwtPayload; try { - jwt.verify(encodedToken, JWT_SECRET); + payload = jwt.verify(encodedToken, JWT_SECRET) as JwtPayload; } catch (e) { // Server refuses to brew (verify) coffee (jwts) with a teapot (random strings) void reply.code(418); @@ -101,14 +103,18 @@ async function tokenMetaHandler( ); } - const payload = jwt.decode(encodedToken) as JwtPayload; - - const examEnvironmentAuthorizationToken = - payload.examEnvironmentAuthorizationToken; + if (!isObjectID(payload.examEnvironmentAuthorizationToken)) { + void reply.code(418); + return reply.send( + ERRORS.FCC_EINVAL_EXAM_ENVIRONMENT_AUTHORIZATION_TOKEN( + 'Token is not valid' + ) + ); + } const token = await this.prisma.examEnvironmentAuthorizationToken.findUnique({ where: { - id: examEnvironmentAuthorizationToken + id: payload.examEnvironmentAuthorizationToken } });