← back to Jill Website
src/middleware/auth.ts
45 lines
import { Request, Response, NextFunction } from 'express';
/**
* Simple authentication middleware for admin routes
* In production, replace with proper session-based or JWT authentication
*/
export function requireAuth(req: Request, res: Response, next: NextFunction): void {
const authHeader = req.headers.authorization;
const adminPassword = process.env.ADMIN_PASSWORD;
if (!adminPassword) {
throw new Error('Missing required environment variable: ADMIN_PASSWORD');
}
if (!authHeader) {
res.setHeader('WWW-Authenticate', 'Basic realm="Admin Area"');
res.status(401).json({ error: 'Authentication required' });
return;
}
// P1 fix 2026-05-04: malformed Authorization header (e.g., "Bearer", no space)
// would crash with "Buffer.from(undefined, 'base64')" and leak a 500 stack trace.
const parts = authHeader.split(' ');
if (parts.length !== 2 || parts[0] !== 'Basic') {
res.status(401).json({ error: 'Invalid authorization format' });
return;
}
const auth = Buffer.from(parts[1], 'base64').toString().split(':');
const username = auth[0] ?? '';
const password = auth[1] ?? '';
// P1 fix 2026-05-04: timing-safe compare to avoid leaking password length.
const usernameOk = username === 'admin';
const pwBuf = Buffer.from(password);
const adminBuf = Buffer.from(adminPassword);
const passwordOk = pwBuf.length === adminBuf.length
&& require('node:crypto').timingSafeEqual(pwBuf, adminBuf);
if (usernameOk && passwordOk) {
next();
} else {
res.status(403).json({ error: 'Invalid credentials' });
}
}