fix(api): add 401 to non user for exam routes (#64396)

This commit is contained in:
Shaun Hamilton
2025-12-10 15:00:18 +02:00
committed by GitHub
parent 397928c510
commit c8395eb1db
4 changed files with 80 additions and 16 deletions
+1
View File
@@ -224,6 +224,7 @@ export const build = async (
void fastify.register(function (fastify, _opts, done) { void fastify.register(function (fastify, _opts, done) {
fastify.addHook('onRequest', fastify.authorizeExamEnvironmentToken); fastify.addHook('onRequest', fastify.authorizeExamEnvironmentToken);
fastify.addHook('onRequest', fastify.send401IfNoUser);
void fastify.register(examEnvironmentValidatedTokenRoutes); void fastify.register(examEnvironmentValidatedTokenRoutes);
done(); done();
@@ -24,6 +24,20 @@ import { isObjectID } from '../../utils/validation.js';
*/ */
export const examEnvironmentValidatedTokenRoutes: FastifyPluginCallbackTypebox = export const examEnvironmentValidatedTokenRoutes: FastifyPluginCallbackTypebox =
(fastify, _options, done) => { (fastify, _options, done) => {
fastify.setErrorHandler((error, req, res) => {
// If the error does not match the format {code: string; message: string}, coerce into:
if (
!Object.hasOwnProperty.call(error, 'code') ||
!Object.hasOwnProperty.call(error, 'message')
) {
const logger = fastify.log.child({ req, res });
logger.error(error, 'Unhandled error in exam environment routes.');
const str = JSON.stringify(error);
res.code(500);
res.send(ERRORS.FCC_ERR_UNKNOWN_STATE(str));
}
});
fastify.get( fastify.get(
'/exam-environment/exams', '/exam-environment/exams',
{ {
@@ -182,7 +196,16 @@ async function postExamGeneratedExamHandler(
reply: FastifyReply reply: FastifyReply
) { ) {
const logger = this.log.child({ req }); const logger = this.log.child({ req });
logger.info({ userId: req.user?.id }); const user = req.user;
if (!user) {
logger.error('No user found in request.');
this.Sentry.captureException('No user found in request.');
void reply.code(500);
return reply.send(ERRORS.FCC_ERR_UNKNOWN_STATE('No user found.'));
}
logger.info({ userId: user.id });
// Get exam from DB // Get exam from DB
const examId = req.body.examId; const examId = req.body.examId;
const maybeExam = await mapErr( const maybeExam = await mapErr(
@@ -218,7 +241,6 @@ async function postExamGeneratedExamHandler(
} }
// Check user has completed prerequisites // Check user has completed prerequisites
const user = req.user!;
const isExamPrerequisitesMet = checkPrerequisites(user, exam.prerequisites); const isExamPrerequisitesMet = checkPrerequisites(user, exam.prerequisites);
if (!isExamPrerequisitesMet) { if (!isExamPrerequisitesMet) {
@@ -521,10 +543,18 @@ async function postExamAttemptHandler(
reply: FastifyReply reply: FastifyReply
) { ) {
const logger = this.log.child({ req }); const logger = this.log.child({ req });
logger.info({ userId: req.user?.id }); const user = req.user;
const { attempt } = req.body;
const user = req.user!; if (!user) {
logger.error('No user found in request.');
this.Sentry.captureException('No user found in request.');
void reply.code(500);
return reply.send(ERRORS.FCC_ERR_UNKNOWN_STATE('No user found.'));
}
logger.info({ userId: user.id });
const { attempt } = req.body;
const maybeAttempts = await mapErr( const maybeAttempts = await mapErr(
this.prisma.examEnvironmentExamAttempt.findMany({ this.prisma.examEnvironmentExamAttempt.findMany({
@@ -704,9 +734,17 @@ export async function getExams(
reply: FastifyReply reply: FastifyReply
) { ) {
const logger = this.log.child({ req }); const logger = this.log.child({ req });
logger.info({ userId: req.user?.id }); const user = req.user;
if (!user) {
logger.error('No user found in request.');
this.Sentry.captureException('No user found in request.');
void reply.code(500);
return reply.send(ERRORS.FCC_ERR_UNKNOWN_STATE('No user found.'));
}
logger.info({ userId: user.id });
const user = req.user!;
const maybeExams = await mapErr( const maybeExams = await mapErr(
this.prisma.examEnvironmentExam.findMany({ this.prisma.examEnvironmentExam.findMany({
where: { where: {
@@ -869,9 +907,16 @@ export async function getExamAttemptsHandler(
reply: FastifyReply reply: FastifyReply
) { ) {
const logger = this.log.child({ req }); const logger = this.log.child({ req });
logger.info({ userId: req.user?.id }); const user = req.user;
const user = req.user!; if (!user) {
logger.error('No user found in request.');
this.Sentry.captureException('No user found in request.');
void reply.code(500);
return reply.send(ERRORS.FCC_ERR_UNKNOWN_STATE('No user found.'));
}
logger.info({ userId: user.id });
// Send all relevant exam attempts // Send all relevant exam attempts
const envExamAttempts = []; const envExamAttempts = [];
@@ -929,9 +974,16 @@ export async function getExamAttemptHandler(
reply: FastifyReply reply: FastifyReply
) { ) {
const logger = this.log.child({ req }); const logger = this.log.child({ req });
logger.info({ userId: req.user?.id }); const user = req.user;
if (!user) {
logger.error('No user found in request.');
this.Sentry.captureException('No user found in request.');
void reply.code(500);
return reply.send(ERRORS.FCC_ERR_UNKNOWN_STATE('No user found.'));
}
logger.info({ userId: user.id });
const user = req.user!;
const { attemptId } = req.params; const { attemptId } = req.params;
// If attempt id is given, only return that attempt // If attempt id is given, only return that attempt
@@ -988,8 +1040,15 @@ export async function getExamAttemptsByExamIdHandler(
reply: FastifyReply reply: FastifyReply
) { ) {
const logger = this.log.child({ req }); const logger = this.log.child({ req });
const user = req.user;
if (!user) {
logger.error('No user found in request.');
this.Sentry.captureException('No user found in request.');
void reply.code(500);
return reply.send(ERRORS.FCC_ERR_UNKNOWN_STATE('No user found.'));
}
const user = req.user!;
const { examId } = req.params; const { examId } = req.params;
logger.info({ examId, userId: user.id }); logger.info({ examId, userId: user.id });
+2 -1
View File
@@ -39,7 +39,8 @@ export const ERRORS = {
'FCC_ENOENT_EXAM_ENVIRONMENT_GENERATED_EXAM', 'FCC_ENOENT_EXAM_ENVIRONMENT_GENERATED_EXAM',
'%s' '%s'
), ),
FCC_EINVAL_EXAM_ID: createError('FCC_EINVAL_EXAM_ID', '%s') FCC_EINVAL_EXAM_ID: createError('FCC_EINVAL_EXAM_ID', '%s'),
FCC_ERR_UNKNOWN_STATE: createError('FCC_ERR_UNKNOWN_STATE', '%s')
}; };
/** /**
+6 -3
View File
@@ -156,9 +156,12 @@ const auth: FastifyPluginCallback = (fastify, _options, done) => {
}); });
if (!token) { if (!token) {
return { void reply.code(403);
message: 'Token not found' return reply.send(
}; ERRORS.FCC_ENOENT_EXAM_ENVIRONMENT_AUTHORIZATION_TOKEN(
'Provided token is revoked.'
)
);
} }
// We're using token.userId since it's possible for the user record to be // We're using token.userId since it's possible for the user record to be
// malformed and for prisma to throw while trying to find the user. // malformed and for prisma to throw while trying to find the user.