@middy/http-cors 7.0.2 → 7.1.0

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
@@ -5,7 +5,7 @@
5
5
  <p>
6
6
  <a href="https://github.com/middyjs/middy/actions/workflows/test-unit.yml"><img src="https://github.com/middyjs/middy/actions/workflows/test-unit.yml/badge.svg" alt="GitHub Actions unit test status"></a>
7
7
  <a href="https://github.com/middyjs/middy/actions/workflows/test-dast.yml"><img src="https://github.com/middyjs/middy/actions/workflows/test-dast.yml/badge.svg" alt="GitHub Actions dast test status"></a>
8
- <a href="https://github.com/middyjs/middy/actions/workflows/test-perf.yml"><img src="https://github.com/middyjs/middy/actions/workflows/test-pref.yml/badge.svg" alt="GitHub Actions perf test status"></a>
8
+ <a href="https://github.com/middyjs/middy/actions/workflows/test-perf.yml"><img src="https://github.com/middyjs/middy/actions/workflows/test-perf.yml/badge.svg" alt="GitHub Actions perf test status"></a>
9
9
  <a href="https://github.com/middyjs/middy/actions/workflows/test-sast.yml"><img src="https://github.com/middyjs/middy/actions/workflows/test-sast.yml/badge.svg" alt="GitHub Actions SAST test status"></a>
10
10
  <a href="https://github.com/middyjs/middy/actions/workflows/test-lint.yml"><img src="https://github.com/middyjs/middy/actions/workflows/test-lint.yml/badge.svg" alt="GitHub Actions lint test status"></a>
11
11
  <br/>
@@ -32,7 +32,7 @@
32
32
 
33
33
  ## License
34
34
 
35
- Licensed under [MIT License](LICENSE). Copyright (c) 2017-2025 [Luciano Mammino](https://github.com/lmammino), [will Farrell](https://github.com/willfarrell), and the [Middy team](https://github.com/middyjs/middy/graphs/contributors).
35
+ Licensed under [MIT License](LICENSE). Copyright (c) 2017-2026 [will Farrell](https://github.com/willfarrell), [Luciano Mammino](https://github.com/lmammino), and [Middy contributors](https://github.com/middyjs/middy/graphs/contributors).
36
36
 
37
37
  <a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy?ref=badge_large">
38
38
  <img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy.svg?type=large" alt="FOSSA Status" style="max-width:100%;">
package/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ // Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
2
+ // SPDX-License-Identifier: MIT
1
3
  import type middy from "@middy/core";
2
4
 
3
5
  export interface Options {
@@ -10,8 +12,8 @@ export interface Options {
10
12
  origins?: string[];
11
13
  exposeHeaders?: string;
12
14
  maxAge?: number | string;
13
- requestHeaders?: string;
14
- requestMethods?: string;
15
+ requestHeaders?: string[];
16
+ requestMethods?: string[];
15
17
  cacheControl?: string;
16
18
  }
17
19
 
package/index.js CHANGED
@@ -1,5 +1,17 @@
1
+ // Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
2
+ // SPDX-License-Identifier: MIT
1
3
  import { normalizeHttpResponse } from "@middy/util";
2
4
 
5
+ // CORS-safelisted request headers
6
+ // https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header
7
+ const corsSafelistedRequestHeaders = [
8
+ "accept",
9
+ "accept-language",
10
+ "content-language",
11
+ "content-type",
12
+ "range",
13
+ ];
14
+
3
15
  const defaults = {
4
16
  disableBeforePreflightResponse: true,
5
17
  getOrigin: undefined, // default inserted below
@@ -10,6 +22,8 @@ const defaults = {
10
22
  origins: [],
11
23
  exposeHeaders: undefined,
12
24
  maxAge: undefined,
25
+ requestHeaders: undefined,
26
+ requestMethods: undefined,
13
27
  cacheControl: undefined,
14
28
  vary: undefined,
15
29
  };
@@ -29,7 +43,7 @@ const httpCorsMiddleware = (opts = {}) => {
29
43
  if (originDynamic.some((regExp) => regExp.test(incomingOrigin))) {
30
44
  return incomingOrigin;
31
45
  }
32
- // TODO deprecate `else` in v6
46
+ // TODO v8 deprecate `else`
33
47
  } else {
34
48
  if (incomingOrigin && options.credentials && options.origin === "*") {
35
49
  return incomingOrigin;
@@ -44,6 +58,9 @@ const httpCorsMiddleware = (opts = {}) => {
44
58
  ...opts,
45
59
  };
46
60
 
61
+ options.requestHeaders = options.requestHeaders?.map((v) => v.toLowerCase());
62
+ options.requestMethods = options.requestMethods?.map((v) => v.toUpperCase());
63
+
47
64
  let originAny = false;
48
65
  let originMany = options.origins.length > 1;
49
66
  const originStatic = {};
@@ -66,7 +83,9 @@ const httpCorsMiddleware = (opts = {}) => {
66
83
  originMany = true;
67
84
  // Dynamic
68
85
  // TODO: IDN -> puncycode not handled, add in if requested
69
- const regExpStr = origin.replaceAll(".", "\\.").replaceAll("*", "[^.]*");
86
+ const regExpStr = origin
87
+ .replace(/[.+?^${}()|[\]\\]/g, "\\$&")
88
+ .replaceAll("*", "[^.]*");
70
89
  // SAST Skipped: Not accessible by users
71
90
  // nosemgrep: javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp
72
91
  originDynamic.push(new RegExp(`^${regExpStr}$`));
@@ -145,6 +164,40 @@ const httpCorsMiddleware = (opts = {}) => {
145
164
  );
146
165
  if (method === "OPTIONS") {
147
166
  normalizeHttpResponse(request);
167
+ const eventHeaders = request.event.headers ?? {};
168
+ const requestMethod =
169
+ eventHeaders["Access-Control-Request-Method"] ??
170
+ eventHeaders["access-control-request-method"];
171
+
172
+ if (options.requestMethods?.length && requestMethod) {
173
+ if (!options.requestMethods.includes(requestMethod)) {
174
+ request.response.statusCode = 204;
175
+ request.response.headers = {};
176
+ return request.response;
177
+ }
178
+ }
179
+
180
+ const requestHeadersValue =
181
+ eventHeaders["Access-Control-Request-Headers"] ??
182
+ eventHeaders["access-control-request-headers"];
183
+
184
+ if (options.requestHeaders?.length && requestHeadersValue) {
185
+ const requestedHeaders = requestHeadersValue
186
+ .split(",")
187
+ .map((h) => h.trim().toLowerCase());
188
+ const nonSafelistedHeaders = requestedHeaders.filter(
189
+ (h) => !corsSafelistedRequestHeaders.includes(h),
190
+ );
191
+ const hasDisallowedHeader = nonSafelistedHeaders.some(
192
+ (h) => !options.requestHeaders.includes(h),
193
+ );
194
+ if (hasDisallowedHeader) {
195
+ request.response.statusCode = 204;
196
+ request.response.headers = {};
197
+ return request.response;
198
+ }
199
+ }
200
+
148
201
  const headers = {};
149
202
  modifyHeaders(headers, options, request);
150
203
  request.response.headers = headers;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@middy/http-cors",
3
- "version": "7.0.2",
3
+ "version": "7.1.0",
4
4
  "description": "CORS (Cross-Origin Resource Sharing) middleware for the middy framework",
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,6 +11,7 @@
11
11
  "access": "public"
12
12
  },
13
13
  "module": "./index.js",
14
+ "sideEffects": false,
14
15
  "exports": {
15
16
  ".": {
16
17
  "import": {
@@ -64,9 +65,9 @@
64
65
  },
65
66
  "gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431",
66
67
  "dependencies": {
67
- "@middy/util": "7.0.2"
68
+ "@middy/util": "7.1.0"
68
69
  },
69
70
  "devDependencies": {
70
- "@middy/core": "7.0.2"
71
+ "@middy/core": "7.1.0"
71
72
  }
72
73
  }