fix(perm): bump token_version on permission change (invalidates JWTs)
setPermission / setUserPermission now bump token_version for affected
users so cached JWTs lose access immediately instead of after expiry.
Aligns with role-change pattern in adminController.updateRole.
Both writes wrapped in db.transaction() so token_version is only bumped
if the permission write itself succeeds.
Also cleaned up inline require('../db/db') calls to use top-level db.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -203,9 +203,15 @@ function setPermission(req, res) {
|
|||||||
return res.status(400).json({ error: 'Invalid role' });
|
return res.status(400).json({ error: 'Invalid role' });
|
||||||
if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === role))
|
if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === role))
|
||||||
return res.status(400).json({ error: 'Unknown permission' });
|
return res.status(400).json({ error: 'Unknown permission' });
|
||||||
db.prepare(
|
db.transaction(() => {
|
||||||
'INSERT OR REPLACE INTO role_permissions (role, permission, enabled) VALUES (?, ?, ?)'
|
db.prepare(
|
||||||
).run(role, permission, enabled ? 1 : 0);
|
'INSERT OR REPLACE INTO role_permissions (role, permission, enabled) VALUES (?, ?, ?)'
|
||||||
|
).run(role, permission, enabled ? 1 : 0);
|
||||||
|
// Invalidate JWTs for all users of that role so the change takes effect immediately
|
||||||
|
db.prepare(
|
||||||
|
'UPDATE users SET token_version = token_version + 1 WHERE role = ?'
|
||||||
|
).run(role);
|
||||||
|
})();
|
||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,19 +245,19 @@ function getMyPermissions(req, res) {
|
|||||||
/* ── GET /api/permissions/users/:id ──────────────────────────────────── */
|
/* ── GET /api/permissions/users/:id ──────────────────────────────────── */
|
||||||
function getUserPermissions(req, res) {
|
function getUserPermissions(req, res) {
|
||||||
const uid = Number(req.params.id);
|
const uid = Number(req.params.id);
|
||||||
const target = require('../db/db').prepare('SELECT id, role FROM users WHERE id = ?').get(uid);
|
const target = db.prepare('SELECT id, role FROM users WHERE id = ?').get(uid);
|
||||||
if (!target) return res.status(404).json({ error: 'User not found' });
|
if (!target) return res.status(404).json({ error: 'User not found' });
|
||||||
|
|
||||||
seedDefaults();
|
seedDefaults();
|
||||||
// role-level values
|
// role-level values
|
||||||
const roleRows = require('../db/db').prepare(
|
const roleRows = db.prepare(
|
||||||
'SELECT permission, enabled FROM role_permissions WHERE role = ?'
|
'SELECT permission, enabled FROM role_permissions WHERE role = ?'
|
||||||
).all(target.role);
|
).all(target.role);
|
||||||
const roleMap = {};
|
const roleMap = {};
|
||||||
for (const r of roleRows) roleMap[r.permission] = r.enabled === 1;
|
for (const r of roleRows) roleMap[r.permission] = r.enabled === 1;
|
||||||
|
|
||||||
// user-level overrides
|
// user-level overrides
|
||||||
const userRows = require('../db/db').prepare(
|
const userRows = db.prepare(
|
||||||
'SELECT permission, enabled FROM user_permissions WHERE user_id = ?'
|
'SELECT permission, enabled FROM user_permissions WHERE user_id = ?'
|
||||||
).all(uid);
|
).all(uid);
|
||||||
const userMap = {};
|
const userMap = {};
|
||||||
@@ -274,13 +280,19 @@ function getUserPermissions(req, res) {
|
|||||||
function setUserPermission(req, res) {
|
function setUserPermission(req, res) {
|
||||||
const uid = Number(req.params.id);
|
const uid = Number(req.params.id);
|
||||||
const { permission, enabled } = req.body;
|
const { permission, enabled } = req.body;
|
||||||
const target = require('../db/db').prepare('SELECT role FROM users WHERE id = ?').get(uid);
|
const target = db.prepare('SELECT role FROM users WHERE id = ?').get(uid);
|
||||||
if (!target) return res.status(404).json({ error: 'User not found' });
|
if (!target) return res.status(404).json({ error: 'User not found' });
|
||||||
if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === target.role))
|
if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === target.role))
|
||||||
return res.status(400).json({ error: 'Unknown permission for this role' });
|
return res.status(400).json({ error: 'Unknown permission for this role' });
|
||||||
require('../db/db').prepare(
|
db.transaction(() => {
|
||||||
'INSERT OR REPLACE INTO user_permissions (user_id, permission, enabled) VALUES (?, ?, ?)'
|
db.prepare(
|
||||||
).run(uid, permission, enabled ? 1 : 0);
|
'INSERT OR REPLACE INTO user_permissions (user_id, permission, enabled) VALUES (?, ?, ?)'
|
||||||
|
).run(uid, permission, enabled ? 1 : 0);
|
||||||
|
// Invalidate existing JWT for this user immediately
|
||||||
|
db.prepare(
|
||||||
|
'UPDATE users SET token_version = token_version + 1 WHERE id = ?'
|
||||||
|
).run(uid);
|
||||||
|
})();
|
||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,11 +301,11 @@ function resetUserPermissions(req, res) {
|
|||||||
const uid = Number(req.params.id);
|
const uid = Number(req.params.id);
|
||||||
const { permission } = req.body; // optional: reset one key
|
const { permission } = req.body; // optional: reset one key
|
||||||
if (permission) {
|
if (permission) {
|
||||||
require('../db/db').prepare(
|
db.prepare(
|
||||||
'DELETE FROM user_permissions WHERE user_id = ? AND permission = ?'
|
'DELETE FROM user_permissions WHERE user_id = ? AND permission = ?'
|
||||||
).run(uid, permission);
|
).run(uid, permission);
|
||||||
} else {
|
} else {
|
||||||
require('../db/db').prepare('DELETE FROM user_permissions WHERE user_id = ?').run(uid);
|
db.prepare('DELETE FROM user_permissions WHERE user_id = ?').run(uid);
|
||||||
}
|
}
|
||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user