feat(auth): implement secure password authentication
- Replace plaintext password comparison with bcrypt verification - Hash passwords before database storage in registration - Validate bcrypt hashes during login to reject legacy plaintext - Update password change and reset flows with proper hashing - Add legacy password detection for security enforcement
This commit is contained in:
@@ -4,6 +4,7 @@ import { EmailVerificationService } from './emailVerification.service';
|
|||||||
import { databaseService } from '../database';
|
import { databaseService } from '../database';
|
||||||
import { logger } from '../logging';
|
import { logger } from '../logging';
|
||||||
import { tokenService } from './token.service';
|
import { tokenService } from './token.service';
|
||||||
|
import { hashPassword, verifyPassword, isBcryptHash } from './password.service';
|
||||||
|
|
||||||
const emailVerificationService = new EmailVerificationService();
|
const emailVerificationService = new EmailVerificationService();
|
||||||
|
|
||||||
@@ -22,9 +23,11 @@ const authService = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create user with password
|
// Create user with password
|
||||||
|
const passwordToPersist = await hashPassword(password);
|
||||||
|
|
||||||
const user = await databaseService.createUserWithPassword(
|
const user = await databaseService.createUserWithPassword(
|
||||||
email,
|
email,
|
||||||
password,
|
passwordToPersist,
|
||||||
username
|
username
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -80,14 +83,21 @@ const authService = {
|
|||||||
throw new Error('Email verification required');
|
throw new Error('Email verification required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple password verification (in production, use bcrypt)
|
if (!isBcryptHash(user.password)) {
|
||||||
logger.auth.login('Comparing passwords', {
|
logger.auth.error('Stored password is not hashed; rejecting login');
|
||||||
inputPassword: input.password,
|
throw new Error('Invalid credentials');
|
||||||
storedPassword: user.password,
|
}
|
||||||
match: user.password === input.password,
|
|
||||||
|
const hasValidPassword = await verifyPassword(
|
||||||
|
input.password,
|
||||||
|
user.password
|
||||||
|
);
|
||||||
|
|
||||||
|
logger.auth.login('Password comparison result', {
|
||||||
|
hasValidPassword,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (user.password !== input.password) {
|
if (!hasValidPassword) {
|
||||||
logger.auth.error('Password mismatch');
|
logger.auth.error('Password mismatch');
|
||||||
throw new Error('Invalid credentials');
|
throw new Error('Invalid credentials');
|
||||||
}
|
}
|
||||||
@@ -162,8 +172,16 @@ const authService = {
|
|||||||
throw new Error('Cannot change password for OAuth accounts');
|
throw new Error('Cannot change password for OAuth accounts');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify current password
|
if (!isBcryptHash(user.password)) {
|
||||||
if (user.password !== currentPassword) {
|
throw new Error('Password needs to be reset before it can be changed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPasswordMatches = await verifyPassword(
|
||||||
|
currentPassword,
|
||||||
|
user.password
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!currentPasswordMatches) {
|
||||||
throw new Error('Current password is incorrect');
|
throw new Error('Current password is incorrect');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +193,7 @@ const authService = {
|
|||||||
// Update user with new password (this should be hashed before calling)
|
// Update user with new password (this should be hashed before calling)
|
||||||
const updatedUser = await databaseService.updateUser({
|
const updatedUser = await databaseService.updateUser({
|
||||||
...user,
|
...user,
|
||||||
password: newPassword,
|
password: await hashPassword(newPassword),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -249,10 +267,11 @@ const authService = {
|
|||||||
throw new Error('User not found');
|
throw new Error('User not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update user with new password (this should be hashed before calling)
|
const hashedPassword = await hashPassword(newPassword);
|
||||||
|
|
||||||
const updatedUser = await databaseService.updateUser({
|
const updatedUser = await databaseService.updateUser({
|
||||||
...user,
|
...user,
|
||||||
password: newPassword,
|
password: hashedPassword,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove used token
|
// Remove used token
|
||||||
|
|||||||
Reference in New Issue
Block a user