Fix login endpoint leaking sensitive user fields

Use select clause instead of spreading full user object to prevent
resetToken, resetTokenExpiry, and other internal fields from being
returned in the login response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
delta-lynx-89e8
2026-02-22 12:40:09 -08:00
parent d09c998d51
commit e72f3133c0

View File

@@ -53,19 +53,19 @@ router.post('/login', validate(loginSchema), async (req, res, next) => {
try { try {
const { email, password } = req.body; const { email, password } = req.body;
const user = await prisma.user.findUnique({ where: { email } }); const fullUser = await prisma.user.findUnique({ where: { email } });
if (!user) throw new AppError(401, 'Invalid email or password'); if (!fullUser) throw new AppError(401, 'Invalid email or password');
if (!user.isActive) throw new AppError(403, 'Account is disabled'); if (!fullUser.isActive) throw new AppError(403, 'Account is disabled');
const valid = await comparePassword(password, user.passwordHash); const valid = await comparePassword(password, fullUser.passwordHash);
if (!valid) throw new AppError(401, 'Invalid email or password'); if (!valid) throw new AppError(401, 'Invalid email or password');
const accessToken = generateAccessToken(user.id); const accessToken = generateAccessToken(fullUser.id);
const refreshToken = generateRefreshToken(user.id); const refreshToken = generateRefreshToken(fullUser.id);
await prisma.session.create({ await prisma.session.create({
data: { data: {
userId: user.id, userId: fullUser.id,
refreshToken, refreshToken,
userAgent: req.headers['user-agent'] || null, userAgent: req.headers['user-agent'] || null,
ipAddress: req.ip || null, ipAddress: req.ip || null,
@@ -80,8 +80,11 @@ router.post('/login', validate(loginSchema), async (req, res, next) => {
maxAge: 7 * 24 * 60 * 60 * 1000, maxAge: 7 * 24 * 60 * 60 * 1000,
}); });
const { passwordHash: _, ...userData } = user; const user = await prisma.user.findUnique({
res.json({ user: userData, accessToken }); where: { id: fullUser.id },
select: { id: true, email: true, fullName: true, nickname: true, avatar: true, phone: true, location: true, bio: true, rating: true, showEmail: true, showPhone: true, showLocation: true, createdAt: true },
});
res.json({ user, accessToken });
} catch (error) { } catch (error) {
next(error); next(error);
} }