diff --git a/services/mam-api/src/routes/auth.js b/services/mam-api/src/routes/auth.js index 2409c27..6efaf37 100644 --- a/services/mam-api/src/routes/auth.js +++ b/services/mam-api/src/routes/auth.js @@ -3,6 +3,8 @@ import pool from '../db/pool.js'; import { DEV_USER_ID } from '../middleware/auth.js'; import { hashPassword, comparePassword } from '../auth/passwords.js'; +const DUMMY_PASSWORD_HASH = '$2b$12$gSeC58PregWedNFK/8Q61OephUo.JJ7EUs0LCTdnJV5AzCS5qQH7K'; + const router = express.Router(); // Real users = anyone except the seeded dev row. @@ -70,8 +72,10 @@ router.post('/login', async (req, res, next) => { [username.trim(), DEV_USER_ID] ); if (rows.length === 0) { - // Still hash the supplied password against a dummy to keep response time uniform. - await comparePassword(password, '$2b$12$dummyhashthatwillalwaysfailtocomparexxxxxxxxxxxxxxxxxxxx'); + // Pre-computed bcrypt hash of a value that no real password input will match. + // Used to keep the user-not-found response time uniform with the wrong-password + // path (~180ms at cost 12) so user enumeration via timing isn't possible. + await comparePassword(password, DUMMY_PASSWORD_HASH); return res.status(401).json({ error: 'invalid credentials' }); } const user = rows[0]; @@ -87,7 +91,8 @@ router.post('/login', async (req, res, next) => { // the prior bounce-to-login logic produced an infinite loop. await new Promise((resolve, reject) => req.session.save(err => err ? reject(err) : resolve())); - await pool.query(`UPDATE users SET last_login_at = NOW() WHERE id = $1`, [user.id]).catch(() => {}); + pool.query(`UPDATE users SET last_login_at = NOW() WHERE id = $1`, [user.id]) + .catch(err => console.error('[auth] last_login_at update failed:', err.message)); res.json({ user: { id: user.id, username: user.username, display_name: user.display_name } }); } catch (err) { next(err); } diff --git a/services/mam-api/test/routes/auth.test.js b/services/mam-api/test/routes/auth.test.js index 5f3e6be..e70168c 100644 --- a/services/mam-api/test/routes/auth.test.js +++ b/services/mam-api/test/routes/auth.test.js @@ -5,7 +5,6 @@ import express from 'express'; import session from 'express-session'; import authRouter from '../../src/routes/auth.js'; import { hashPassword } from '../../src/auth/passwords.js'; -import { comparePassword } from '../../src/auth/passwords.js'; import { requireAuth } from '../../src/middleware/auth.js'; async function appWithAuth(pool) {