mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-03-24 11:03:17 -04:00
chore(api): add ExamEnvironmentAuthorizationToken -> user relation (#56627)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -207,6 +207,11 @@ export const defaultUserEmail = 'foo@bar.com';
|
||||
export const defaultUsername = 'fcc-test-user';
|
||||
|
||||
export const resetDefaultUser = async (): Promise<void> => {
|
||||
await fastifyTestInstance.prisma.examEnvironmentAuthorizationToken.deleteMany(
|
||||
{
|
||||
where: { userId: defaultUserId }
|
||||
}
|
||||
);
|
||||
await fastifyTestInstance.prisma.user.deleteMany({
|
||||
where: { email: defaultUserEmail }
|
||||
});
|
||||
|
||||
@@ -143,7 +143,8 @@ model user {
|
||||
isClassroomAccount Boolean? // Undefined
|
||||
|
||||
// Relations
|
||||
examAttempts EnvExamAttempt[]
|
||||
examAttempts EnvExamAttempt[]
|
||||
examEnvironmentAuthorizationToken ExamEnvironmentAuthorizationToken?
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
@@ -377,15 +378,13 @@ model UserToken {
|
||||
@@index([userId], map: "userId_1")
|
||||
}
|
||||
|
||||
/// TODO: Token has to outlive the exam attempt
|
||||
/// Validation has to be taken as the attempt is requested
|
||||
/// to ensure it lives long enough.
|
||||
model ExamEnvironmentAuthorizationToken {
|
||||
id String @id @map("_id")
|
||||
createdDate DateTime @db.Date
|
||||
userId String @db.ObjectId
|
||||
userId String @unique @db.ObjectId
|
||||
|
||||
@@index([userId], map: "userId_1")
|
||||
// Relations
|
||||
user user @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
model sessions {
|
||||
|
||||
@@ -107,7 +107,7 @@ async function tokenVerifyHandler(
|
||||
const examEnvironmentAuthorizationToken =
|
||||
payload.examEnvironmentAuthorizationToken;
|
||||
|
||||
const token = await this.prisma.examEnvironmentAuthorizationToken.findFirst({
|
||||
const token = await this.prisma.examEnvironmentAuthorizationToken.findUnique({
|
||||
where: {
|
||||
id: examEnvironmentAuthorizationToken
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
createSuperRequest
|
||||
} from '../../../jest.utils';
|
||||
import { JWT_SECRET } from '../../utils/env';
|
||||
import { customNanoid } from '../../utils/ids';
|
||||
import { getMsTranscriptApiUrl } from './user';
|
||||
|
||||
const mockedFetch = jest.fn();
|
||||
@@ -564,6 +565,11 @@ describe('userRoutes', () => {
|
||||
await fastifyTestInstance.prisma.userToken.deleteMany({
|
||||
where: { id: userTokenId }
|
||||
});
|
||||
await fastifyTestInstance.prisma.examEnvironmentAuthorizationToken.deleteMany(
|
||||
{
|
||||
where: { userId: defaultUserId }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('GET rejects with 500 status code if the username is missing', async () => {
|
||||
@@ -1130,6 +1136,72 @@ Thanks and regards,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/user/exam-environment/token', () => {
|
||||
afterEach(async () => {
|
||||
await fastifyTestInstance.prisma.examEnvironmentAuthorizationToken.deleteMany(
|
||||
{
|
||||
where: { userId: defaultUserId }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('POST generates a new token if one does not exist', async () => {
|
||||
const response = await superPost('/user/exam-environment/token');
|
||||
const { examEnvironmentAuthorizationToken } = response.body.data;
|
||||
|
||||
const decodedToken = jwt.decode(examEnvironmentAuthorizationToken);
|
||||
|
||||
expect(decodedToken).toStrictEqual({
|
||||
examEnvironmentAuthorizationToken:
|
||||
expect.stringMatching(/^[a-zA-Z0-9]{64}$/),
|
||||
iat: expect.any(Number)
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
jwt.verify(examEnvironmentAuthorizationToken, 'wrong-secret')
|
||||
).toThrow();
|
||||
expect(() =>
|
||||
jwt.verify(examEnvironmentAuthorizationToken, JWT_SECRET)
|
||||
).not.toThrow();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
test('POST only allows for one token per user id', async () => {
|
||||
const id = customNanoid();
|
||||
await fastifyTestInstance.prisma.examEnvironmentAuthorizationToken.create(
|
||||
{
|
||||
data: {
|
||||
userId: defaultUserId,
|
||||
id,
|
||||
createdDate: new Date()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const response = await superPost('/user/exam-environment/token');
|
||||
|
||||
const { examEnvironmentAuthorizationToken } = response.body.data;
|
||||
|
||||
const decodedToken = jwt.decode(examEnvironmentAuthorizationToken);
|
||||
|
||||
expect(decodedToken).not.toHaveProperty(
|
||||
'examEnvironmentAuthorizationToken',
|
||||
id
|
||||
);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
const tokens =
|
||||
await fastifyTestInstance.prisma.examEnvironmentAuthorizationToken.findMany(
|
||||
{
|
||||
where: { userId: defaultUserId }
|
||||
}
|
||||
);
|
||||
expect(tokens).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unauthenticated user', () => {
|
||||
|
||||
Reference in New Issue
Block a user