mirror of
https://dev.azure.com/tstanciu94/PhantomMind/_git/Bitip
synced 2025-10-13 01:52:19 +03:00
111 lines
2.8 KiB
TypeScript
111 lines
2.8 KiB
TypeScript
import { Request, Response, NextFunction } from 'express';
|
|
import config from '../services/config.js';
|
|
import logger from '../services/logger.js';
|
|
|
|
interface AuthenticatedRequest extends Request {
|
|
apiKeyType?: 'frontend' | 'external';
|
|
}
|
|
|
|
export const apiKeyAuth = (
|
|
req: AuthenticatedRequest,
|
|
res: Response,
|
|
next: NextFunction
|
|
): void => {
|
|
if (req.path === '/health') {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
const apiKey = req.header('X-API-Key') || (req.query.apikey as string);
|
|
|
|
if (!apiKey) {
|
|
logger.warn('API request without API key', { ip: req.ip, path: req.path });
|
|
res.status(401).json({
|
|
error: 'Unauthorized',
|
|
message: 'API key is required',
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Check frontend API key
|
|
if (apiKey === config.apiKeys.frontend) {
|
|
// Validate origin for frontend API key
|
|
const origin = req.headers.origin || req.headers.referer;
|
|
const allowedOrigins = config.frontendAllowedOrigins;
|
|
|
|
// If no origin/referer header, check if it's a same-origin request by checking Host header
|
|
if (!origin) {
|
|
const host = req.headers.host;
|
|
const protocol = req.protocol || 'http';
|
|
const requestOrigin = `${protocol}://${host}`;
|
|
|
|
// Check if the request comes from an allowed origin based on Host header
|
|
const isSameOriginAllowed = allowedOrigins.some(allowed =>
|
|
requestOrigin.startsWith(allowed)
|
|
);
|
|
|
|
if (!isSameOriginAllowed) {
|
|
logger.warn('Frontend API key used without origin/referer header', {
|
|
ip: req.ip,
|
|
path: req.path,
|
|
host: host,
|
|
requestOrigin: requestOrigin,
|
|
userAgent: req.headers['user-agent'],
|
|
});
|
|
res.status(403).json({
|
|
error: 'Forbidden',
|
|
message: 'Origin header required for frontend API key',
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Same-origin request allowed
|
|
req.apiKeyType = 'frontend';
|
|
next();
|
|
return;
|
|
}
|
|
|
|
const isOriginAllowed = allowedOrigins.some(allowed =>
|
|
origin.startsWith(allowed)
|
|
);
|
|
|
|
if (!isOriginAllowed) {
|
|
logger.warn('Frontend API key used from invalid origin', {
|
|
ip: req.ip,
|
|
origin: origin,
|
|
path: req.path,
|
|
allowedOrigins: allowedOrigins,
|
|
});
|
|
res.status(403).json({
|
|
error: 'Forbidden',
|
|
message: 'Invalid origin for frontend API key',
|
|
});
|
|
return;
|
|
}
|
|
|
|
req.apiKeyType = 'frontend';
|
|
next();
|
|
return;
|
|
}
|
|
|
|
// Check external API keys
|
|
if (config.apiKeys.external.includes(apiKey)) {
|
|
req.apiKeyType = 'external';
|
|
next();
|
|
return;
|
|
}
|
|
|
|
logger.warn('API request with invalid API key', {
|
|
ip: req.ip,
|
|
path: req.path,
|
|
apiKey: apiKey.substring(0, 8) + '...',
|
|
});
|
|
|
|
res.status(401).json({
|
|
error: 'Unauthorized',
|
|
message: 'Invalid API key',
|
|
});
|
|
};
|
|
|
|
export default apiKeyAuth;
|