import type { NextFunction, Request, Response } from "express";
import { ConfigService } from "../config.js";
import { Logger } from "winston";
const DEFAULT_API_KEY_HEADER = "x-lunar-api-key";
export type AuthGuard = (rq: Request, rs: Response, f: NextFunction) => void;
export const noOpAuthGuard: AuthGuard = (
_req: Request,
_res: Response,
next: NextFunction,
): void => {
next();
};
/**
* Builds an Express middleware that enforces the “API key” header for the
* routes you mount it on, given on loaded configuration.
* - 401 when the header is missing
* - 403 when the key is present but wrong
* - calls `next()` when auth is disabled **or** the key is valid
*/
export function buildApiKeyGuard(
config: ConfigService,
logger: Logger,
apiKey?: string,
): AuthGuard {
if (!config.getConfig().auth?.enabled) {
logger.info("API key guard is not enabled");
return noOpAuthGuard;
}
if (!apiKey) {
logger.warn("API key guard is enabled but no API key configured");
return noOpAuthGuard;
}
logger.info("API key guard is enabled");
return function (req: Request, res: Response, next: NextFunction): void {
const headerName = (
config.getConfig().auth.header ?? DEFAULT_API_KEY_HEADER
).toLowerCase();
const supplied = req.headers[headerName] as string | undefined;
if (!supplied) {
logger.warn("API key not provided in headers, will not allow connection");
res.status(401).send("Unauthorized: API key required");
return;
}
if (supplied !== apiKey) {
logger.warn("Invalid API key provided, will not allow connection");
res.status(403).send("Forbidden: Invalid API key");
return;
}
next();
};
}