Add admin-assisted password reset
There's no email infrastructure in this app, so a self-service "forgot password" flow isn't feasible yet. Adds a "Reset Password" button per user in the admin panel instead: generates a random temporary password (shown once, for the admin to relay out-of-band), overwrites the user's password hash, and signs them out of every existing session so a stolen session can't outlive the reset. Verified live: old password rejected after reset, new temporary password logs in successfully. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+17
-1
@@ -10,12 +10,13 @@ import {
|
||||
enableTotp, disableTotp, setBackupCodeHashes, setPodcastName,
|
||||
getShareToken, setShareToken, clearShareToken, getProjectByShareToken,
|
||||
adminGetAllUsers, adminDeleteUser, adminGetAllProjects, adminGetProject, adminDeleteProject,
|
||||
adminSetPassword, destroyAllSessionsForUser,
|
||||
} from './db.js';
|
||||
import { SqliteSessionStore } from './sessionStore.js';
|
||||
import {
|
||||
isValidEmail, isValidPassword, hashPassword, verifyPassword, requireAuth, requireAdmin, isAdminEmail,
|
||||
generateTotpSecret, totpKeyUri, verifyTotpToken,
|
||||
generateBackupCodes, hashBackupCodes, consumeBackupCode,
|
||||
generateBackupCodes, hashBackupCodes, consumeBackupCode, generateTemporaryPassword,
|
||||
} from './auth.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
@@ -389,6 +390,21 @@ app.delete('/api/admin/users/:id', requireAuth, requireAdmin, (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/admin/users/:id/reset-password — sets a random temporary password and
|
||||
// signs the user out everywhere, since there's no self-service "forgot password" flow yet.
|
||||
app.post('/api/admin/users/:id/reset-password', requireAuth, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const temporaryPassword = generateTemporaryPassword();
|
||||
const passwordHash = await hashPassword(temporaryPassword);
|
||||
adminSetPassword(req.params.id, passwordHash);
|
||||
destroyAllSessionsForUser(req.params.id);
|
||||
res.json({ temporaryPassword });
|
||||
} catch (err) {
|
||||
console.error('POST /api/admin/users/:id/reset-password error:', err);
|
||||
res.status(500).json({ error: 'Failed to reset password.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/admin/projects', requireAuth, requireAdmin, (req, res) => {
|
||||
try {
|
||||
res.json(adminGetAllProjects());
|
||||
|
||||
Reference in New Issue
Block a user