@lwrjs/security 0.10.0-alpha.16
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/LICENSE +10 -0
- package/build/cjs/headers/content-security-policy.cjs +82 -0
- package/build/cjs/headers/referrer-policy.cjs +21 -0
- package/build/cjs/headers/strict-transport-security.cjs +41 -0
- package/build/cjs/headers.cjs +127 -0
- package/build/cjs/index.cjs +32 -0
- package/build/cjs/options.cjs +5 -0
- package/build/cjs/route-handler.cjs +34 -0
- package/build/cjs/wrapper.cjs +57 -0
- package/build/es/headers/content-security-policy.d.ts +11 -0
- package/build/es/headers/content-security-policy.js +71 -0
- package/build/es/headers/referrer-policy.d.ts +3 -0
- package/build/es/headers/referrer-policy.js +10 -0
- package/build/es/headers/strict-transport-security.d.ts +7 -0
- package/build/es/headers/strict-transport-security.js +30 -0
- package/build/es/headers.d.ts +4 -0
- package/build/es/headers.js +111 -0
- package/build/es/index.d.ts +4 -0
- package/build/es/index.js +4 -0
- package/build/es/options.d.ts +16 -0
- package/build/es/options.js +2 -0
- package/build/es/route-handler.d.ts +11 -0
- package/build/es/route-handler.js +14 -0
- package/build/es/wrapper.d.ts +15 -0
- package/build/es/wrapper.js +47 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
MIT LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020, Salesforce.com, Inc.
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// packages/@lwrjs/security/src/headers/content-security-policy.ts
|
|
9
|
+
__markAsModule(exports);
|
|
10
|
+
__export(exports, {
|
|
11
|
+
default: () => contentSecurityPolicy
|
|
12
|
+
});
|
|
13
|
+
var DEFAULT_DIRECTIVES = {
|
|
14
|
+
"default-src": ["'self'"],
|
|
15
|
+
"base-uri": ["'self'"],
|
|
16
|
+
"font-src": ["'self'", "https:", "data:"],
|
|
17
|
+
"form-action": ["'self'"],
|
|
18
|
+
"frame-ancestors": ["'self'"],
|
|
19
|
+
"img-src": ["'self'", "data:"],
|
|
20
|
+
"object-src": ["'none'"],
|
|
21
|
+
"script-src": ["'self'"],
|
|
22
|
+
"script-src-attr": ["'none'"],
|
|
23
|
+
"style-src": ["'self'", "https:", "'unsafe-inline'"],
|
|
24
|
+
"upgrade-insecure-requests": []
|
|
25
|
+
};
|
|
26
|
+
function parseDirectives(str) {
|
|
27
|
+
const directives = {};
|
|
28
|
+
for (const directive of str.split(";")) {
|
|
29
|
+
const [key, ...value] = directive.trim().split(" ");
|
|
30
|
+
directives[key] = value;
|
|
31
|
+
}
|
|
32
|
+
return directives;
|
|
33
|
+
}
|
|
34
|
+
function stringifyDirectives(directives) {
|
|
35
|
+
const output = [];
|
|
36
|
+
for (const directive of directives.keys()) {
|
|
37
|
+
const values = directives.get(directive);
|
|
38
|
+
if (!values) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
output.push(`${directive} ${Array.from(values).join(" ")}`);
|
|
42
|
+
}
|
|
43
|
+
return output.join(";");
|
|
44
|
+
}
|
|
45
|
+
function normalizeDirectives(input) {
|
|
46
|
+
const output = new Map();
|
|
47
|
+
for (const directives of input) {
|
|
48
|
+
for (const [directive, values] of Object.entries(directives)) {
|
|
49
|
+
let set = output.get(directive);
|
|
50
|
+
if (!set) {
|
|
51
|
+
set = new Set();
|
|
52
|
+
output.set(directive, set);
|
|
53
|
+
}
|
|
54
|
+
for (const value of values) {
|
|
55
|
+
set.add(value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return output;
|
|
60
|
+
}
|
|
61
|
+
function contentSecurityPolicy(header, options, hashes) {
|
|
62
|
+
const input = [];
|
|
63
|
+
if (options?.useDefault === void 0 || options?.useDefault === true) {
|
|
64
|
+
input.push(DEFAULT_DIRECTIVES);
|
|
65
|
+
}
|
|
66
|
+
if (options?.directives && typeof options.directives === "object") {
|
|
67
|
+
input.push(options.directives);
|
|
68
|
+
}
|
|
69
|
+
if (options?.directives && typeof options.directives === "string") {
|
|
70
|
+
input.push(parseDirectives(options.directives));
|
|
71
|
+
}
|
|
72
|
+
if (header?.length) {
|
|
73
|
+
input.push(parseDirectives(header));
|
|
74
|
+
}
|
|
75
|
+
if (hashes?.length) {
|
|
76
|
+
input.push({
|
|
77
|
+
"script-src": hashes
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const normalizedDirectives = normalizeDirectives(input);
|
|
81
|
+
return stringifyDirectives(normalizedDirectives);
|
|
82
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// packages/@lwrjs/security/src/headers/referrer-policy.ts
|
|
9
|
+
__markAsModule(exports);
|
|
10
|
+
__export(exports, {
|
|
11
|
+
default: () => referrerPolicy
|
|
12
|
+
});
|
|
13
|
+
var DEFAULT_DIRECTIVE = "no-referrer";
|
|
14
|
+
function referrerPolicy(header, option) {
|
|
15
|
+
const value = header || option;
|
|
16
|
+
if (!value) {
|
|
17
|
+
return DEFAULT_DIRECTIVE;
|
|
18
|
+
}
|
|
19
|
+
const directives = typeof value === "string" ? [value] : value;
|
|
20
|
+
return directives.join(",");
|
|
21
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// packages/@lwrjs/security/src/headers/strict-transport-security.ts
|
|
9
|
+
__markAsModule(exports);
|
|
10
|
+
__export(exports, {
|
|
11
|
+
default: () => strictTransportSecurity
|
|
12
|
+
});
|
|
13
|
+
var DEFAULT_MAX_AGE = 180 * 24 * 60 * 60;
|
|
14
|
+
function parseDirectives(str) {
|
|
15
|
+
const policy = {};
|
|
16
|
+
for (const segment of str.split(";")) {
|
|
17
|
+
const directive = segment.trim();
|
|
18
|
+
if (directive.startsWith("maxage")) {
|
|
19
|
+
policy.maxAge = parseInt(directive.substring(directive.indexOf("=") + 1));
|
|
20
|
+
}
|
|
21
|
+
if (directive === "includeSubDomains") {
|
|
22
|
+
policy.includeSubDomains = true;
|
|
23
|
+
}
|
|
24
|
+
if (directive === "preload") {
|
|
25
|
+
policy.preload = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return policy;
|
|
29
|
+
}
|
|
30
|
+
function strictTransportSecurity(header, option) {
|
|
31
|
+
const policy = header !== void 0 ? parseDirectives(header) : option;
|
|
32
|
+
const maxAge = policy?.maxAge !== void 0 ? policy.maxAge : DEFAULT_MAX_AGE;
|
|
33
|
+
const directives = [`max-age=${maxAge}`];
|
|
34
|
+
if (policy?.includeSubDomains === void 0 || policy?.includeSubDomains) {
|
|
35
|
+
directives.push("includeSubDomains");
|
|
36
|
+
}
|
|
37
|
+
if (policy?.preload) {
|
|
38
|
+
directives.push("preload");
|
|
39
|
+
}
|
|
40
|
+
return directives.join("; ");
|
|
41
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
11
|
+
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/security/src/headers.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
resolveHeaders: () => resolveHeaders
|
|
28
|
+
});
|
|
29
|
+
var import_crypto = __toModule(require("crypto"));
|
|
30
|
+
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
31
|
+
var import_content_security_policy = __toModule(require("./headers/content-security-policy.cjs"));
|
|
32
|
+
var import_referrer_policy = __toModule(require("./headers/referrer-policy.cjs"));
|
|
33
|
+
var import_strict_transport_security = __toModule(require("./headers/strict-transport-security.cjs"));
|
|
34
|
+
function getResources(viewDefinition) {
|
|
35
|
+
const {viewRecord} = viewDefinition;
|
|
36
|
+
const resources = [];
|
|
37
|
+
if (viewRecord.resources) {
|
|
38
|
+
resources.push(...viewRecord.resources);
|
|
39
|
+
}
|
|
40
|
+
if (viewRecord.bootstrapModule?.resources) {
|
|
41
|
+
resources.push(...viewRecord.bootstrapModule.resources);
|
|
42
|
+
}
|
|
43
|
+
return resources;
|
|
44
|
+
}
|
|
45
|
+
function hash(source) {
|
|
46
|
+
return `'sha256-${(0, import_crypto.createHash)("sha256").update(source).digest("base64")}'`;
|
|
47
|
+
}
|
|
48
|
+
async function hashResources(resources) {
|
|
49
|
+
const hashes = [];
|
|
50
|
+
for (const resource of resources) {
|
|
51
|
+
if (!resource.inline || resource.type !== "application/javascript")
|
|
52
|
+
continue;
|
|
53
|
+
if (resource.content) {
|
|
54
|
+
hashes.push(hash(resource.content));
|
|
55
|
+
}
|
|
56
|
+
if (resource.stream) {
|
|
57
|
+
const content = await (0, import_shared_utils.streamToString)(resource.stream());
|
|
58
|
+
hashes.push(hash(content));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return hashes;
|
|
62
|
+
}
|
|
63
|
+
async function getResourceHashes(viewResponse) {
|
|
64
|
+
if (!viewResponse.metadata?.viewDefinition) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const {viewDefinition} = viewResponse.metadata;
|
|
68
|
+
const resources = getResources(viewDefinition);
|
|
69
|
+
const hashes = await hashResources(resources);
|
|
70
|
+
return hashes;
|
|
71
|
+
}
|
|
72
|
+
function normalizeHeaders(headers = {}) {
|
|
73
|
+
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
|
|
74
|
+
}
|
|
75
|
+
function normalizeOptions(options = {}) {
|
|
76
|
+
for (const [option, value] of Object.entries(options)) {
|
|
77
|
+
if (value === true) {
|
|
78
|
+
delete options[option];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return options;
|
|
82
|
+
}
|
|
83
|
+
async function resolveHeaders(viewResponse, options) {
|
|
84
|
+
options = normalizeOptions(options);
|
|
85
|
+
const headers = normalizeHeaders(viewResponse.headers);
|
|
86
|
+
if (options.contentSecurityPolicy === void 0 || typeof options.contentSecurityPolicy === "object") {
|
|
87
|
+
const headerName = options.contentSecurityPolicy?.reportOnly ? "content-security-policy-report-only" : "content-security-policy";
|
|
88
|
+
let hashes;
|
|
89
|
+
if (options.contentSecurityPolicy?.resourceHashing === void 0) {
|
|
90
|
+
hashes = await getResourceHashes(viewResponse);
|
|
91
|
+
}
|
|
92
|
+
headers[headerName] = (0, import_content_security_policy.default)(headers[headerName], options.contentSecurityPolicy, hashes);
|
|
93
|
+
}
|
|
94
|
+
if (options.referrerPolicy === void 0 || typeof options.referrerPolicy === "object") {
|
|
95
|
+
const headerName = "referrer-policy";
|
|
96
|
+
headers[headerName] = (0, import_referrer_policy.default)(headers[headerName], options.referrerPolicy);
|
|
97
|
+
}
|
|
98
|
+
if (options.strictTransportSecurity === void 0 || typeof options.strictTransportSecurity === "object") {
|
|
99
|
+
const headerName = "strict-transport-security";
|
|
100
|
+
headers[headerName] = (0, import_strict_transport_security.default)(headers[headerName], options.strictTransportSecurity);
|
|
101
|
+
}
|
|
102
|
+
if (options.crossOriginEmbedderPolicy === void 0 || typeof options.crossOriginEmbedderPolicy === "string") {
|
|
103
|
+
const headerName = "cross-origin-embedder-policy";
|
|
104
|
+
headers[headerName] = headers[headerName] || options?.crossOriginEmbedderPolicy || "require-corp";
|
|
105
|
+
}
|
|
106
|
+
if (options.crossOriginOpenerPolicy === void 0 || typeof options.crossOriginOpenerPolicy === "string") {
|
|
107
|
+
const headerName = "cross-origin-opener-policy";
|
|
108
|
+
headers[headerName] = headers[headerName] || options?.crossOriginOpenerPolicy || "same-origin";
|
|
109
|
+
}
|
|
110
|
+
if (options.crossOriginResourcePolicy === void 0 || typeof options.crossOriginResourcePolicy === "string") {
|
|
111
|
+
const headerName = "cross-origin-resource-policy";
|
|
112
|
+
headers[headerName] = headers[headerName] || options?.crossOriginResourcePolicy || "same-origin";
|
|
113
|
+
}
|
|
114
|
+
if (options.xContentTypeOptions === void 0) {
|
|
115
|
+
headers["x-content-type-options"] = "nosniff";
|
|
116
|
+
}
|
|
117
|
+
if (options.xFrameOptions === void 0) {
|
|
118
|
+
headers["x-frame-options"] = "sameorigin";
|
|
119
|
+
}
|
|
120
|
+
if (options.xPermittedCrossDomainPolicies === void 0) {
|
|
121
|
+
headers["x-permitted-cross-domain-policies"] = "none";
|
|
122
|
+
}
|
|
123
|
+
if (options.xXSSProtection === void 0) {
|
|
124
|
+
headers["x-xss-protection"] = "0";
|
|
125
|
+
}
|
|
126
|
+
return headers;
|
|
127
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
11
|
+
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/security/src/index.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
default: () => import_route_handler.default,
|
|
28
|
+
secure: () => import_wrapper.secure
|
|
29
|
+
});
|
|
30
|
+
var import_route_handler = __toModule(require("./route-handler.cjs"));
|
|
31
|
+
var import_wrapper = __toModule(require("./wrapper.cjs"));
|
|
32
|
+
__exportStar(exports, __toModule(require("./options.cjs")));
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
11
|
+
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/security/src/route-handler.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
default: () => securityRouteHandler
|
|
28
|
+
});
|
|
29
|
+
var import_headers = __toModule(require("./headers.cjs"));
|
|
30
|
+
async function securityRouteHandler(request, context, options) {
|
|
31
|
+
const viewResponse = await context.viewApi.getViewResponse(context.route);
|
|
32
|
+
viewResponse.headers = await (0, import_headers.resolveHeaders)(viewResponse, options);
|
|
33
|
+
return viewResponse;
|
|
34
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, {get: all[name], enumerable: true});
|
|
11
|
+
};
|
|
12
|
+
var __exportStar = (target, module2, desc) => {
|
|
13
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(module2))
|
|
15
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
16
|
+
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
|
|
17
|
+
}
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
var __toModule = (module2) => {
|
|
21
|
+
return __exportStar(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? {get: () => module2.default, enumerable: true} : {value: module2, enumerable: true})), module2);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// packages/@lwrjs/security/src/wrapper.ts
|
|
25
|
+
__markAsModule(exports);
|
|
26
|
+
__export(exports, {
|
|
27
|
+
secure: () => secure
|
|
28
|
+
});
|
|
29
|
+
var import_headers = __toModule(require("./headers.cjs"));
|
|
30
|
+
function isViewResponse(response) {
|
|
31
|
+
return response.body !== void 0;
|
|
32
|
+
}
|
|
33
|
+
function isViewDefinitionResponse(response) {
|
|
34
|
+
return response.view !== void 0;
|
|
35
|
+
}
|
|
36
|
+
function secure(routeHandler, options) {
|
|
37
|
+
return async (request, context) => {
|
|
38
|
+
const routeHandlerResponse = await routeHandler(request, context);
|
|
39
|
+
if (isViewResponse(routeHandlerResponse)) {
|
|
40
|
+
if (!routeHandlerResponse.headers || !routeHandlerResponse.headers["content-type"].startsWith("text/html")) {
|
|
41
|
+
return routeHandlerResponse;
|
|
42
|
+
}
|
|
43
|
+
routeHandlerResponse.headers = await (0, import_headers.resolveHeaders)(routeHandlerResponse, options);
|
|
44
|
+
return routeHandlerResponse;
|
|
45
|
+
}
|
|
46
|
+
if (isViewDefinitionResponse(routeHandlerResponse)) {
|
|
47
|
+
const viewResponse = await context.viewApi.getViewResponse(routeHandlerResponse.view, routeHandlerResponse.viewParams, routeHandlerResponse.renderOptions);
|
|
48
|
+
viewResponse.headers = {
|
|
49
|
+
...viewResponse.headers,
|
|
50
|
+
...routeHandlerResponse.headers
|
|
51
|
+
};
|
|
52
|
+
viewResponse.headers = await (0, import_headers.resolveHeaders)(viewResponse, options);
|
|
53
|
+
return viewResponse;
|
|
54
|
+
}
|
|
55
|
+
throw new Error("Unexpected route handler response");
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare type Directives = {
|
|
2
|
+
[key: string]: string[];
|
|
3
|
+
};
|
|
4
|
+
export interface ContentSecurityPolicy {
|
|
5
|
+
useDefault?: boolean;
|
|
6
|
+
resourceHashing?: boolean;
|
|
7
|
+
reportOnly?: boolean;
|
|
8
|
+
directives?: Directives | string;
|
|
9
|
+
}
|
|
10
|
+
export default function contentSecurityPolicy(header?: string, options?: ContentSecurityPolicy, hashes?: string[]): string;
|
|
11
|
+
//# sourceMappingURL=content-security-policy.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const DEFAULT_DIRECTIVES = {
|
|
2
|
+
'default-src': ["'self'"],
|
|
3
|
+
'base-uri': ["'self'"],
|
|
4
|
+
'font-src': ["'self'", 'https:', 'data:'],
|
|
5
|
+
'form-action': ["'self'"],
|
|
6
|
+
'frame-ancestors': ["'self'"],
|
|
7
|
+
'img-src': ["'self'", 'data:'],
|
|
8
|
+
'object-src': ["'none'"],
|
|
9
|
+
'script-src': ["'self'"],
|
|
10
|
+
'script-src-attr': ["'none'"],
|
|
11
|
+
'style-src': ["'self'", 'https:', "'unsafe-inline'"],
|
|
12
|
+
'upgrade-insecure-requests': [],
|
|
13
|
+
};
|
|
14
|
+
function parseDirectives(str) {
|
|
15
|
+
const directives = {};
|
|
16
|
+
for (const directive of str.split(';')) {
|
|
17
|
+
const [key, ...value] = directive.trim().split(' ');
|
|
18
|
+
directives[key] = value;
|
|
19
|
+
}
|
|
20
|
+
return directives;
|
|
21
|
+
}
|
|
22
|
+
function stringifyDirectives(directives) {
|
|
23
|
+
const output = [];
|
|
24
|
+
for (const directive of directives.keys()) {
|
|
25
|
+
const values = directives.get(directive);
|
|
26
|
+
if (!values) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
output.push(`${directive} ${Array.from(values).join(' ')}`);
|
|
30
|
+
}
|
|
31
|
+
return output.join(';');
|
|
32
|
+
}
|
|
33
|
+
function normalizeDirectives(input) {
|
|
34
|
+
const output = new Map();
|
|
35
|
+
for (const directives of input) {
|
|
36
|
+
for (const [directive, values] of Object.entries(directives)) {
|
|
37
|
+
let set = output.get(directive);
|
|
38
|
+
if (!set) {
|
|
39
|
+
set = new Set();
|
|
40
|
+
output.set(directive, set);
|
|
41
|
+
}
|
|
42
|
+
for (const value of values) {
|
|
43
|
+
set.add(value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return output;
|
|
48
|
+
}
|
|
49
|
+
export default function contentSecurityPolicy(header, options, hashes) {
|
|
50
|
+
const input = [];
|
|
51
|
+
if (options?.useDefault === undefined || options?.useDefault === true) {
|
|
52
|
+
input.push(DEFAULT_DIRECTIVES);
|
|
53
|
+
}
|
|
54
|
+
if (options?.directives && typeof options.directives === 'object') {
|
|
55
|
+
input.push(options.directives);
|
|
56
|
+
}
|
|
57
|
+
if (options?.directives && typeof options.directives === 'string') {
|
|
58
|
+
input.push(parseDirectives(options.directives));
|
|
59
|
+
}
|
|
60
|
+
if (header?.length) {
|
|
61
|
+
input.push(parseDirectives(header));
|
|
62
|
+
}
|
|
63
|
+
if (hashes?.length) {
|
|
64
|
+
input.push({
|
|
65
|
+
'script-src': hashes,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const normalizedDirectives = normalizeDirectives(input);
|
|
69
|
+
return stringifyDirectives(normalizedDirectives);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=content-security-policy.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const DEFAULT_DIRECTIVE = 'no-referrer';
|
|
2
|
+
export default function referrerPolicy(header, option) {
|
|
3
|
+
const value = header || option;
|
|
4
|
+
if (!value) {
|
|
5
|
+
return DEFAULT_DIRECTIVE;
|
|
6
|
+
}
|
|
7
|
+
const directives = typeof value === 'string' ? [value] : value;
|
|
8
|
+
return directives.join(',');
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=referrer-policy.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface StrictTransportSecurity {
|
|
2
|
+
maxAge?: number;
|
|
3
|
+
includeSubDomains?: boolean;
|
|
4
|
+
preload?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export default function strictTransportSecurity(header?: string, option?: StrictTransportSecurity): string;
|
|
7
|
+
//# sourceMappingURL=strict-transport-security.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const DEFAULT_MAX_AGE = 180 * 24 * 60 * 60;
|
|
2
|
+
function parseDirectives(str) {
|
|
3
|
+
const policy = {};
|
|
4
|
+
for (const segment of str.split(';')) {
|
|
5
|
+
const directive = segment.trim();
|
|
6
|
+
if (directive.startsWith('maxage')) {
|
|
7
|
+
policy.maxAge = parseInt(directive.substring(directive.indexOf('=') + 1));
|
|
8
|
+
}
|
|
9
|
+
if (directive === 'includeSubDomains') {
|
|
10
|
+
policy.includeSubDomains = true;
|
|
11
|
+
}
|
|
12
|
+
if (directive === 'preload') {
|
|
13
|
+
policy.preload = true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return policy;
|
|
17
|
+
}
|
|
18
|
+
export default function strictTransportSecurity(header, option) {
|
|
19
|
+
const policy = header !== undefined ? parseDirectives(header) : option;
|
|
20
|
+
const maxAge = policy?.maxAge !== undefined ? policy.maxAge : DEFAULT_MAX_AGE;
|
|
21
|
+
const directives = [`max-age=${maxAge}`];
|
|
22
|
+
if (policy?.includeSubDomains === undefined || policy?.includeSubDomains) {
|
|
23
|
+
directives.push('includeSubDomains');
|
|
24
|
+
}
|
|
25
|
+
if (policy?.preload) {
|
|
26
|
+
directives.push('preload');
|
|
27
|
+
}
|
|
28
|
+
return directives.join('; ');
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=strict-transport-security.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ViewResponse } from '@lwrjs/types';
|
|
2
|
+
import type { SecurityOptions } from './options.js';
|
|
3
|
+
export declare function resolveHeaders(viewResponse: ViewResponse, options?: SecurityOptions): Promise<Record<string, string>>;
|
|
4
|
+
//# sourceMappingURL=headers.d.ts.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { streamToString } from '@lwrjs/shared-utils';
|
|
3
|
+
import contentSecurityPolicy from './headers/content-security-policy.js';
|
|
4
|
+
import referrerPolicy from './headers/referrer-policy.js';
|
|
5
|
+
import strictTransportSecurity from './headers/strict-transport-security.js';
|
|
6
|
+
function getResources(viewDefinition) {
|
|
7
|
+
const { viewRecord } = viewDefinition;
|
|
8
|
+
const resources = [];
|
|
9
|
+
if (viewRecord.resources) {
|
|
10
|
+
resources.push(...viewRecord.resources);
|
|
11
|
+
}
|
|
12
|
+
if (viewRecord.bootstrapModule?.resources) {
|
|
13
|
+
resources.push(...viewRecord.bootstrapModule.resources);
|
|
14
|
+
}
|
|
15
|
+
return resources;
|
|
16
|
+
}
|
|
17
|
+
function hash(source) {
|
|
18
|
+
return `'sha256-${createHash('sha256').update(source).digest('base64')}'`;
|
|
19
|
+
}
|
|
20
|
+
async function hashResources(resources) {
|
|
21
|
+
const hashes = [];
|
|
22
|
+
for (const resource of resources) {
|
|
23
|
+
// TODO: support other inlined resource types
|
|
24
|
+
if (!resource.inline || resource.type !== 'application/javascript')
|
|
25
|
+
continue;
|
|
26
|
+
if (resource.content) {
|
|
27
|
+
hashes.push(hash(resource.content));
|
|
28
|
+
}
|
|
29
|
+
if (resource.stream) {
|
|
30
|
+
// eslint-disable-next-line no-await-in-loop
|
|
31
|
+
const content = await streamToString(resource.stream());
|
|
32
|
+
hashes.push(hash(content));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return hashes;
|
|
36
|
+
}
|
|
37
|
+
async function getResourceHashes(viewResponse) {
|
|
38
|
+
if (!viewResponse.metadata?.viewDefinition) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const { viewDefinition } = viewResponse.metadata;
|
|
42
|
+
const resources = getResources(viewDefinition);
|
|
43
|
+
const hashes = await hashResources(resources);
|
|
44
|
+
return hashes;
|
|
45
|
+
}
|
|
46
|
+
function normalizeHeaders(headers = {}) {
|
|
47
|
+
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
|
|
48
|
+
}
|
|
49
|
+
function normalizeOptions(options = {}) {
|
|
50
|
+
for (const [option, value] of Object.entries(options)) {
|
|
51
|
+
// true values are the same as undefined
|
|
52
|
+
if (value === true) {
|
|
53
|
+
delete options[option];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return options;
|
|
57
|
+
}
|
|
58
|
+
export async function resolveHeaders(viewResponse, options) {
|
|
59
|
+
options = normalizeOptions(options);
|
|
60
|
+
const headers = normalizeHeaders(viewResponse.headers);
|
|
61
|
+
if (options.contentSecurityPolicy === undefined || typeof options.contentSecurityPolicy === 'object') {
|
|
62
|
+
const headerName = options.contentSecurityPolicy?.reportOnly
|
|
63
|
+
? 'content-security-policy-report-only'
|
|
64
|
+
: 'content-security-policy';
|
|
65
|
+
let hashes;
|
|
66
|
+
if (options.contentSecurityPolicy?.resourceHashing === undefined) {
|
|
67
|
+
hashes = await getResourceHashes(viewResponse);
|
|
68
|
+
}
|
|
69
|
+
headers[headerName] = contentSecurityPolicy(headers[headerName], options.contentSecurityPolicy, hashes);
|
|
70
|
+
}
|
|
71
|
+
if (options.referrerPolicy === undefined || typeof options.referrerPolicy === 'object') {
|
|
72
|
+
const headerName = 'referrer-policy';
|
|
73
|
+
headers[headerName] = referrerPolicy(headers[headerName], options.referrerPolicy);
|
|
74
|
+
}
|
|
75
|
+
if (options.strictTransportSecurity === undefined ||
|
|
76
|
+
typeof options.strictTransportSecurity === 'object') {
|
|
77
|
+
const headerName = 'strict-transport-security';
|
|
78
|
+
headers[headerName] = strictTransportSecurity(headers[headerName], options.strictTransportSecurity);
|
|
79
|
+
}
|
|
80
|
+
if (options.crossOriginEmbedderPolicy === undefined ||
|
|
81
|
+
typeof options.crossOriginEmbedderPolicy === 'string') {
|
|
82
|
+
const headerName = 'cross-origin-embedder-policy';
|
|
83
|
+
headers[headerName] = headers[headerName] || options?.crossOriginEmbedderPolicy || 'require-corp';
|
|
84
|
+
}
|
|
85
|
+
if (options.crossOriginOpenerPolicy === undefined ||
|
|
86
|
+
typeof options.crossOriginOpenerPolicy === 'string') {
|
|
87
|
+
const headerName = 'cross-origin-opener-policy';
|
|
88
|
+
headers[headerName] = headers[headerName] || options?.crossOriginOpenerPolicy || 'same-origin';
|
|
89
|
+
}
|
|
90
|
+
if (options.crossOriginResourcePolicy === undefined ||
|
|
91
|
+
typeof options.crossOriginResourcePolicy === 'string') {
|
|
92
|
+
const headerName = 'cross-origin-resource-policy';
|
|
93
|
+
headers[headerName] = headers[headerName] || options?.crossOriginResourcePolicy || 'same-origin';
|
|
94
|
+
}
|
|
95
|
+
if (options.xContentTypeOptions === undefined) {
|
|
96
|
+
headers['x-content-type-options'] = 'nosniff';
|
|
97
|
+
}
|
|
98
|
+
if (options.xFrameOptions === undefined) {
|
|
99
|
+
headers['x-frame-options'] = 'sameorigin';
|
|
100
|
+
}
|
|
101
|
+
if (options.xPermittedCrossDomainPolicies === undefined) {
|
|
102
|
+
headers['x-permitted-cross-domain-policies'] = 'none';
|
|
103
|
+
}
|
|
104
|
+
if (options.xXSSProtection === undefined) {
|
|
105
|
+
// this header is deprecated, and the recommendation is to disable it
|
|
106
|
+
// https://owasp.org/www-project-secure-headers/#x-xss-protection
|
|
107
|
+
headers['x-xss-protection'] = '0';
|
|
108
|
+
}
|
|
109
|
+
return headers;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=headers.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ContentSecurityPolicy } from './headers/content-security-policy.js';
|
|
2
|
+
import type { ReferrerPolicy } from './headers/referrer-policy.js';
|
|
3
|
+
import type { StrictTransportSecurity } from './headers/strict-transport-security.js';
|
|
4
|
+
export interface SecurityOptions extends Record<string, any> {
|
|
5
|
+
contentSecurityPolicy?: ContentSecurityPolicy | boolean;
|
|
6
|
+
referrerPolicy?: ReferrerPolicy | boolean;
|
|
7
|
+
strictTransportSecurity?: StrictTransportSecurity | boolean;
|
|
8
|
+
crossOriginEmbedderPolicy?: string | boolean;
|
|
9
|
+
crossOriginOpenerPolicy?: string | boolean;
|
|
10
|
+
crossOriginResourcePolicy?: string | boolean;
|
|
11
|
+
xContentTypeOptions?: boolean;
|
|
12
|
+
xFrameOptions?: boolean;
|
|
13
|
+
xPermittedCrossDomainPolicies?: boolean;
|
|
14
|
+
xXSSProtection?: boolean;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HandlerContext, ViewRequest, ViewResponse } from '@lwrjs/types';
|
|
2
|
+
import type { SecurityOptions } from './options.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve and secure the view
|
|
5
|
+
*
|
|
6
|
+
* @param request - inbound view request
|
|
7
|
+
* @param context - route handler context
|
|
8
|
+
* @returns a route handler
|
|
9
|
+
*/
|
|
10
|
+
export default function securityRouteHandler(request: ViewRequest, context: HandlerContext, options?: SecurityOptions): Promise<ViewResponse>;
|
|
11
|
+
//# sourceMappingURL=route-handler.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { resolveHeaders } from './headers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve and secure the view
|
|
4
|
+
*
|
|
5
|
+
* @param request - inbound view request
|
|
6
|
+
* @param context - route handler context
|
|
7
|
+
* @returns a route handler
|
|
8
|
+
*/
|
|
9
|
+
export default async function securityRouteHandler(request, context, options) {
|
|
10
|
+
const viewResponse = await context.viewApi.getViewResponse(context.route);
|
|
11
|
+
viewResponse.headers = await resolveHeaders(viewResponse, options);
|
|
12
|
+
return viewResponse;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=route-handler.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RouteHandlerFunction } from '@lwrjs/types';
|
|
2
|
+
import type { SecurityOptions } from './options.js';
|
|
3
|
+
/**
|
|
4
|
+
* Wrap existing route handlers to apply security headers and conditionally inline script hashing
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Script hashing is only applied when the provided route handler returns a `ViewDefinitionResponse`
|
|
8
|
+
*
|
|
9
|
+
* Security headers are not applied when the route handler returns a `ViewResponse` that is not HTML
|
|
10
|
+
*
|
|
11
|
+
* @param routeHandler - existing route handler
|
|
12
|
+
* @returns a route handler
|
|
13
|
+
*/
|
|
14
|
+
export declare function secure(routeHandler: RouteHandlerFunction, options?: SecurityOptions): RouteHandlerFunction;
|
|
15
|
+
//# sourceMappingURL=wrapper.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { resolveHeaders } from './headers.js';
|
|
2
|
+
function isViewResponse(response) {
|
|
3
|
+
return response.body !== undefined;
|
|
4
|
+
}
|
|
5
|
+
function isViewDefinitionResponse(response) {
|
|
6
|
+
return response.view !== undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wrap existing route handlers to apply security headers and conditionally inline script hashing
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Script hashing is only applied when the provided route handler returns a `ViewDefinitionResponse`
|
|
13
|
+
*
|
|
14
|
+
* Security headers are not applied when the route handler returns a `ViewResponse` that is not HTML
|
|
15
|
+
*
|
|
16
|
+
* @param routeHandler - existing route handler
|
|
17
|
+
* @returns a route handler
|
|
18
|
+
*/
|
|
19
|
+
export function secure(routeHandler, options) {
|
|
20
|
+
return async (request, context) => {
|
|
21
|
+
// TODO: handle sync response
|
|
22
|
+
const routeHandlerResponse = await routeHandler(request, context);
|
|
23
|
+
if (isViewResponse(routeHandlerResponse)) {
|
|
24
|
+
// only apply headers when the view response is html
|
|
25
|
+
if (!routeHandlerResponse.headers ||
|
|
26
|
+
!routeHandlerResponse.headers['content-type'].startsWith('text/html')) {
|
|
27
|
+
return routeHandlerResponse;
|
|
28
|
+
}
|
|
29
|
+
// merge custom security headers with defaults
|
|
30
|
+
routeHandlerResponse.headers = await resolveHeaders(routeHandlerResponse, options);
|
|
31
|
+
return routeHandlerResponse;
|
|
32
|
+
}
|
|
33
|
+
if (isViewDefinitionResponse(routeHandlerResponse)) {
|
|
34
|
+
// resolve the view based on the route handler response
|
|
35
|
+
const viewResponse = await context.viewApi.getViewResponse(routeHandlerResponse.view, routeHandlerResponse.viewParams, routeHandlerResponse.renderOptions);
|
|
36
|
+
viewResponse.headers = {
|
|
37
|
+
...viewResponse.headers,
|
|
38
|
+
...routeHandlerResponse.headers,
|
|
39
|
+
};
|
|
40
|
+
// set headers according to options
|
|
41
|
+
viewResponse.headers = await resolveHeaders(viewResponse, options);
|
|
42
|
+
return viewResponse;
|
|
43
|
+
}
|
|
44
|
+
throw new Error('Unexpected route handler response');
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=wrapper.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lwrjs/security",
|
|
3
|
+
"version": "0.10.0-alpha.16",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "build/es/index.d.ts",
|
|
7
|
+
"module": "build/es/index.js",
|
|
8
|
+
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/salesforce-experience-platform-emu/lwr.git",
|
|
12
|
+
"directory": "packages/@lwrjs/security"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/salesforce-experience-platform-emu/lwr/issues"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./build/es/index.js",
|
|
23
|
+
"require": "./build/cjs/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"build/**/*.js",
|
|
28
|
+
"build/**/*.cjs",
|
|
29
|
+
"build/**/*.d.ts"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@lwrjs/shared-utils": "0.10.0-alpha.16"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@lwrjs/types": "0.10.0-alpha.16"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=16.0.0 <20"
|
|
39
|
+
},
|
|
40
|
+
"gitHead": "c5a13d471330c0f738d0c783fd1b69f456c544bd"
|
|
41
|
+
}
|