Fixing API Token conflict with req.session

This commit is contained in:
Rafael Foster
2026-04-25 12:34:10 -03:00
parent 6e2dec66e8
commit bb44a90d48
3 changed files with 25 additions and 15 deletions
View File
+13 -11
View File
@@ -192,15 +192,15 @@ function requireAuth(req, res, next) {
const apiToken = authenticateApiToken(req); const apiToken = authenticateApiToken(req);
if (apiToken) { if (apiToken) {
req.authMethod = 'api_token'; req.authMethod = 'api_token';
req.session = { req.authUserId = apiToken.created_by;
userId: apiToken.created_by, req.authRole = apiToken.role;
role: apiToken.role,
};
return next(); return next();
} }
if (req.session && req.session.userId) { if (req.session && req.session.userId) {
req.authMethod = 'session'; req.authMethod = 'session';
req.authUserId = req.session.userId;
req.authRole = req.session.role;
return next(); return next();
} }
res.status(401).json({ error: 'Not authenticated.', code: 401 }); res.status(401).json({ error: 'Not authenticated.', code: 401 });
@@ -210,7 +210,7 @@ function requireAuth(req, res, next) {
* Prüft ob der authentifizierte User Admin-Rolle hat. * Prüft ob der authentifizierte User Admin-Rolle hat.
*/ */
function requireAdmin(req, res, next) { function requireAdmin(req, res, next) {
if (req.session && req.session.role === 'admin') { if (req.authRole === 'admin') {
return next(); return next();
} }
res.status(403).json({ error: 'Permission denied.', code: 403 }); res.status(403).json({ error: 'Permission denied.', code: 403 });
@@ -363,10 +363,12 @@ router.get('/me', requireAuth, (req, res) => {
try { try {
const user = db.get() const user = db.get()
.prepare('SELECT id, username, display_name, avatar_color, role FROM users WHERE id = ?') .prepare('SELECT id, username, display_name, avatar_color, role FROM users WHERE id = ?')
.get(req.session.userId); .get(req.authUserId);
if (!user) { if (!user) {
if (req.authMethod === 'session' && typeof req.session.destroy === 'function') {
req.session.destroy(() => {}); req.session.destroy(() => {});
}
return res.status(401).json({ error: 'User not found.', code: 401 }); return res.status(401).json({ error: 'User not found.', code: 401 });
} }
@@ -448,7 +450,7 @@ router.post('/api-tokens', requireAuth, requireAdmin, csrfMiddleware, (req, res)
const result = db.get().prepare(` const result = db.get().prepare(`
INSERT INTO api_tokens (name, token_hash, token_prefix, created_by, expires_at) INSERT INTO api_tokens (name, token_hash, token_prefix, created_by, expires_at)
VALUES (?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?)
`).run(name, tokenHash, tokenPrefix, req.session.userId, normalizedExpiresAt); `).run(name, tokenHash, tokenPrefix, req.authUserId, normalizedExpiresAt);
const row = db.get().prepare(` const row = db.get().prepare(`
SELECT t.*, u.display_name AS creator_name SELECT t.*, u.display_name AS creator_name
@@ -551,14 +553,14 @@ router.patch('/me/password', requireAuth, csrfMiddleware, async (req, res) => {
return res.status(400).json({ error: 'New password must be at least 8 characters long.', code: 400 }); return res.status(400).json({ error: 'New password must be at least 8 characters long.', code: 400 });
} }
const user = db.get().prepare('SELECT password_hash FROM users WHERE id = ?').get(req.session.userId); const user = db.get().prepare('SELECT password_hash FROM users WHERE id = ?').get(req.authUserId);
if (!user) return res.status(404).json({ error: 'User not found.', code: 404 }); if (!user) return res.status(404).json({ error: 'User not found.', code: 404 });
const valid = await bcrypt.compare(current_password, user.password_hash); const valid = await bcrypt.compare(current_password, user.password_hash);
if (!valid) return res.status(401).json({ error: 'Current password is incorrect.', code: 401 }); if (!valid) return res.status(401).json({ error: 'Current password is incorrect.', code: 401 });
const hash = await bcrypt.hash(new_password, 12); const hash = await bcrypt.hash(new_password, 12);
db.get().prepare('UPDATE users SET password_hash = ? WHERE id = ?').run(hash, req.session.userId); db.get().prepare('UPDATE users SET password_hash = ? WHERE id = ?').run(hash, req.authUserId);
// Alle anderen Sessions dieses Users invalidieren (aktuelle behalten) // Alle anderen Sessions dieses Users invalidieren (aktuelle behalten)
const currentSid = req.sessionID; const currentSid = req.sessionID;
@@ -567,7 +569,7 @@ router.patch('/me/password', requireAuth, csrfMiddleware, async (req, res) => {
if (row.sid === currentSid) continue; if (row.sid === currentSid) continue;
try { try {
const sess = JSON.parse(row.sess); const sess = JSON.parse(row.sess);
if (sess.userId === req.session.userId) { if (sess.userId === req.authUserId) {
db.get().prepare('DELETE FROM sessions WHERE sid = ?').run(row.sid); db.get().prepare('DELETE FROM sessions WHERE sid = ?').run(row.sid);
} }
} catch { /* ignore malformed session */ } } catch { /* ignore malformed session */ }
@@ -589,7 +591,7 @@ router.delete('/users/:id', requireAuth, requireAdmin, csrfMiddleware, (req, res
try { try {
const userId = parseInt(req.params.id, 10); const userId = parseInt(req.params.id, 10);
if (userId === req.session.userId) { if (userId === req.authUserId) {
return res.status(400).json({ error: 'You cannot delete your own account.', code: 400 }); return res.status(400).json({ error: 'You cannot delete your own account.', code: 400 });
} }
+11 -3
View File
@@ -12,14 +12,22 @@ const isProduction = process.env.NODE_ENV === 'production';
function emit(level, mod, msg, extra) { function emit(level, mod, msg, extra) {
if (LEVELS[level] < currentLevel) return; if (LEVELS[level] < currentLevel) return;
const normalizedExtra = extra instanceof Error
? {
name: extra.name,
message: extra.message,
stack: extra.stack,
}
: extra;
if (isProduction) { if (isProduction) {
const entry = { ts: new Date().toISOString(), level, mod, msg }; const entry = { ts: new Date().toISOString(), level, mod, msg };
if (extra !== undefined) entry.extra = extra; if (normalizedExtra !== undefined) entry.extra = normalizedExtra;
process.stdout.write(JSON.stringify(entry) + '\n'); process.stdout.write(JSON.stringify(entry) + '\n');
} else { } else {
const prefix = `[${mod}]`; const prefix = `[${mod}]`;
if (extra !== undefined) { if (normalizedExtra !== undefined) {
console[level === 'debug' ? 'log' : level](prefix, msg, extra); console[level === 'debug' ? 'log' : level](prefix, msg, normalizedExtra);
} else { } else {
console[level === 'debug' ? 'log' : level](prefix, msg); console[level === 'debug' ? 'log' : level](prefix, msg);
} }