Import source: backend/src/middleware/adminAuth

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:12:24 +03:30
parent dea14b8377
commit efa493a93e
+33
View File
@@ -0,0 +1,33 @@
import { timingSafeEqual } from 'node:crypto';
import type { RequestHandler } from 'express';
import { env } from '../config/env.js';
import { HttpError } from './errorHandler.js';
import { sha256 } from '../utils/crypto.js';
function safeEqual(left: string, right: string) {
const a = Buffer.from(sha256(left));
const b = Buffer.from(sha256(right));
return a.length === b.length && timingSafeEqual(a, b);
}
export const requireAdmin: RequestHandler = (req, _res, next) => {
if (!env.adminApiKey) {
throw new HttpError(503, 'ADMIN_DISABLED', 'Admin API is not configured');
}
// IP Whitelisting (defense-in-depth)
const allowedIpsStr = process.env.ADMIN_ALLOWED_IPS;
if (allowedIpsStr) {
const allowedIps = allowedIpsStr.split(',').map((ip) => ip.trim());
const clientIp = req.ip ?? req.socket.remoteAddress ?? '';
if (!allowedIps.includes(clientIp) && !allowedIps.includes('::ffff:' + clientIp)) {
throw new HttpError(403, 'ADMIN_IP_RESTRICTED', 'Admin access denied from this IP address');
}
}
const key = req.header('x-admin-key') ?? '';
if (!key || !safeEqual(key, env.adminApiKey)) {
throw new HttpError(401, 'ADMIN_KEY_REQUIRED', 'Admin API key is required');
}
next();
};