Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,48 @@
|
||||
import { createHmac, timingSafeEqual } from "node:crypto";
|
||||
import { loadWebConfig } from "@toolctrl/config";
|
||||
import { NOT_FOUND_ENVELOPE } from "~/utils/errors.server";
|
||||
|
||||
export const internalWebApiProxyHeader = "x-toolctrl-internal-web-api-proxy";
|
||||
export const internalWebApiProxySignatureHeader = "x-toolctrl-internal-web-api-proxy-signature";
|
||||
|
||||
export function requireInternalWebApiProxyRequest(request: Request) {
|
||||
if (request.headers.get(internalWebApiProxyHeader) !== "1" || !isValidInternalWebApiProxySignature(request)) {
|
||||
throw Response.json(NOT_FOUND_ENVELOPE, { status: 404 });
|
||||
}
|
||||
}
|
||||
|
||||
export function createInternalWebApiProxySignature(input: { method: string; url: string | URL; secret: string }) {
|
||||
const url = new URL(input.url);
|
||||
const canonicalTarget = `${input.method.toUpperCase()}\n${url.pathname}${url.search}`;
|
||||
return createHmac("sha256", input.secret).update(canonicalTarget).digest("base64url");
|
||||
}
|
||||
|
||||
function getApiAccessToken() {
|
||||
return loadWebConfig().config.apiAccessToken;
|
||||
}
|
||||
|
||||
export function createInternalWebApiProxyHeaders(request: Request, secret = getApiAccessToken()) {
|
||||
if (!secret) {
|
||||
throw new Error("API_ACCESS_TOKEN is required for internal web API proxy requests.");
|
||||
}
|
||||
|
||||
return {
|
||||
[internalWebApiProxyHeader]: "1",
|
||||
[internalWebApiProxySignatureHeader]: createInternalWebApiProxySignature({ method: request.method, url: request.url, secret }),
|
||||
};
|
||||
}
|
||||
|
||||
function isValidInternalWebApiProxySignature(request: Request) {
|
||||
const secret = getApiAccessToken();
|
||||
const signature = request.headers.get(internalWebApiProxySignatureHeader);
|
||||
if (!secret || !signature) return false;
|
||||
|
||||
const expected = createInternalWebApiProxySignature({ method: request.method, url: request.url, secret });
|
||||
return timingSafeEqualString(signature, expected);
|
||||
}
|
||||
|
||||
function timingSafeEqualString(left: string, right: string) {
|
||||
const leftBuffer = Buffer.from(left);
|
||||
const rightBuffer = Buffer.from(right);
|
||||
return leftBuffer.length === rightBuffer.length && timingSafeEqual(leftBuffer, rightBuffer);
|
||||
}
|
||||
Reference in new issue
Block a user