UNPKG

1.85 kBJavaScriptView Raw
1/**
2 * react-router v8.0.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11//#region lib/actions.ts
12function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
13 let originHeader = request.headers.get("origin");
14 let originDomain = null;
15 try {
16 originDomain = typeof originHeader === "string" && originHeader !== "null" ? new URL(originHeader).host : originHeader;
17 } catch {
18 throw new Error(`\`origin\` header is not a valid URL. Aborting the action.`);
19 }
20 let host = new URL(request.url).host;
21 if (originDomain && originDomain !== host) {
22 if (!isAllowedOrigin(originDomain, allowedActionOrigins)) throw new Error("The `request.url` host does not match `origin` header from a forwarded action request. Aborting the action.");
23 }
24}
25function matchWildcardDomain(domain, pattern) {
26 const domainParts = domain.split(".");
27 const patternParts = pattern.split(".");
28 if (patternParts.length < 1) return false;
29 if (domainParts.length < patternParts.length) return false;
30 while (patternParts.length) {
31 const patternPart = patternParts.pop();
32 const domainPart = domainParts.pop();
33 switch (patternPart) {
34 case "": return false;
35 case "*": if (domainPart) continue;
36 else return false;
37 case "**":
38 if (patternParts.length > 0) return false;
39 return domainPart !== void 0;
40 case void 0:
41 default: if (domainPart !== patternPart) return false;
42 }
43 }
44 return domainParts.length === 0;
45}
46function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
47 return allowedActionOrigins.some((allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin)));
48}
49//#endregion
50export { throwIfPotentialCSRFAttack };