@tanstack/start-client-core
Version:
Modern and scalable routing for React applications
63 lines (62 loc) • 2.79 kB
JavaScript
import { createMiddleware } from "./createMiddleware.js";
import { createIsomorphicFn } from "@tanstack/start-fn-stubs";
//#region src/createCsrfMiddleware.ts
var csrfSymbol = Symbol.for("tanstack-start:csrf-middleware");
var innerCreateCsrfMiddleware = (opts = {}) => {
const middleware = createMiddleware().server(async (ctx) => {
const csrfCtx = ctx;
if (opts.filter && !await opts.filter(csrfCtx)) return ctx.next();
if (await isCsrfRequestAllowed(opts, csrfCtx)) return ctx.next();
return getFailureResponse(opts, csrfCtx);
});
if (process.env.NODE_ENV !== "production") Object.defineProperty(middleware, csrfSymbol, { value: true });
return middleware;
};
var createCsrfMiddleware = createIsomorphicFn().server(innerCreateCsrfMiddleware);
async function isCsrfRequestAllowed(opts, ctx) {
const result = await getCsrfRequestValidationResult(opts, ctx);
return result === true || result === void 0 && opts.allowRequestsWithoutOriginCheck === true;
}
async function getCsrfRequestValidationResult(opts, ctx) {
const fetchSite = ctx.request.headers.get("Sec-Fetch-Site");
if (fetchSite !== null) return matchValue(opts.secFetchSite ?? "same-origin", fetchSite, ctx);
const origin = ctx.request.headers.get("Origin");
if (origin !== null) {
if (opts.origin) return matchValue(opts.origin, origin, ctx);
return origin === new URL(ctx.request.url).origin;
}
const referer = ctx.request.headers.get("Referer");
if (referer === null || opts.referer === false) return;
if (typeof opts.referer === "function") return opts.referer(referer, ctx);
if (opts.origin) {
const refererOrigin = getOriginFromUrl(referer);
return refererOrigin !== void 0 && matchValue(opts.origin, refererOrigin, ctx);
}
return isRefererSameOrigin(referer, new URL(ctx.request.url).origin);
}
async function matchValue(matcher, value, ctx) {
if (typeof matcher === "function") return matcher(value, ctx);
if (Array.isArray(matcher)) return matcher.includes(value);
return value === matcher;
}
function getOriginFromUrl(url) {
try {
return new URL(url).origin;
} catch {
return;
}
}
function isRefererSameOrigin(referer, requestOrigin) {
if (referer === requestOrigin) return true;
if (!referer.startsWith(requestOrigin)) return false;
if (referer.length === requestOrigin.length) return true;
const code = referer.charCodeAt(requestOrigin.length);
return code === 47 || code === 63 || code === 35;
}
async function getFailureResponse(opts, ctx) {
if (typeof opts.failureResponse === "function") return opts.failureResponse(ctx);
return opts.failureResponse?.clone() ?? new Response("Forbidden", { status: 403 });
}
//#endregion
export { createCsrfMiddleware, csrfSymbol, getCsrfRequestValidationResult, isCsrfRequestAllowed };
//# sourceMappingURL=createCsrfMiddleware.js.map