Files
MixedAssets/server/routes/profile.js

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;