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:
William Valentin
2025-10-16 13:15:08 -07:00
parent 50a352fb27
commit a183aca4d8

View File

@@ -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