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 { logger } from '../logging';
|
||||
import { tokenService } from './token.service';
|
||||
import { hashPassword, verifyPassword, isBcryptHash } from './password.service';
|
||||
|
||||
const emailVerificationService = new EmailVerificationService();
|
||||
|
||||
@@ -22,9 +23,11 @@ const authService = {
|
||||
}
|
||||
|
||||
// Create user with password
|
||||
const passwordToPersist = await hashPassword(password);
|
||||
|
||||
const user = await databaseService.createUserWithPassword(
|
||||
email,
|
||||
password,
|
||||
passwordToPersist,
|
||||
username
|
||||
);
|
||||
|
||||
@@ -80,14 +83,21 @@ const authService = {
|
||||
throw new Error('Email verification required');
|
||||
}
|
||||
|
||||
// Simple password verification (in production, use bcrypt)
|
||||
logger.auth.login('Comparing passwords', {
|
||||
inputPassword: input.password,
|
||||
storedPassword: user.password,
|
||||
match: user.password === input.password,
|
||||
if (!isBcryptHash(user.password)) {
|
||||
logger.auth.error('Stored password is not hashed; rejecting login');
|
||||
throw new Error('Invalid credentials');
|
||||
}
|
||||
|
||||
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');
|
||||
throw new Error('Invalid credentials');
|
||||
}
|
||||
@@ -162,8 +172,16 @@ const authService = {
|
||||
throw new Error('Cannot change password for OAuth accounts');
|
||||
}
|
||||
|
||||
// Verify current password
|
||||
if (user.password !== currentPassword) {
|
||||
if (!isBcryptHash(user.password)) {
|
||||
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');
|
||||
}
|
||||
|
||||
@@ -175,7 +193,7 @@ const authService = {
|
||||
// Update user with new password (this should be hashed before calling)
|
||||
const updatedUser = await databaseService.updateUser({
|
||||
...user,
|
||||
password: newPassword,
|
||||
password: await hashPassword(newPassword),
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -249,10 +267,11 @@ const authService = {
|
||||
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({
|
||||
...user,
|
||||
password: newPassword,
|
||||
password: hashedPassword,
|
||||
});
|
||||
|
||||
// Remove used token
|
||||
|
||||
Reference in New Issue
Block a user