Added account update form and e-mail verification.

This commit is contained in:
2026-07-22 05:49:39 +02:00
parent 17d34f6a80
commit 9b058fd44b
19 changed files with 1108 additions and 233 deletions

View File

@@ -1,4 +1,5 @@
import crypto from 'node:crypto';
import { Router } from 'express';
import IPCIDR from 'ip-cidr';
import argv from '../argv.js';
@@ -8,10 +9,16 @@ import {
flushUserKeys,
login,
removeUserKey,
sendEmailVerification,
signup,
updateSettings,
updateUser,
verifyEmail,
} from '../auth.js';
import { fetchUser } from '../users.js';
import {
fetchUser,
} from '../users.js';
// changes every time the process restarts, so a deploy invalidates all cached session users
// even if they're within the staleness window below
@@ -131,6 +138,60 @@ export async function signupApi(req, res) {
res.send(user);
}
async function updateUserApi(req, res) {
const updatedUser = await updateUser(req.body, req.user, req.session);
const sessions = await req.sessionStore.all();
req.session.user.refreshedAt = 0;
await Promise.all(sessions.map(async (session) => {
if (session.user?.id === req.user.id && session.id !== req.sessionID) {
if (req.body.credentials?.password) {
// we changed the password, destroy all user sessions except our own (we already provided all the credentials)
await req.sessionStore.destroy(session.id);
}
else {
// mark our sessions as stale
session.user.refreshedAt = 0; // eslint-disable-line no-param-reassign
await req.sessionStore.set(session.id, session);
}
}
}));
res.send(updatedUser);
}
async function sendEmailVerificationApi(req, res) {
await sendEmailVerification(req.user, null, 'verify');
res.status(204).send();
}
async function verifyEmailApi(req, res) {
const userId = Number(req.body.userId) || null;
await verifyEmail(userId, req.body.token);
const sessions = await req.sessionStore.all();
await Promise.all(sessions.map(async (session) => {
if (session.user?.id === userId) {
session.user.refreshedAt = 0; // eslint-disable-line no-param-reassign
await req.sessionStore.set(session.id, session);
}
}));
res.status(204).send();
}
async function updateSettingsApi(req, res) {
const updatedSettings = await updateSettings(req.body, req.user);
req.session.user.settings = updatedSettings;
res.send(updatedSettings);
}
export async function fetchUserKeysApi(req, res) {
const keys = await fetchUserKeys(req.user);
@@ -154,3 +215,28 @@ export async function flushUserKeysApi(req, res) {
res.status(204).send();
}
export const authRouter = Router();
// SESSION
// authRouter.use(setUserApi);
authRouter.post('/api/session', loginApi);
authRouter.delete('/api/session', logoutApi);
// USERS
authRouter.post('/api/users', signupApi);
// SETTINGS
authRouter.patch('/api/me', updateUserApi);
authRouter.patch('/api/me/settings', updateSettingsApi);
// EMAIL VERIFICATION
authRouter.post('/api/me/email_verification', sendEmailVerificationApi);
authRouter.post('/api/emails/verify', verifyEmailApi); // usable without session
// API KEYS
authRouter.get('/api/me/keys', fetchUserKeysApi);
authRouter.post('/api/me/keys', createKeyApi);
authRouter.delete('/api/me/keys/:keyIdentifier', removeUserKeyApi);
authRouter.delete('/api/me/keys', flushUserKeysApi);