@remix-run/cop-middleware 0.1.2 → 0.1.4
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 +11 -11
- package/dist/lib/cop.d.ts.map +1 -1
- package/dist/lib/cop.js +6 -3
- package/package.json +5 -5
- package/src/lib/cop.ts +8 -4
package/README.md
CHANGED
|
@@ -18,8 +18,8 @@ npm i remix
|
|
|
18
18
|
## Usage
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
|
-
import { createRouter } from 'remix/
|
|
22
|
-
import { cop } from 'remix/cop
|
|
21
|
+
import { createRouter } from 'remix/router'
|
|
22
|
+
import { cop } from 'remix/middleware/cop'
|
|
23
23
|
|
|
24
24
|
let router = createRouter({
|
|
25
25
|
middleware: [cop()],
|
|
@@ -51,11 +51,11 @@ You can also layer `cop()` in front of `csrf()` when you want both browser prove
|
|
|
51
51
|
|
|
52
52
|
```ts
|
|
53
53
|
import { createCookie } from 'remix/cookie'
|
|
54
|
-
import { createRouter } from 'remix/
|
|
55
|
-
import { createCookieSessionStorage } from 'remix/session/cookie
|
|
56
|
-
import { session } from 'remix/session
|
|
57
|
-
import { cop } from 'remix/cop
|
|
58
|
-
import { csrf } from 'remix/csrf
|
|
54
|
+
import { createRouter } from 'remix/router'
|
|
55
|
+
import { createCookieSessionStorage } from 'remix/session-storage/cookie'
|
|
56
|
+
import { session } from 'remix/middleware/session'
|
|
57
|
+
import { cop } from 'remix/middleware/cop'
|
|
58
|
+
import { csrf } from 'remix/middleware/csrf'
|
|
59
59
|
|
|
60
60
|
let sessionCookie = createCookie('__session', { secrets: ['secret1'] })
|
|
61
61
|
let sessionStorage = createCookieSessionStorage()
|
|
@@ -70,8 +70,8 @@ In this setup, `cop()` runs first and rejects unsafe cross-origin browser reques
|
|
|
70
70
|
## Trusted Origins
|
|
71
71
|
|
|
72
72
|
```ts
|
|
73
|
-
import { createRouter } from 'remix/
|
|
74
|
-
import { cop } from 'remix/cop
|
|
73
|
+
import { createRouter } from 'remix/router'
|
|
74
|
+
import { cop } from 'remix/middleware/cop'
|
|
75
75
|
|
|
76
76
|
let router = createRouter({
|
|
77
77
|
middleware: [
|
|
@@ -95,8 +95,8 @@ Bypass patterns intentionally weaken protection for specific endpoints. They sup
|
|
|
95
95
|
- Tail wildcards with `{name...}`
|
|
96
96
|
|
|
97
97
|
```ts
|
|
98
|
-
import { createRouter } from 'remix/
|
|
99
|
-
import { cop } from 'remix/cop
|
|
98
|
+
import { createRouter } from 'remix/router'
|
|
99
|
+
import { cop } from 'remix/middleware/cop'
|
|
100
100
|
|
|
101
101
|
let router = createRouter({
|
|
102
102
|
middleware: [
|
package/dist/lib/cop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cop.d.ts","sourceRoot":"","sources":["../../src/lib/cop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAiB,MAAM,yBAAyB,CAAA;AAaxF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,sBAAsB,GAAG,uCAAuC,CAAA;AAE/F;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAClF;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAElC;;OAEG;IACH,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAE1C;;OAEG;IACH,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;
|
|
1
|
+
{"version":3,"file":"cop.d.ts","sourceRoot":"","sources":["../../src/lib/cop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAiB,MAAM,yBAAyB,CAAA;AAaxF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,sBAAsB,GAAG,uCAAuC,CAAA;AAE/F;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAClF;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAElC;;OAEG;IACH,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAE1C;;OAEG;IACH,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAyFD;;;;;GAKG;AACH,wBAAgB,GAAG,CAAC,OAAO,GAAE,UAAe,GAAG,UAAU,CAWxD"}
|
package/dist/lib/cop.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isRequestMethod } from '@remix-run/fetch-router';
|
|
2
2
|
const safeMethods = ['GET', 'HEAD', 'OPTIONS'];
|
|
3
3
|
class CrossOriginProtection {
|
|
4
4
|
#trustedOrigins = new Set();
|
|
@@ -23,7 +23,7 @@ class CrossOriginProtection {
|
|
|
23
23
|
this.#onDeny = onDeny;
|
|
24
24
|
}
|
|
25
25
|
check(context) {
|
|
26
|
-
if (
|
|
26
|
+
if (isSafeMethod(context.method)) {
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
29
|
let secFetchSite = getHeaderValue(context.headers, 'Sec-Fetch-Site')?.toLowerCase() ?? '';
|
|
@@ -66,6 +66,9 @@ class CrossOriginProtection {
|
|
|
66
66
|
return normalizedOrigin != null && this.#trustedOrigins.has(normalizedOrigin);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
function isSafeMethod(method) {
|
|
70
|
+
return isRequestMethod(method) && safeMethods.includes(method);
|
|
71
|
+
}
|
|
69
72
|
/**
|
|
70
73
|
* Creates middleware that rejects unsafe cross-origin requests.
|
|
71
74
|
*
|
|
@@ -145,7 +148,7 @@ function parseBypassPattern(pattern) {
|
|
|
145
148
|
let methodPattern = /^([A-Z]+)\s+(.+)$/.exec(trimmedPattern);
|
|
146
149
|
if (methodPattern != null && methodPattern[2].startsWith('/')) {
|
|
147
150
|
let maybeMethod = methodPattern[1];
|
|
148
|
-
if (!
|
|
151
|
+
if (!isRequestMethod(maybeMethod)) {
|
|
149
152
|
throw new Error(`invalid request method in bypass pattern ${JSON.stringify(pattern)}`);
|
|
150
153
|
}
|
|
151
154
|
method = maybeMethod;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/cop-middleware",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Middleware for tokenless cross-origin protection in Fetch API servers",
|
|
5
5
|
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^24.6.0",
|
|
30
30
|
"@typescript/native-preview": "7.0.0-dev.20251125.1",
|
|
31
|
-
"@remix-run/
|
|
32
|
-
"@remix-run/
|
|
33
|
-
"@remix-run/test": "0.
|
|
31
|
+
"@remix-run/assert": "0.2.1",
|
|
32
|
+
"@remix-run/fetch-router": "0.19.1",
|
|
33
|
+
"@remix-run/test": "0.4.1"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@remix-run/fetch-router": "^0.
|
|
36
|
+
"@remix-run/fetch-router": "^0.19.1"
|
|
37
37
|
},
|
|
38
38
|
"keywords": [
|
|
39
39
|
"fetch",
|
package/src/lib/cop.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isRequestMethod } from '@remix-run/fetch-router'
|
|
2
2
|
import type { Middleware, RequestContext, RequestMethod } from '@remix-run/fetch-router'
|
|
3
3
|
|
|
4
4
|
const safeMethods: RequestMethod[] = ['GET', 'HEAD', 'OPTIONS']
|
|
@@ -77,7 +77,7 @@ class CrossOriginProtection {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
check(context: RequestContext): CopFailureReason | null {
|
|
80
|
-
if (
|
|
80
|
+
if (isSafeMethod(context.method)) {
|
|
81
81
|
return null
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -130,6 +130,10 @@ class CrossOriginProtection {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
function isSafeMethod(method: string): boolean {
|
|
134
|
+
return isRequestMethod(method) && safeMethods.includes(method)
|
|
135
|
+
}
|
|
136
|
+
|
|
133
137
|
/**
|
|
134
138
|
* Creates middleware that rejects unsafe cross-origin requests.
|
|
135
139
|
*
|
|
@@ -228,8 +232,8 @@ function parseBypassPattern(pattern: string): BypassPattern {
|
|
|
228
232
|
let methodPattern = /^([A-Z]+)\s+(.+)$/.exec(trimmedPattern)
|
|
229
233
|
|
|
230
234
|
if (methodPattern != null && methodPattern[2].startsWith('/')) {
|
|
231
|
-
let maybeMethod = methodPattern[1]
|
|
232
|
-
if (!
|
|
235
|
+
let maybeMethod = methodPattern[1]
|
|
236
|
+
if (!isRequestMethod(maybeMethod)) {
|
|
233
237
|
throw new Error(`invalid request method in bypass pattern ${JSON.stringify(pattern)}`)
|
|
234
238
|
}
|
|
235
239
|
|