step 10.7: done

This commit is contained in:
bepis
2026-10-23 00:07:22 +11:00
parent 9a31c7c460
commit add65e9e5b
5 changed files with 288 additions and 21 deletions
+30 -1
View File
@@ -99,12 +99,19 @@ function createApp() {
app.get('/api/heroes/:name', heroProfileRoutes.getHeroProfile);
// Catch-all: serve 404 page for unknown paths (HTML requests only).
// API paths still return JSON errors via the central handler.
// API paths (/api/*) always return JSON errors, never HTML.
// Placed before static files so it intercepts non-file paths.
const PUBLIC_DIR = path.resolve(__dirname, '../public');
app.use((req, res, next) => {
// If a route already set headers, let it through (e.g., static file not found)
if (res.headersSent) return next();
// API paths always return JSON, regardless of Accept header
if (req.path.startsWith('/api/')) {
return res.status(404).json({
ok: false,
error: { code: 'NOT_FOUND', message: 'Resource not found.' },
});
}
if (req.accepts('html')) {
return res.status(404).sendFile(path.join(PUBLIC_DIR, '404.html'));
}
@@ -134,6 +141,28 @@ function createApp() {
});
}
// Express JSON parser: malformed JSON → 400
if (err instanceof SyntaxError && err.status === 400) {
return res.status(400).json({
ok: false,
error: {
code: 'INVALID_JSON',
message: 'Malformed JSON in request body.',
},
});
}
// Express JSON parser: body exceeds size limit → 413
if (err.status === 413) {
return res.status(413).json({
ok: false,
error: {
code: 'PAYLOAD_TOO_LARGE',
message: 'Request body exceeds the maximum allowed size.',
},
});
}
// Check for Zod-like validation errors
if (err.name === 'ZodError' || (err.errors && Array.isArray(err.errors))) {
return res.status(400).json({
+6 -2
View File
@@ -47,7 +47,9 @@ async function handleRegister(req, res) {
// Regenerate session to prevent fixation
req.session.regenerate((err) => {
if (err) throw new AppError('INTERNAL_ERROR', 'Session regeneration failed.', 500);
if (err) {
return next(err);
}
req.session.userId = user.id;
req.session.username = user.username;
res.status(201).json({ ok: true, data: { user: { id: user.id, username: user.username } } });
@@ -65,7 +67,9 @@ async function handleLogin(req, res) {
// Regenerate session to prevent fixation
req.session.regenerate((err) => {
if (err) throw new AppError('INTERNAL_ERROR', 'Session regeneration failed.', 500);
if (err) {
return next(err);
}
req.session.userId = user.id;
res.json({ ok: true, data: { user: { id: user.id, username: user.username }, hasHero: userHasHero(user.id) } });
});