Merge commit from fork

This commit is contained in:
Oliver Eyton-Williams
2026-01-14 13:49:25 +01:00
committed by Mrugesh Mohapatra
parent 0b0b03296c
commit 521c583c66
2 changed files with 57 additions and 3 deletions
+52 -1
View File
@@ -25,6 +25,7 @@ import {
getWaitMessage,
validateSocialUrl
} from './settings.js';
import { findOrCreateUser } from '../helpers/auth-helpers.js';
const baseProfileUI = {
isLocked: false,
@@ -109,15 +110,28 @@ describe('settingRoutes', () => {
'4kZFEVHChxzY7kX1XSzB4uhh8fcUwcqAGWV9hv25hsI6nviVlwzXCv2YE9lENYGY';
const tokenWithMissingUser =
'4kZFEVHChxzY7kX1XSzB4uhh8fcUwcqAGWV9hv25hsI6nviVlwzXCv2YE9lENYGH';
const tokenWithDifferentUser =
'4kZFEVHChxzY7kX1XSzB4uhh8fcUwcqAGWV9hv25hsI6nviVlwzXCv2YE9lENYGI';
const expiredToken =
'4kZFEVHChxzY7kX1XSzB4uhh8fcUwcqAGWV9hv25hsI6nviVlwzXCv2YE9lENYGE';
const tokens = [validToken, tokenWithMissingUser, expiredToken];
const tokens = [
validToken,
tokenWithMissingUser,
expiredToken,
tokenWithDifferentUser
];
const newEmail = 'anything@goes.com';
const otherUserEmail = 'another@user.com';
const encodedEmail = Buffer.from(newEmail).toString('base64');
const notEmail = Buffer.from('foobar.com').toString('base64');
beforeEach(async () => {
const otherUser = await findOrCreateUser(
fastifyTestInstance,
otherUserEmail
);
await fastifyTestInstance.prisma.authToken.create({
data: {
created: new Date(),
@@ -137,6 +151,15 @@ describe('settingRoutes', () => {
}
});
await fastifyTestInstance.prisma.authToken.create({
data: {
created: new Date(),
id: tokenWithDifferentUser,
ttl: 1000,
userId: otherUser.id
}
});
await fastifyTestInstance.prisma.authToken.create({
data: {
created: new Date(Date.now() - 1000),
@@ -157,6 +180,17 @@ describe('settingRoutes', () => {
emailAuthLinkTTL: new Date()
}
});
// Simulate another user changing their email. This user is signed out.
await fastifyTestInstance.prisma.user.update({
where: { id: otherUser.id },
data: {
newEmail,
emailVerified: false,
emailVerifyTTL: new Date(),
emailAuthLinkTTL: new Date()
}
});
});
afterEach(async () => {
@@ -167,6 +201,9 @@ describe('settingRoutes', () => {
where: { id: defaultUserId },
data: { newEmail: null, email: defaultUserEmail, emailVerified: true }
});
await fastifyTestInstance.prisma.user.deleteMany({
where: { email: otherUserEmail }
});
});
test('should reject requests without params', async () => {
@@ -223,6 +260,20 @@ describe('settingRoutes', () => {
expect(res.status).toBe(302);
});
test('should reject requests when the target user does not match the signed in user', async () => {
// The signed in user is the default (foo@bar.com), but the token is for
// a different user (another@user.com).
const res = await superGet(
`/confirm-email?email=${encodedEmail}&token=${tokenWithDifferentUser}`
);
expect(res.headers.location).toBe(
`${HOME_LOCATION}?` + formatMessage(defaultErrorMessage)
);
expect(res.status).toBe(302);
});
// TODO(Post-MVP): there's no need to keep the auth token around if,
// somehow, the user is missing
test.todo(
+5 -2
View File
@@ -838,12 +838,15 @@ export const settingRedirectRoutes: FastifyPluginCallbackTypebox = (
return reply.redirectWithMessage(origin, expirationMessage);
}
// TODO(Post-MVP): should this fail if it's not the currently signed in
// user?
const targetUser = await fastify.prisma.user.findUnique({
where: { id: authToken.userId }
});
if (targetUser?.id !== req.user?.id) {
logger.warn('Target user does not match signed in user');
return reply.redirectWithMessage(origin, redirectMessage);
}
if (targetUser?.newEmail !== email) {
return reply.redirectWithMessage(origin, redirectMessage);
}