star-chart-search-enhancer/scripts/mock-protected-api.mjs

118 lines
3.2 KiB
JavaScript

import http from "node:http";
export function createMockProtectedApiServer({ port = 4319 } = {}) {
let server;
return {
get baseUrl() {
const address = server?.address();
const resolvedPort =
typeof address === "object" && address ? address.port : port;
return `http://127.0.0.1:${resolvedPort}`;
},
async start() {
server = http.createServer(async (request, response) => {
if (request.url === "/api/mock/protected") {
const authHeader = readBearerToken(request, response);
if (!authHeader) {
return;
}
response.writeHead(200, { "content-type": "application/json" });
response.end(
JSON.stringify({
ok: true,
source: "mock-protected-api",
message: "authorized",
receivedAuthHeader: authHeader
})
);
return;
}
if (request.url === "/api/mock/batches" && request.method === "POST") {
const authHeader = readBearerToken(request, response);
if (!authHeader) {
return;
}
const payload = await readJsonBody(request);
const authors = Array.isArray(payload?.authors) ? payload.authors : [];
response.writeHead(200, { "content-type": "application/json" });
response.end(
JSON.stringify({
ok: true,
source: "mock-batch-submit",
acceptedCount: authors.length,
batchId:
typeof payload?.batchId === "string" ? payload.batchId : null,
receivedAuthHeader: authHeader
})
);
return;
}
response.writeHead(404, { "content-type": "application/json" });
response.end(JSON.stringify({ ok: false, error: "not-found" }));
});
await new Promise((resolve) => {
server.listen(port, "127.0.0.1", resolve);
});
},
async close() {
if (!server) {
return;
}
await new Promise((resolve, reject) => {
server.close((error) => {
if (error) {
reject(error);
return;
}
resolve(undefined);
});
});
}
};
}
function readBearerToken(request, response) {
const authHeader = request.headers.authorization ?? "";
const isBearer =
typeof authHeader === "string" &&
authHeader.startsWith("Bearer ") &&
authHeader.length > "Bearer ".length;
if (!isBearer) {
response.writeHead(401, { "content-type": "application/json" });
response.end(JSON.stringify({ ok: false, error: "unauthorized" }));
return null;
}
return authHeader;
}
async function readJsonBody(request) {
const chunks = [];
for await (const chunk of request) {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
}
if (chunks.length === 0) {
return null;
}
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
}
if (import.meta.url === `file://${process.argv[1]}`) {
const server = createMockProtectedApiServer();
await server.start();
console.log(`mock protected api listening on ${server.baseUrl}`);
}