Fix session revocation bug that could log out current device

- Fix: DELETE all other sessions query used empty string fallback when
  req.sessionId was undefined, causing id != '' to match ALL rows
  (including current session). Now skips deletion if sessionId unknown.
- Fix: Revoke All endpoint returns error if current session not identified
- Fix: var confirm shadowing window.confirm in password change handler
This commit is contained in:
Daniel 2026-04-09 02:33:00 +02:00
parent 4fa2b58d75
commit adf1365fa2
3 changed files with 9 additions and 6 deletions

View file

@ -594,13 +594,13 @@ document.addEventListener('DOMContentLoaded', function() {
e.preventDefault();
var current = document.getElementById('pw-current');
var newPw = document.getElementById('pw-new');
var confirm = document.getElementById('pw-confirm');
var confirmPw = document.getElementById('pw-confirm');
var status = document.getElementById('pw-change-status');
if (!current || !newPw || !confirm) return;
if (!current || !newPw || !confirmPw) return;
if (!current.value || !newPw.value) { showToast('Fill in all fields', 'error'); return; }
if (newPw.value.length < 8) { showToast('New password must be 8+ characters', 'error'); return; }
if (newPw.value !== confirm.value) { showToast('Passwords do not match', 'error'); return; }
if (newPw.value !== confirmPw.value) { showToast('Passwords do not match', 'error'); return; }
if (status) { status.textContent = 'Changing...'; status.style.color = 'var(--g500)'; }
@ -614,7 +614,7 @@ document.addEventListener('DOMContentLoaded', function() {
if (data.success) {
showToast(data.message || 'Password changed', 'success');
if (data.passwordWarning) setTimeout(function() { showToast(data.passwordWarning, 'warning'); }, 1500);
current.value = ''; newPw.value = ''; confirm.value = '';
current.value = ''; newPw.value = ''; confirmPw.value = '';
if (status) { status.textContent = ''; }
if (typeof loadSessions === 'function') loadSessions();
} else {

View file

@ -449,7 +449,9 @@ router.post('/change-password', authMiddleware, async (req, res) => {
await db.run('UPDATE users SET password = ? WHERE id = ?', [hash, req.user.id]);
// Destroy all OTHER sessions (keep current one)
try { await db.run('DELETE FROM user_sessions WHERE user_id = ? AND id != ?', [req.user.id, req.sessionId || '']); } catch (e) { /* best effort */ }
if (req.sessionId) {
try { await db.run('DELETE FROM user_sessions WHERE user_id = ? AND id != ?', [req.user.id, req.sessionId]); } catch (e) { /* best effort */ }
}
await db.run('INSERT INTO audit_log (user_id, action, ip_address) VALUES (?, ?, ?)', [req.user.id, 'password_changed', req.ip]);

View file

@ -38,9 +38,10 @@ router.delete('/:id', async function(req, res) {
// Revoke all other sessions
router.delete('/', async function(req, res) {
try {
if (!req.sessionId) return res.status(400).json({ error: 'Current session not identified. Log out and log back in.' });
var result = await db.run(
'DELETE FROM user_sessions WHERE user_id = ? AND id != ?',
[req.user.id, req.sessionId || '']
[req.user.id, req.sessionId]
);
res.json({ success: true, revoked: result.changes });
} catch (e) {