@lwrjs/security 0.15.0-alpha.8 → 0.15.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/build/cjs/headers.cjs +18 -6
- package/build/es/headers.js +22 -6
- package/package.json +5 -4
package/build/cjs/headers.cjs
CHANGED
|
@@ -30,6 +30,10 @@ var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
|
30
30
|
var import_content_security_policy = __toModule(require("./headers/content-security-policy.cjs"));
|
|
31
31
|
var import_referrer_policy = __toModule(require("./headers/referrer-policy.cjs"));
|
|
32
32
|
var import_strict_transport_security = __toModule(require("./headers/strict-transport-security.cjs"));
|
|
33
|
+
var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
34
|
+
var import_util = __toModule(require("util"));
|
|
35
|
+
var CSP_HEADER_NAME = "content-security-policy";
|
|
36
|
+
var MAX_HEADER_SIZE = 4096;
|
|
33
37
|
function getResources(viewDefinition) {
|
|
34
38
|
const {viewRecord} = viewDefinition;
|
|
35
39
|
const resources = [];
|
|
@@ -75,9 +79,6 @@ async function getResourceHashes(viewResponse) {
|
|
|
75
79
|
}
|
|
76
80
|
return hashes;
|
|
77
81
|
}
|
|
78
|
-
function normalizeHeaders(headers = {}) {
|
|
79
|
-
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
|
|
80
|
-
}
|
|
81
82
|
function normalizeOptions(options = {}) {
|
|
82
83
|
for (const [option, value] of Object.entries(options)) {
|
|
83
84
|
if (value === true) {
|
|
@@ -88,23 +89,31 @@ function normalizeOptions(options = {}) {
|
|
|
88
89
|
}
|
|
89
90
|
async function resolveHeaders(viewResponse, options) {
|
|
90
91
|
options = normalizeOptions(options);
|
|
91
|
-
const headers = normalizeHeaders(viewResponse.headers);
|
|
92
|
+
const headers = (0, import_shared_utils.normalizeHeaders)(viewResponse.headers);
|
|
92
93
|
if (options.contentSecurityPolicy === void 0 || typeof options.contentSecurityPolicy === "object") {
|
|
93
|
-
const headerName = options.contentSecurityPolicy?.reportOnly ? "content-security-policy-report-only" :
|
|
94
|
+
const headerName = options.contentSecurityPolicy?.reportOnly ? "content-security-policy-report-only" : CSP_HEADER_NAME;
|
|
94
95
|
let hashes = [];
|
|
95
96
|
if (options.contentSecurityPolicy?.resourceHashing === void 0) {
|
|
96
97
|
hashes = await getResourceHashes(viewResponse);
|
|
97
98
|
}
|
|
98
99
|
headers[headerName] = (0, import_content_security_policy.default)(headers[headerName], options.contentSecurityPolicy, hashes);
|
|
100
|
+
const size = byteSize(headers[headerName]);
|
|
101
|
+
if (size > MAX_HEADER_SIZE) {
|
|
102
|
+
import_diagnostics.logger.warn(`[security] Header "${headerName}" size (${size}) exceeds the recommended limit of ${MAX_HEADER_SIZE}.`);
|
|
103
|
+
}
|
|
99
104
|
}
|
|
100
105
|
if (typeof options.contentSecurityPolicy === "string") {
|
|
101
106
|
const parsedOptions = {
|
|
102
107
|
directives: options.contentSecurityPolicy,
|
|
103
108
|
useDefault: false
|
|
104
109
|
};
|
|
105
|
-
const headerName =
|
|
110
|
+
const headerName = CSP_HEADER_NAME;
|
|
106
111
|
const hashes = await getResourceHashes(viewResponse);
|
|
107
112
|
headers[headerName] = (0, import_content_security_policy.default)(headers[headerName], parsedOptions, hashes);
|
|
113
|
+
const size = byteSize(headers[headerName]);
|
|
114
|
+
if (size > MAX_HEADER_SIZE) {
|
|
115
|
+
import_diagnostics.logger.warn(`[security] Header "${headerName}" size (${size}) exceeds the recommended limit of ${MAX_HEADER_SIZE}.`);
|
|
116
|
+
}
|
|
108
117
|
}
|
|
109
118
|
if (options.referrerPolicy === void 0 || typeof options.referrerPolicy === "object") {
|
|
110
119
|
const headerName = "referrer-policy";
|
|
@@ -140,3 +149,6 @@ async function resolveHeaders(viewResponse, options) {
|
|
|
140
149
|
}
|
|
141
150
|
return headers;
|
|
142
151
|
}
|
|
152
|
+
function byteSize(str) {
|
|
153
|
+
return str ? new import_util.TextEncoder().encode(str).length : 0;
|
|
154
|
+
}
|
package/build/es/headers.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { createIntegrityHash, getFeatureFlags, streamToString } from '@lwrjs/shared-utils';
|
|
1
|
+
import { createIntegrityHash, getFeatureFlags, streamToString, normalizeHeaders } from '@lwrjs/shared-utils';
|
|
2
2
|
import contentSecurityPolicy from './headers/content-security-policy.js';
|
|
3
3
|
import referrerPolicy from './headers/referrer-policy.js';
|
|
4
4
|
import strictTransportSecurity from './headers/strict-transport-security.js';
|
|
5
|
+
import { logger } from '@lwrjs/diagnostics';
|
|
6
|
+
import { TextEncoder } from 'util';
|
|
7
|
+
const CSP_HEADER_NAME = 'content-security-policy';
|
|
8
|
+
// Recommend CSP header should be < than 4k. There is a 10k MAX for all headers on AWS API gateway.
|
|
9
|
+
const MAX_HEADER_SIZE = 4096;
|
|
5
10
|
function getResources(viewDefinition) {
|
|
6
11
|
const { viewRecord } = viewDefinition;
|
|
7
12
|
const resources = [];
|
|
@@ -51,9 +56,6 @@ async function getResourceHashes(viewResponse) {
|
|
|
51
56
|
}
|
|
52
57
|
return hashes;
|
|
53
58
|
}
|
|
54
|
-
function normalizeHeaders(headers = {}) {
|
|
55
|
-
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
|
|
56
|
-
}
|
|
57
59
|
function normalizeOptions(options = {}) {
|
|
58
60
|
for (const [option, value] of Object.entries(options)) {
|
|
59
61
|
// true values are the same as undefined
|
|
@@ -69,21 +71,31 @@ export async function resolveHeaders(viewResponse, options) {
|
|
|
69
71
|
if (options.contentSecurityPolicy === undefined || typeof options.contentSecurityPolicy === 'object') {
|
|
70
72
|
const headerName = options.contentSecurityPolicy?.reportOnly
|
|
71
73
|
? 'content-security-policy-report-only'
|
|
72
|
-
:
|
|
74
|
+
: CSP_HEADER_NAME;
|
|
73
75
|
let hashes = [];
|
|
74
76
|
if (options.contentSecurityPolicy?.resourceHashing === undefined) {
|
|
75
77
|
hashes = await getResourceHashes(viewResponse);
|
|
76
78
|
}
|
|
77
79
|
headers[headerName] = contentSecurityPolicy(headers[headerName], options.contentSecurityPolicy, hashes);
|
|
80
|
+
// Warn if the header size is greater than the recommended limit
|
|
81
|
+
const size = byteSize(headers[headerName]);
|
|
82
|
+
if (size > MAX_HEADER_SIZE) {
|
|
83
|
+
logger.warn(`[security] Header "${headerName}" size (${size}) exceeds the recommended limit of ${MAX_HEADER_SIZE}.`);
|
|
84
|
+
}
|
|
78
85
|
}
|
|
79
86
|
if (typeof options.contentSecurityPolicy === 'string') {
|
|
80
87
|
const parsedOptions = {
|
|
81
88
|
directives: options.contentSecurityPolicy,
|
|
82
89
|
useDefault: false,
|
|
83
90
|
};
|
|
84
|
-
const headerName =
|
|
91
|
+
const headerName = CSP_HEADER_NAME;
|
|
85
92
|
const hashes = await getResourceHashes(viewResponse);
|
|
86
93
|
headers[headerName] = contentSecurityPolicy(headers[headerName], parsedOptions, hashes);
|
|
94
|
+
// Warn if the header size is greater than the recommended limit
|
|
95
|
+
const size = byteSize(headers[headerName]);
|
|
96
|
+
if (size > MAX_HEADER_SIZE) {
|
|
97
|
+
logger.warn(`[security] Header "${headerName}" size (${size}) exceeds the recommended limit of ${MAX_HEADER_SIZE}.`);
|
|
98
|
+
}
|
|
87
99
|
}
|
|
88
100
|
if (options.referrerPolicy === undefined || typeof options.referrerPolicy === 'object') {
|
|
89
101
|
const headerName = 'referrer-policy';
|
|
@@ -125,4 +137,8 @@ export async function resolveHeaders(viewResponse, options) {
|
|
|
125
137
|
}
|
|
126
138
|
return headers;
|
|
127
139
|
}
|
|
140
|
+
// Get number of bytes from a string. Different char encodings can effect size per char.
|
|
141
|
+
function byteSize(str) {
|
|
142
|
+
return str ? new TextEncoder().encode(str).length : 0;
|
|
143
|
+
}
|
|
128
144
|
//# sourceMappingURL=headers.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lwrjs/security",
|
|
3
|
-
"version": "0.15.0
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "build/es/index.d.ts",
|
|
@@ -32,13 +32,14 @@
|
|
|
32
32
|
"build": "tsc -b"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@lwrjs/
|
|
35
|
+
"@lwrjs/diagnostics": "0.15.0",
|
|
36
|
+
"@lwrjs/shared-utils": "0.15.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
|
-
"@lwrjs/types": "0.15.0
|
|
39
|
+
"@lwrjs/types": "0.15.0"
|
|
39
40
|
},
|
|
40
41
|
"engines": {
|
|
41
42
|
"node": ">=18.0.0"
|
|
42
43
|
},
|
|
43
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "ee374df435d5342f63e4da126a09461e761837f3"
|
|
44
45
|
}
|