@holo-js/security 0.3.19 → 0.3.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -293,28 +293,6 @@ function getHeaderToken(request) {
293
293
  const { header } = getSecurityRuntime().config.csrf;
294
294
  return request.headers.get(header)?.trim() || void 0;
295
295
  }
296
- function getRequestOrigin(request) {
297
- const origin = request.headers.get("origin")?.trim();
298
- if (origin) {
299
- return origin;
300
- }
301
- const referer = request.headers.get("referer")?.trim();
302
- if (!referer) {
303
- return void 0;
304
- }
305
- try {
306
- return new URL(referer).origin;
307
- } catch {
308
- return void 0;
309
- }
310
- }
311
- function isSameOriginRequest(request) {
312
- const requestOrigin = getRequestOrigin(request);
313
- if (!requestOrigin) {
314
- return false;
315
- }
316
- return requestOrigin === new URL(request.url).origin;
317
- }
318
296
  async function readFormToken(request) {
319
297
  const { field: field2 } = getSecurityRuntime().config.csrf;
320
298
  try {
@@ -343,9 +321,6 @@ async function verifyRequest(request, options) {
343
321
  }
344
322
  return;
345
323
  }
346
- if (isSameOriginRequest(request)) {
347
- return;
348
- }
349
324
  const requestToken = await readFormToken(request);
350
325
  if (requestToken !== cookieToken) {
351
326
  throw new SecurityCsrfError();
@@ -432,7 +407,6 @@ var csrfInternals = {
432
407
  getCookieToken,
433
408
  getHeaderToken,
434
409
  isSecureRequest,
435
- isSameOriginRequest,
436
410
  readFormToken,
437
411
  isExcludedPath,
438
412
  isSafeMethod,
@@ -3,7 +3,7 @@ import {
3
3
  getSecurityRuntime,
4
4
  isSecureRequest,
5
5
  token
6
- } from "./chunk-G3HBF4Q5.mjs";
6
+ } from "./chunk-5SCCUNBO.mjs";
7
7
  import {
8
8
  SECURITY_CLIENT_CONFIG_COOKIE,
9
9
  createSecurityClientConfig,
package/dist/index.d.ts CHANGED
@@ -23,7 +23,6 @@ declare function decodeCsrfToken(token: string): {
23
23
  declare function isValidSignedCsrfToken(token: string): boolean;
24
24
  declare function getCookieToken(request: Request): string | undefined;
25
25
  declare function getHeaderToken(request: Request): string | undefined;
26
- declare function isSameOriginRequest(request: Request): boolean;
27
26
  declare function readFormToken(request: Request): Promise<string | undefined>;
28
27
  declare function token(request: Request): Promise<string>;
29
28
  declare function field(request: Request): Promise<SecurityCsrfField>;
@@ -45,7 +44,6 @@ declare const csrfInternals: {
45
44
  getCookieToken: typeof getCookieToken;
46
45
  getHeaderToken: typeof getHeaderToken;
47
46
  isSecureRequest: typeof isSecureRequest;
48
- isSameOriginRequest: typeof isSameOriginRequest;
49
47
  readFormToken: typeof readFormToken;
50
48
  isExcludedPath: typeof isExcludedPath;
51
49
  isSafeMethod: typeof isSafeMethod;
package/dist/index.mjs CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  token,
35
35
  verify,
36
36
  verifySignedToken
37
- } from "./chunk-G3HBF4Q5.mjs";
37
+ } from "./chunk-5SCCUNBO.mjs";
38
38
  import {
39
39
  SecurityCsrfError,
40
40
  SecurityRateLimitError,
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  prepareCsrfCookies
3
- } from "../chunk-5M3RHQIG.mjs";
3
+ } from "../chunk-CTRTL4CO.mjs";
4
4
  import {
5
+ cors,
6
+ getSecurityRuntime,
5
7
  protect
6
- } from "../chunk-G3HBF4Q5.mjs";
8
+ } from "../chunk-5SCCUNBO.mjs";
7
9
  import "../chunk-FUOZWKHK.mjs";
8
10
  import {
9
11
  SecurityCsrfError
@@ -38,8 +40,34 @@ async function issueCsrfCookie(request) {
38
40
  }
39
41
  return response;
40
42
  }
43
+ async function actionRequest(request) {
44
+ const { field, header } = getSecurityRuntime().config.csrf;
45
+ if (!request.headers.has("next-action") || request.headers.get(header)?.trim() || !request.headers.get("content-type")?.startsWith("multipart/form-data")) return request;
46
+ try {
47
+ const data = await request.clone().formData();
48
+ const root = data.get("0");
49
+ if (typeof root !== "string") return request;
50
+ const args = JSON.parse(root);
51
+ if (!Array.isArray(args)) return request;
52
+ for (const argument of args) {
53
+ if (typeof argument !== "string") continue;
54
+ const part = /^\$K([0-9a-f]+)$/.exec(argument)?.[1];
55
+ if (!part) continue;
56
+ const token = data.get(`_${Number.parseInt(part, 16)}_${field}`);
57
+ if (typeof token !== "string") continue;
58
+ const headers = new Headers(request.headers);
59
+ headers.set(header, token);
60
+ return new Request(request.clone(), { headers });
61
+ }
62
+ } catch {
63
+ return request;
64
+ }
65
+ return request;
66
+ }
41
67
  function csrfProtection() {
42
68
  return async (request) => {
69
+ const preflight = cors.preflight(request);
70
+ if (preflight) return preflight;
43
71
  if (request.method.trim().toUpperCase() === "TRACE") {
44
72
  return new Response("Method Not Allowed", {
45
73
  status: 405,
@@ -47,14 +75,18 @@ function csrfProtection() {
47
75
  });
48
76
  }
49
77
  try {
50
- await protect(request);
78
+ await protect(await actionRequest(request));
51
79
  } catch (error) {
52
80
  if (error instanceof SecurityCsrfError) {
53
- return createCsrfErrorResponse(error);
81
+ return cors.apply(request, createCsrfErrorResponse(error));
54
82
  }
55
83
  throw error;
56
84
  }
57
- return await issueCsrfCookie(request);
85
+ const response = await issueCsrfCookie(request);
86
+ if (response) return cors.apply(request, response);
87
+ if ([...cors.headers(request)].length === 0) return void 0;
88
+ const { NextResponse } = await import("next/server.js");
89
+ return cors.apply(request, NextResponse.next());
58
90
  };
59
91
  }
60
92
  var nextSecurityInternals = {
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  prepareCsrfCookies
3
- } from "../chunk-5M3RHQIG.mjs";
3
+ } from "../chunk-CTRTL4CO.mjs";
4
4
  import {
5
+ cors,
5
6
  protect
6
- } from "../chunk-G3HBF4Q5.mjs";
7
+ } from "../chunk-5SCCUNBO.mjs";
7
8
  import "../chunk-FUOZWKHK.mjs";
8
9
  import {
9
10
  SecurityCsrfError
@@ -19,11 +20,12 @@ import {
19
20
  getRequestHeaders,
20
21
  getRequestURL,
21
22
  readRawBody,
22
- setCookie
23
+ setCookie,
24
+ setResponseHeader
23
25
  } from "h3";
24
26
  function isSafeMethod(method) {
25
27
  const normalized = method.trim().toUpperCase();
26
- return normalized === "GET" || normalized === "HEAD";
28
+ return normalized === "GET" || normalized === "HEAD" || normalized === "OPTIONS";
27
29
  }
28
30
  function createHeaders(event) {
29
31
  const headers = new Headers();
@@ -67,6 +69,9 @@ function csrfProtection() {
67
69
  });
68
70
  }
69
71
  const request = await createRequest(event);
72
+ const preflight = cors.preflight(request);
73
+ if (preflight) return preflight;
74
+ cors.headers(request).forEach((value, name) => setResponseHeader(event, name, value));
70
75
  try {
71
76
  await protect(request);
72
77
  } catch (error) {
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  prepareCsrfCookies
3
- } from "../chunk-5M3RHQIG.mjs";
3
+ } from "../chunk-CTRTL4CO.mjs";
4
4
  import {
5
+ cors,
5
6
  protect
6
- } from "../chunk-G3HBF4Q5.mjs";
7
+ } from "../chunk-5SCCUNBO.mjs";
7
8
  import "../chunk-FUOZWKHK.mjs";
8
9
  import {
9
10
  SecurityCsrfError
@@ -27,6 +28,8 @@ function createCsrfErrorResponse(error) {
27
28
  }
28
29
  function csrfProtection() {
29
30
  return async ({ event, resolve }) => {
31
+ const preflight = cors.preflight(event.request);
32
+ if (preflight) return preflight;
30
33
  if (event.request.method.trim().toUpperCase() === "TRACE") {
31
34
  return new Response("Method Not Allowed", {
32
35
  status: 405,
@@ -37,12 +40,12 @@ function csrfProtection() {
37
40
  await protect(event.request);
38
41
  } catch (error) {
39
42
  if (error instanceof SecurityCsrfError) {
40
- return createCsrfErrorResponse(error);
43
+ return cors.apply(event.request, createCsrfErrorResponse(error));
41
44
  }
42
45
  throw error;
43
46
  }
44
47
  await issueCsrfCookie(event);
45
- return resolve(event);
48
+ return cors.apply(event.request, await resolve(event));
46
49
  };
47
50
  }
48
51
  var svelteKitSecurityInternals = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holo-js/security",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
4
4
  "description": "Holo-JS Framework - CSRF and rate-limit contracts, config, and runtime seams",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -58,8 +58,8 @@
58
58
  "test": "vitest --run --coverage"
59
59
  },
60
60
  "dependencies": {
61
- "@holo-js/config": "^0.3.19",
62
- "@holo-js/kernel": "^0.3.19"
61
+ "@holo-js/config": "^0.3.20",
62
+ "@holo-js/kernel": "^0.3.20"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "h3": "^1.15.11",