@appwarden/middleware 3.10.1 → 3.10.2

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.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![GitHub](https://img.shields.io/badge/GitHub-appwarden%2Fmiddleware-181717?logo=github&logoColor=white)](https://github.com/appwarden/middleware)
5
5
  [![npm version](https://img.shields.io/npm/v/@appwarden/middleware.svg)](https://www.npmjs.com/package/@appwarden/middleware)
6
6
  [![npm provenance](https://img.shields.io/badge/npm-provenance-green)](https://docs.npmjs.com/generating-provenance-statements)
7
- ![Test Coverage](https://img.shields.io/badge/coverage-92.72%25-brightgreen)
7
+ ![Test Coverage](https://img.shields.io/badge/coverage-92.9%25-brightgreen)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
9
 
10
10
  ## Core Features
@@ -51,9 +51,9 @@ function isHTMLRequest(request) {
51
51
  }
52
52
  const normalizedAccept = accept.toLowerCase();
53
53
  const isWildcardOnlyAccept = (value) => {
54
- const mediaRanges = value.split(",");
54
+ const mediaRanges2 = value.split(",");
55
55
  let hasNonEmptyRange = false;
56
- for (const range of mediaRanges) {
56
+ for (const range of mediaRanges2) {
57
57
  const [typeSubtype] = range.split(";");
58
58
  const trimmed = typeSubtype.trim();
59
59
  if (!trimmed) {
@@ -69,7 +69,15 @@ function isHTMLRequest(request) {
69
69
  if (isWildcardOnlyAccept(normalizedAccept)) {
70
70
  return false;
71
71
  }
72
- return normalizedAccept.includes("text/html");
72
+ const mediaRanges = normalizedAccept.split(",");
73
+ for (const range of mediaRanges) {
74
+ const [typeSubtype] = range.split(";");
75
+ const token = typeSubtype.trim();
76
+ if (token === "text/html") {
77
+ return true;
78
+ }
79
+ }
80
+ return false;
73
81
  }
74
82
 
75
83
  // src/schemas/use-content-security-policy.ts
@@ -0,0 +1,86 @@
1
+ import {
2
+ UseCSPInputSchema,
3
+ isHTMLResponse
4
+ } from "./chunk-2WPLLVUI.js";
5
+ import {
6
+ makeCSPHeader
7
+ } from "./chunk-QUVGY2YI.js";
8
+
9
+ // src/middlewares/use-content-security-policy.ts
10
+ var AppendAttribute = (attribute, nonce) => ({
11
+ element: function(element) {
12
+ element.setAttribute(attribute, nonce);
13
+ }
14
+ });
15
+ var useContentSecurityPolicy = (input) => {
16
+ const parsedInput = UseCSPInputSchema.safeParse(input);
17
+ if (!parsedInput.success) {
18
+ throw parsedInput.error;
19
+ }
20
+ const config = parsedInput.data;
21
+ return async (context, next) => {
22
+ await next();
23
+ const { response } = context;
24
+ if (
25
+ // if the csp is disabled
26
+ !["enforced", "report-only"].includes(config.mode)
27
+ ) {
28
+ context.debug("CSP is disabled");
29
+ return;
30
+ }
31
+ if (response.headers.has("Content-Type") && !isHTMLResponse(response)) {
32
+ return;
33
+ }
34
+ const cspNonce = crypto.randomUUID();
35
+ const [cspHeaderName, cspHeaderValue] = makeCSPHeader(
36
+ cspNonce,
37
+ config.directives,
38
+ config.mode
39
+ );
40
+ context.debug(`Applying CSP in ${config.mode} mode`);
41
+ const method = context.request.method.toUpperCase();
42
+ const shouldSkipTransform = !response.body || response.status === 204 || response.status === 304 || method === "HEAD";
43
+ if (shouldSkipTransform) {
44
+ context.debug(
45
+ "Skipping HTMLRewriter transform for response without body or HEAD request"
46
+ );
47
+ const nextResponse2 = new Response(null, response);
48
+ nextResponse2.headers.set(cspHeaderName, cspHeaderValue);
49
+ const originalContentType2 = response.headers.get("content-type");
50
+ if (originalContentType2) {
51
+ if (/charset\s*=/i.test(originalContentType2)) {
52
+ nextResponse2.headers.set("content-type", originalContentType2);
53
+ } else {
54
+ nextResponse2.headers.set(
55
+ "content-type",
56
+ `${originalContentType2}; charset=utf-8`
57
+ );
58
+ }
59
+ } else {
60
+ nextResponse2.headers.set("content-type", "text/html; charset=utf-8");
61
+ }
62
+ context.response = nextResponse2;
63
+ return;
64
+ }
65
+ const nextResponse = new Response(response.clone().body, response);
66
+ nextResponse.headers.set(cspHeaderName, cspHeaderValue);
67
+ const originalContentType = response.headers.get("content-type");
68
+ if (originalContentType) {
69
+ if (/charset\s*=/i.test(originalContentType)) {
70
+ nextResponse.headers.set("content-type", originalContentType);
71
+ } else {
72
+ nextResponse.headers.set(
73
+ "content-type",
74
+ `${originalContentType}; charset=utf-8`
75
+ );
76
+ }
77
+ } else {
78
+ nextResponse.headers.set("content-type", "text/html; charset=utf-8");
79
+ }
80
+ context.response = new HTMLRewriter().on("style", AppendAttribute("nonce", cspNonce)).on("script", AppendAttribute("nonce", cspNonce)).transform(nextResponse);
81
+ };
82
+ };
83
+
84
+ export {
85
+ useContentSecurityPolicy
86
+ };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  LOCKDOWN_TEST_EXPIRY_MS
3
- } from "./chunk-6O25N45F.js";
3
+ } from "./chunk-2WPLLVUI.js";
4
4
  import {
5
5
  printMessage
6
- } from "./chunk-QGXPAVOA.js";
6
+ } from "./chunk-QUVGY2YI.js";
7
7
 
8
8
  // src/utils/build-lock-page-url.ts
9
9
  function normalizeLockPageSlug(lockPageSlug) {
@@ -210,7 +210,7 @@ var insertErrorLogs = async (context, error) => {
210
210
  { html: true }
211
211
  );
212
212
  }
213
- }).transform(await fetch(context.request));
213
+ }).transform(await fetch(context.request.clone()));
214
214
  };
215
215
 
216
216
  // src/utils/cloudflare/make-csp-header.ts
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  MemoryCache,
3
3
  debug
4
- } from "./chunk-HIGZSGKS.js";
4
+ } from "./chunk-KE2UVIYR.js";
5
5
  import {
6
6
  APPWARDEN_CACHE_KEY,
7
7
  APPWARDEN_TEST_ROUTE
8
- } from "./chunk-6O25N45F.js";
8
+ } from "./chunk-2WPLLVUI.js";
9
9
  import {
10
10
  deleteEdgeValue,
11
11
  getLockValue,
12
12
  store,
13
13
  syncEdgeValue
14
- } from "./chunk-QGXPAVOA.js";
14
+ } from "./chunk-QUVGY2YI.js";
15
15
 
16
16
  // src/core/check-lock-status.ts
17
17
  var createContext = async (config) => {
@@ -3,29 +3,29 @@ import {
3
3
  } from "../chunk-XFG6SUSV.js";
4
4
  import {
5
5
  useContentSecurityPolicy
6
- } from "../chunk-ZQNXNGLV.js";
6
+ } from "../chunk-K7ZIT3FM.js";
7
7
  import {
8
8
  getNowMs
9
9
  } from "../chunk-X7WZVYQS.js";
10
10
  import {
11
11
  checkLockStatus
12
- } from "../chunk-TASPCREA.js";
12
+ } from "../chunk-ZOYE6D3A.js";
13
13
  import {
14
14
  TEMPORARY_REDIRECT_STATUS,
15
15
  buildLockPageUrl,
16
16
  createRedirect,
17
17
  debug,
18
18
  isOnLockPage
19
- } from "../chunk-HIGZSGKS.js";
19
+ } from "../chunk-KE2UVIYR.js";
20
20
  import {
21
21
  UseCSPInputSchema,
22
22
  isHTMLRequest
23
- } from "../chunk-6O25N45F.js";
23
+ } from "../chunk-2WPLLVUI.js";
24
24
  import {
25
25
  AppwardenApiTokenSchema,
26
26
  BooleanSchema,
27
27
  printMessage
28
- } from "../chunk-QGXPAVOA.js";
28
+ } from "../chunk-QUVGY2YI.js";
29
29
 
30
30
  // src/adapters/astro-cloudflare.ts
31
31
  import { waitUntil } from "cloudflare:workers";
@@ -3,22 +3,22 @@ import {
3
3
  } from "../chunk-X7WZVYQS.js";
4
4
  import {
5
5
  checkLockStatus
6
- } from "../chunk-TASPCREA.js";
6
+ } from "../chunk-ZOYE6D3A.js";
7
7
  import {
8
8
  TEMPORARY_REDIRECT_STATUS,
9
9
  buildLockPageUrl,
10
10
  debug,
11
11
  isOnLockPage
12
- } from "../chunk-HIGZSGKS.js";
12
+ } from "../chunk-KE2UVIYR.js";
13
13
  import {
14
14
  UseCSPInputSchema,
15
15
  isHTMLRequest
16
- } from "../chunk-6O25N45F.js";
16
+ } from "../chunk-2WPLLVUI.js";
17
17
  import {
18
18
  AppwardenApiTokenSchema,
19
19
  BooleanSchema,
20
20
  printMessage
21
- } from "../chunk-QGXPAVOA.js";
21
+ } from "../chunk-QUVGY2YI.js";
22
22
 
23
23
  // src/adapters/nextjs-cloudflare.ts
24
24
  import {
@@ -101,7 +101,7 @@ function createAppwardenMiddleware(configFn) {
101
101
  debugFn(
102
102
  `Applying CSP headers in ${config.contentSecurityPolicy.mode} mode`
103
103
  );
104
- const { makeCSPHeader } = await import("../cloudflare-PE3JKP3X.js");
104
+ const { makeCSPHeader } = await import("../cloudflare-JVRRPVRP.js");
105
105
  const [headerName, headerValue] = makeCSPHeader(
106
106
  "",
107
107
  config.contentSecurityPolicy.directives,
@@ -3,28 +3,28 @@ import {
3
3
  } from "../chunk-XFG6SUSV.js";
4
4
  import {
5
5
  useContentSecurityPolicy
6
- } from "../chunk-ZQNXNGLV.js";
6
+ } from "../chunk-K7ZIT3FM.js";
7
7
  import {
8
8
  getNowMs
9
9
  } from "../chunk-X7WZVYQS.js";
10
10
  import {
11
11
  checkLockStatus
12
- } from "../chunk-TASPCREA.js";
12
+ } from "../chunk-ZOYE6D3A.js";
13
13
  import {
14
14
  buildLockPageUrl,
15
15
  createRedirect,
16
16
  debug,
17
17
  isOnLockPage
18
- } from "../chunk-HIGZSGKS.js";
18
+ } from "../chunk-KE2UVIYR.js";
19
19
  import {
20
20
  UseCSPInputSchema,
21
21
  isHTMLRequest
22
- } from "../chunk-6O25N45F.js";
22
+ } from "../chunk-2WPLLVUI.js";
23
23
  import {
24
24
  AppwardenApiTokenSchema,
25
25
  BooleanSchema,
26
26
  printMessage
27
- } from "../chunk-QGXPAVOA.js";
27
+ } from "../chunk-QUVGY2YI.js";
28
28
 
29
29
  // src/adapters/react-router-cloudflare.ts
30
30
  import { waitUntil } from "cloudflare:workers";
@@ -3,28 +3,28 @@ import {
3
3
  } from "../chunk-XFG6SUSV.js";
4
4
  import {
5
5
  useContentSecurityPolicy
6
- } from "../chunk-ZQNXNGLV.js";
6
+ } from "../chunk-K7ZIT3FM.js";
7
7
  import {
8
8
  getNowMs
9
9
  } from "../chunk-X7WZVYQS.js";
10
10
  import {
11
11
  checkLockStatus
12
- } from "../chunk-TASPCREA.js";
12
+ } from "../chunk-ZOYE6D3A.js";
13
13
  import {
14
14
  buildLockPageUrl,
15
15
  createRedirect,
16
16
  debug,
17
17
  isOnLockPage
18
- } from "../chunk-HIGZSGKS.js";
18
+ } from "../chunk-KE2UVIYR.js";
19
19
  import {
20
20
  UseCSPInputSchema,
21
21
  isHTMLRequest
22
- } from "../chunk-6O25N45F.js";
22
+ } from "../chunk-2WPLLVUI.js";
23
23
  import {
24
24
  AppwardenApiTokenSchema,
25
25
  BooleanSchema,
26
26
  printMessage
27
- } from "../chunk-QGXPAVOA.js";
27
+ } from "../chunk-QUVGY2YI.js";
28
28
 
29
29
  // src/adapters/tanstack-start-cloudflare.ts
30
30
  import { waitUntil } from "cloudflare:workers";
@@ -11,7 +11,7 @@ import {
11
11
  makeCSPHeader,
12
12
  store,
13
13
  syncEdgeValue
14
- } from "./chunk-QGXPAVOA.js";
14
+ } from "./chunk-QUVGY2YI.js";
15
15
  export {
16
16
  CSP_KEYWORDS,
17
17
  autoQuoteCSPDirectiveArray,
package/cloudflare.js CHANGED
@@ -1,25 +1,25 @@
1
1
  import {
2
2
  useContentSecurityPolicy
3
- } from "./chunk-ZQNXNGLV.js";
3
+ } from "./chunk-K7ZIT3FM.js";
4
4
  import {
5
5
  checkLockStatus
6
- } from "./chunk-TASPCREA.js";
6
+ } from "./chunk-ZOYE6D3A.js";
7
7
  import {
8
8
  buildLockPageUrl,
9
9
  createRedirect,
10
10
  debug,
11
11
  isOnLockPage
12
- } from "./chunk-HIGZSGKS.js";
12
+ } from "./chunk-KE2UVIYR.js";
13
13
  import {
14
14
  UseCSPInputSchema,
15
15
  isHTMLRequest
16
- } from "./chunk-6O25N45F.js";
16
+ } from "./chunk-2WPLLVUI.js";
17
17
  import {
18
18
  AppwardenApiTokenSchema,
19
19
  BooleanSchema,
20
20
  insertErrorLogs,
21
21
  printMessage
22
- } from "./chunk-QGXPAVOA.js";
22
+ } from "./chunk-QUVGY2YI.js";
23
23
 
24
24
  // src/runners/appwarden-on-cloudflare.ts
25
25
  import { ZodError } from "zod";
@@ -81,6 +81,9 @@ var useAppwarden = (input) => async (context, next) => {
81
81
  let shouldCallNext = true;
82
82
  try {
83
83
  const requestUrl = new URL(request.url);
84
+ if (request.method.toUpperCase() === "OPTIONS") {
85
+ return;
86
+ }
84
87
  if (!isHTMLRequest(request)) {
85
88
  return;
86
89
  }
@@ -121,11 +124,7 @@ var useAppwarden = (input) => async (context, next) => {
121
124
 
122
125
  // src/middlewares/use-fetch-origin.ts
123
126
  var useFetchOrigin = () => async (context, next) => {
124
- context.response = await fetch(
125
- new Request(context.request, {
126
- redirect: "manual"
127
- })
128
- );
127
+ context.response = await fetch(new Request(context.request));
129
128
  await next();
130
129
  };
131
130
 
package/index.js CHANGED
@@ -5,14 +5,14 @@ import {
5
5
  } from "./chunk-QEFORWCW.js";
6
6
  import {
7
7
  useContentSecurityPolicy
8
- } from "./chunk-ZQNXNGLV.js";
8
+ } from "./chunk-K7ZIT3FM.js";
9
9
  import {
10
10
  APPWARDEN_CACHE_KEY,
11
11
  CSPDirectivesSchema,
12
12
  CSPModeSchema,
13
13
  LOCKDOWN_TEST_EXPIRY_MS
14
- } from "./chunk-6O25N45F.js";
15
- import "./chunk-QGXPAVOA.js";
14
+ } from "./chunk-2WPLLVUI.js";
15
+ import "./chunk-QUVGY2YI.js";
16
16
  export {
17
17
  APPWARDEN_CACHE_KEY,
18
18
  CSPDirectivesSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appwarden/middleware",
3
- "version": "3.10.1",
3
+ "version": "3.10.2",
4
4
  "description": "Instantly disable all user interaction with your app deployed on Cloudflare or Vercel",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/vercel.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  buildLockPageUrl,
9
9
  debug,
10
10
  isOnLockPage
11
- } from "./chunk-HIGZSGKS.js";
11
+ } from "./chunk-KE2UVIYR.js";
12
12
  import {
13
13
  APPWARDEN_CACHE_KEY,
14
14
  CSPDirectivesSchema,
@@ -16,13 +16,13 @@ import {
16
16
  errors,
17
17
  globalErrors,
18
18
  isHTMLRequest
19
- } from "./chunk-6O25N45F.js";
19
+ } from "./chunk-2WPLLVUI.js";
20
20
  import {
21
21
  LockValue,
22
22
  getErrors,
23
23
  makeCSPHeader,
24
24
  printMessage
25
- } from "./chunk-QGXPAVOA.js";
25
+ } from "./chunk-QUVGY2YI.js";
26
26
 
27
27
  // src/runners/appwarden-on-vercel.ts
28
28
  import { waitUntil } from "@vercel/functions";
package/chunk-ZQNXNGLV.js DELETED
@@ -1,50 +0,0 @@
1
- import {
2
- UseCSPInputSchema,
3
- isHTMLResponse
4
- } from "./chunk-6O25N45F.js";
5
- import {
6
- makeCSPHeader
7
- } from "./chunk-QGXPAVOA.js";
8
-
9
- // src/middlewares/use-content-security-policy.ts
10
- var AppendAttribute = (attribute, nonce) => ({
11
- element: function(element) {
12
- element.setAttribute(attribute, nonce);
13
- }
14
- });
15
- var useContentSecurityPolicy = (input) => {
16
- const parsedInput = UseCSPInputSchema.safeParse(input);
17
- if (!parsedInput.success) {
18
- throw parsedInput.error;
19
- }
20
- const config = parsedInput.data;
21
- return async (context, next) => {
22
- await next();
23
- const { response } = context;
24
- if (
25
- // if the csp is disabled
26
- !["enforced", "report-only"].includes(config.mode)
27
- ) {
28
- context.debug("CSP is disabled");
29
- return;
30
- }
31
- if (response.headers.has("Content-Type") && !isHTMLResponse(response)) {
32
- return;
33
- }
34
- const cspNonce = crypto.randomUUID();
35
- const [cspHeaderName, cspHeaderValue] = makeCSPHeader(
36
- cspNonce,
37
- config.directives,
38
- config.mode
39
- );
40
- context.debug(`Applying CSP in ${config.mode} mode`);
41
- const nextResponse = new Response(response.body, response);
42
- nextResponse.headers.set(cspHeaderName, cspHeaderValue);
43
- nextResponse.headers.set("content-type", "text/html; charset=utf-8");
44
- context.response = new HTMLRewriter().on("style", AppendAttribute("nonce", cspNonce)).on("script", AppendAttribute("nonce", cspNonce)).transform(nextResponse);
45
- };
46
- };
47
-
48
- export {
49
- useContentSecurityPolicy
50
- };