Fix admin authorization and harden chat requests
CI / check (22) (push) Successful in 10m3s
CI / check (24) (push) Successful in 9m34s

This commit is contained in:
2026-10-05 22:49:29 +02:00
parent e8cd13a0af
commit c48e1b17c4
38 changed files with 4897 additions and 1257 deletions
+17 -8
View File
@@ -2,6 +2,7 @@
* @file Verarbeitet Registrierung, Anmeldung, Abmeldung und die Abfrage der aktuellen Sitzung.
*/
import express from "express";
import {asyncHandler} from "../middleware/asyncHandler.js";
import bcrypt from "bcrypt";
import {validateBody} from "../middleware/validate.js";
@@ -19,23 +20,31 @@ const credentialsValidator = (body) => {
export function createAuthRouter({repositories, authRateLimiters, config}) {
const router = express.Router();
router.post("/register", ...authRateLimiters, validateBody(credentialsValidator), async (req, res) => {
router.post("/register", ...authRateLimiters, validateBody(credentialsValidator), asyncHandler(async (req, res) => {
const {username, password, inviteCode} = req.validatedBody;
if (config.registrationInviteCode && inviteCode !== config.registrationInviteCode) {
return res.status(403).json({error: "Valid invite code is required"});
}
if (repositories.getUser(username)) {
return res.status(400).json({error: "User already exists"});
return res.status(409).json({error: "User already exists", code: "USERNAME_TAKEN"});
}
const hashed = await bcrypt.hash(password, 10);
repositories.insertUser(username, hashed);
try {
repositories.insertUser(username, hashed);
} catch (error) {
// The precheck can race while bcrypt yields; the database is authoritative.
if (["SQLITE_CONSTRAINT_PRIMARYKEY", "SQLITE_CONSTRAINT_UNIQUE"].includes(error.code)) {
return res.status(409).json({error: "User already exists", code: "USERNAME_TAKEN"});
}
throw error;
}
req.session.user = username;
req.session.sessionVersion = 0;
return res.json({message: "Registration successful"});
});
}));
router.post("/login", ...authRateLimiters, validateBody(credentialsValidator), async (req, res) => {
router.post("/login", ...authRateLimiters, validateBody(credentialsValidator), asyncHandler(async (req, res) => {
const {username, password} = req.validatedBody;
const user = repositories.getUser(username);
if (!user) return res.status(400).json({error: "User not found"});
@@ -44,10 +53,10 @@ export function createAuthRouter({repositories, authRateLimiters, config}) {
req.session.user = username;
req.session.sessionVersion = Number(user.session_version || 0);
return res.json({message: "Login successful"});
});
}));
router.post("/logout", (req, res) => {
req.session.destroy(() => res.json({message: "Logged out"}));
router.post("/logout", (req, res, next) => {
req.session.destroy(error => error ? next(error) : res.json({message: "Logged out"}));
});
router.get("/session", (req, res) => {