Spaces:
Runtime error
Runtime error
File size: 2,294 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | "use strict";
const http = require("node:http");
const HIGH_RISK_METHOD_RULES = [
[/^\/api\/auth\/login\/?$/, ["POST"]],
[/^\/api\/auth\/logout\/?$/, ["POST"]],
[/^\/api\/keys\/?$/, ["GET", "POST"]],
[/^\/api\/keys\/[^/]+\/?$/, ["GET", "PATCH", "DELETE"]],
];
let installed = false;
function getPathname(req) {
const rawUrl = typeof req?.url === "string" && req.url ? req.url : "/";
try {
return new URL(rawUrl, "http://localhost").pathname;
} catch {
return rawUrl.split("?")[0] || "/";
}
}
function getAllowedMethods(pathname) {
for (const [pattern, methods] of HIGH_RISK_METHOD_RULES) {
if (pattern.test(pathname)) return methods;
}
return null;
}
function getAllowHeader(pathname) {
const methods = getAllowedMethods(pathname);
return methods ? methods.join(", ") : null;
}
function maybeHandleDisallowedMethod(req, res) {
const method = typeof req?.method === "string" ? req.method.toUpperCase() : "";
const pathname = getPathname(req);
const methods = getAllowedMethods(pathname);
if (!methods || method === "OPTIONS" || methods.includes(method)) return false;
res.statusCode = 405;
res.setHeader("Allow", methods.join(", "));
res.setHeader("Cache-Control", "no-store");
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.end(
JSON.stringify({
error: {
code: "METHOD_NOT_ALLOWED",
message: `${method || "Method"} is not allowed`,
},
})
);
return true;
}
function wrapRequestListenerWithMethodGuard(listener) {
return function methodGuardRequestHandler(req, res) {
if (maybeHandleDisallowedMethod(req, res)) return;
return listener.call(this, req, res);
};
}
function installHttpMethodGuard() {
if (installed) return;
installed = true;
const originalCreateServer = http.createServer.bind(http);
http.createServer = function createServerWithMethodGuard(...args) {
const lastFnIdx = args.map((arg) => typeof arg === "function").lastIndexOf(true);
if (lastFnIdx >= 0) {
args[lastFnIdx] = wrapRequestListenerWithMethodGuard(args[lastFnIdx]);
}
return originalCreateServer(...args);
};
}
module.exports = {
getAllowHeader,
maybeHandleDisallowedMethod,
wrapRequestListenerWithMethodGuard,
installHttpMethodGuard,
};
|