49 lines
2.1 KiB
JavaScript
49 lines
2.1 KiB
JavaScript
const express = require('express');
|
|
const bcrypt = require('bcryptjs');
|
|
const { audit, now, one, run } = require('../db');
|
|
const { getProfile, savePreferences } = require('../services/profile');
|
|
const {
|
|
describe, getPolicy, minAgeRemainingMinutes, recordPassword, validatePassword
|
|
} = require('../services/passwordPolicy');
|
|
|
|
const router = express.Router();
|
|
|
|
router.get('/profile', (req, res) => {
|
|
res.json({ ...getProfile(req.user), passwordPolicy: { rules: describe() } });
|
|
});
|
|
|
|
router.put('/profile', (req, res) => {
|
|
const preferences = savePreferences(req.user.id, req.body.preferences || {});
|
|
audit(req.user.id, 'update', 'profile_preferences', req.user.id, null, { preferences });
|
|
res.json({ user: getProfile(req.user).user, preferences });
|
|
});
|
|
|
|
// Self-service password change. Honors the configured policy (complexity, identifiers, history,
|
|
// and minimum age), then clears any forced-change flag.
|
|
router.put('/profile/password', (req, res, next) => {
|
|
try {
|
|
const { current_password: current, new_password: next } = req.body || {};
|
|
const user = one('SELECT * FROM users WHERE id = ?', [req.user.id]);
|
|
if (!user || !bcrypt.compareSync(current || '', user.password_hash)) {
|
|
return res.status(400).json({ error: 'Your current password is incorrect' });
|
|
}
|
|
// The minimum-age rule never blocks a forced change (expired / admin-required).
|
|
const remaining = minAgeRemainingMinutes(user, getPolicy());
|
|
if (remaining > 0 && !user.must_change_password) {
|
|
return res.status(400).json({ error: `You can change your password again in ${remaining} minute(s)` });
|
|
}
|
|
validatePassword(next, { id: user.id, name: user.name, email: user.email });
|
|
const hash = bcrypt.hashSync(next, 12);
|
|
run('UPDATE users SET password_hash = ?, password_changed_at = ?, must_change_password = 0, updated_at = ? WHERE id = ?', [
|
|
hash, now(), now(), user.id
|
|
]);
|
|
recordPassword(user.id, hash);
|
|
audit(user.id, 'password_change', 'user', user.id, null, { self: true });
|
|
return res.json({ ok: true });
|
|
} catch (error) {
|
|
return next(error);
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|