Added account update form and e-mail verification.
This commit is contained in:
@@ -219,12 +219,12 @@ export async function updateNotificationGraphql(query, req) {
|
||||
return updatedNotification;
|
||||
}
|
||||
|
||||
export const router = Router();
|
||||
export const alertsRouter = Router();
|
||||
|
||||
router.get('/api/alerts', fetchAlertsApi);
|
||||
router.post('/api/alerts', createAlertApi);
|
||||
router.delete('/api/alerts/:alertId', removeAlertApi);
|
||||
alertsRouter.get('/api/alerts', fetchAlertsApi);
|
||||
alertsRouter.post('/api/alerts', createAlertApi);
|
||||
alertsRouter.delete('/api/alerts/:alertId', removeAlertApi);
|
||||
|
||||
router.get('/api/users/:userId/notifications', fetchNotificationsApi);
|
||||
router.patch('/api/users/:userId/notifications', updateNotificationsApi);
|
||||
router.patch('/api/users/:userId/notifications/:notificationId', updateNotificationApi);
|
||||
alertsRouter.get('/api/users/:userId/notifications', fetchNotificationsApi);
|
||||
alertsRouter.patch('/api/users/:userId/notifications', updateNotificationsApi);
|
||||
alertsRouter.patch('/api/users/:userId/notifications/:notificationId', updateNotificationApi);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -30,6 +30,7 @@ export default async function mainHandler(req, res, next) {
|
||||
role: req.user.role,
|
||||
abilities: req.user.abilities,
|
||||
avatar: req.user.avatar,
|
||||
isEmailVerified: req.user.isEmailVerified,
|
||||
},
|
||||
assets: req.user
|
||||
? {
|
||||
|
||||
@@ -12,19 +12,11 @@ import initLogger from '../logger.js';
|
||||
|
||||
import redis from '../redis.js';
|
||||
import queryBoolean from '../utils/query-boolean.js';
|
||||
import { actorsRouter } from './actors.js';
|
||||
|
||||
import { router as alertsRouter } from './alerts.js';
|
||||
import {
|
||||
createKeyApi,
|
||||
fetchUserKeysApi,
|
||||
flushUserKeysApi,
|
||||
loginApi,
|
||||
logoutApi,
|
||||
removeUserKeyApi,
|
||||
setUserApi,
|
||||
signupApi,
|
||||
} from './auth.js';
|
||||
import { actorsRouter } from './actors.js';
|
||||
import { alertsRouter } from './alerts.js';
|
||||
import { authRouter, setUserApi } from './auth.js';
|
||||
|
||||
import consentHandler from './consent.js';
|
||||
|
||||
import { fetchEntitiesApi } from './entities.js';
|
||||
@@ -91,8 +83,6 @@ export default async function initServer() {
|
||||
store: redisStore,
|
||||
}));
|
||||
|
||||
router.use(setUserApi);
|
||||
|
||||
// Vite integration
|
||||
if (isProduction) {
|
||||
app.enable('trust proxy');
|
||||
@@ -118,6 +108,7 @@ export default async function initServer() {
|
||||
router.use(viteDevMiddleware);
|
||||
}
|
||||
|
||||
router.use(setUserApi); // we need to set the IP before the restriction handler
|
||||
router.use(restrictionHandler);
|
||||
|
||||
router.get('/consent', (_req, res) => {
|
||||
@@ -134,22 +125,10 @@ export default async function initServer() {
|
||||
next();
|
||||
});
|
||||
|
||||
// SESSION
|
||||
router.post('/api/session', loginApi);
|
||||
router.delete('/api/session', logoutApi);
|
||||
|
||||
// USERS
|
||||
router.post('/api/users', signupApi);
|
||||
|
||||
// API KEYS
|
||||
router.get('/api/me/keys', fetchUserKeysApi);
|
||||
router.post('/api/me/keys', createKeyApi);
|
||||
router.delete('/api/me/keys/:keyIdentifier', removeUserKeyApi);
|
||||
router.delete('/api/me/keys', flushUserKeysApi);
|
||||
|
||||
router.use(userRouter);
|
||||
router.use(stashesRouter);
|
||||
router.use(alertsRouter);
|
||||
router.use(authRouter);
|
||||
router.use(scenesRouter);
|
||||
router.use(actorsRouter);
|
||||
router.use(syncRouter);
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
fetchUser,
|
||||
fetchUserTemplates,
|
||||
removeTemplate,
|
||||
updateSettings,
|
||||
} from '../users.js';
|
||||
|
||||
async function fetchUserApi(req, res) {
|
||||
@@ -15,14 +14,6 @@ async function fetchUserApi(req, res) {
|
||||
res.send(user);
|
||||
}
|
||||
|
||||
async function updateSettingsApi(req, res) {
|
||||
const updatedSettings = await updateSettings(req.body, req.user);
|
||||
|
||||
req.session.user.settings = updatedSettings;
|
||||
|
||||
res.send(updatedSettings);
|
||||
}
|
||||
|
||||
async function fetchUserTemplatesApi(req, res) {
|
||||
const templates = await fetchUserTemplates(req.user);
|
||||
|
||||
@@ -52,8 +43,6 @@ export const router = Router();
|
||||
router.get('/api/users/:userId', fetchUserApi);
|
||||
router.get('/api/users/:userId/templates', fetchUserTemplatesApi);
|
||||
|
||||
router.patch('/api/me/settings', updateSettingsApi);
|
||||
|
||||
router.post('/api/templates', createTemplateApi);
|
||||
router.delete('/api/templates/:templateId', removeTemplateApi);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user