@lwrjs/fs-asset-provider 0.24.0 → 0.24.1
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/index.cjs +7 -3
- package/build/es/index.d.ts +6 -0
- package/build/es/index.js +20 -4
- package/package.json +5 -5
package/build/cjs/index.cjs
CHANGED
|
@@ -72,13 +72,17 @@ var FsAssetProvider = class {
|
|
|
72
72
|
const fullAssetPath = (0, import_shared_utils.normalizeAssetSpecifier)(assetId, this.assetPathMap, this.resourcePaths, this.basePath);
|
|
73
73
|
return this.getAssetFromFSPath(fullAssetPath);
|
|
74
74
|
}
|
|
75
|
+
isWithinConfiguredRoots(resolvedPath) {
|
|
76
|
+
const roots = [...this.assetPathMap.values(), ...Object.values(this.resourcePaths)].filter((root) => typeof root === "string" && root.length > 0).map((root) => (0, import_path.resolve)(root));
|
|
77
|
+
return roots.some((root) => resolvedPath === root || resolvedPath.startsWith(root + import_path.sep));
|
|
78
|
+
}
|
|
75
79
|
async getAssetFromFSPath(assetPath) {
|
|
76
|
-
|
|
77
|
-
const fullAssetPath =
|
|
80
|
+
const decodedAssetPath = decodeURI(assetPath);
|
|
81
|
+
const fullAssetPath = (0, import_shared_utils.toForwardSlash)((0, import_path.normalize)(decodedAssetPath));
|
|
78
82
|
if (!this.cachedAssets.has(fullAssetPath)) {
|
|
79
83
|
const [assetPath2] = fullAssetPath.split("?");
|
|
80
84
|
const ext = (0, import_path.extname)(`x.${assetPath2}`).toLowerCase().substring(1);
|
|
81
|
-
if (ext && import_fs_extra.default.existsSync(assetPath2)) {
|
|
85
|
+
if (ext && import_fs_extra.default.existsSync(assetPath2) && this.isWithinConfiguredRoots((0, import_path.resolve)(assetPath2))) {
|
|
82
86
|
const ownHash = hash(assetPath2);
|
|
83
87
|
const mimeType = (0, import_shared_utils.mimeLookup)(assetPath2);
|
|
84
88
|
const assetDef = {
|
package/build/es/index.d.ts
CHANGED
|
@@ -14,6 +14,12 @@ export default class FsAssetProvider implements AssetProvider {
|
|
|
14
14
|
* Public API to get an AssetSource object from an asset identifier
|
|
15
15
|
*/
|
|
16
16
|
getAsset(assetId: AssetIdentifier): Promise<AssetSource | undefined>;
|
|
17
|
+
/**
|
|
18
|
+
* True if the resolved path falls within one of the roots this provider is configured
|
|
19
|
+
* to serve from. Last line of defense against path traversal, independent of whatever
|
|
20
|
+
* validation (or lack thereof) happened upstream of this provider.
|
|
21
|
+
*/
|
|
22
|
+
private isWithinConfiguredRoots;
|
|
17
23
|
/**
|
|
18
24
|
* Get and AssetSource object from a resolved filesystem file path.
|
|
19
25
|
*/
|
package/build/es/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
|
-
import { extname, normalize } from 'path';
|
|
2
|
+
import { extname, normalize, resolve, sep } from 'path';
|
|
3
3
|
import { logger } from '@lwrjs/diagnostics';
|
|
4
4
|
import { mimeLookup, normalizeAssetSpecifier, toForwardSlash } from '@lwrjs/shared-utils';
|
|
5
5
|
function hash(filePath) {
|
|
@@ -45,17 +45,33 @@ export default class FsAssetProvider {
|
|
|
45
45
|
const fullAssetPath = normalizeAssetSpecifier(assetId, this.assetPathMap, this.resourcePaths, this.basePath);
|
|
46
46
|
return this.getAssetFromFSPath(fullAssetPath);
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* True if the resolved path falls within one of the roots this provider is configured
|
|
50
|
+
* to serve from. Last line of defense against path traversal, independent of whatever
|
|
51
|
+
* validation (or lack thereof) happened upstream of this provider.
|
|
52
|
+
*/
|
|
53
|
+
isWithinConfiguredRoots(resolvedPath) {
|
|
54
|
+
const roots = [...this.assetPathMap.values(), ...Object.values(this.resourcePaths)]
|
|
55
|
+
.filter((root) => typeof root === 'string' && root.length > 0)
|
|
56
|
+
.map((root) => resolve(root));
|
|
57
|
+
return roots.some((root) => resolvedPath === root || resolvedPath.startsWith(root + sep));
|
|
58
|
+
}
|
|
48
59
|
/**
|
|
49
60
|
* Get and AssetSource object from a resolved filesystem file path.
|
|
50
61
|
*/
|
|
51
62
|
async getAssetFromFSPath(assetPath) {
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
// Decode BEFORE normalizing: percent-encoded traversal segments (eg '%2e%2e%2f')
|
|
64
|
+
// must become literal '..' segments before normalize() can collapse them. Decoding
|
|
65
|
+
// after normalize (the previous order) let encoded traversal sequences pass through
|
|
66
|
+
// untouched.
|
|
67
|
+
// decodeURIComponent decodes too many things (eg: /), so use decodeURI here.
|
|
68
|
+
const decodedAssetPath = decodeURI(assetPath);
|
|
69
|
+
const fullAssetPath = toForwardSlash(normalize(decodedAssetPath));
|
|
54
70
|
if (!this.cachedAssets.has(fullAssetPath)) {
|
|
55
71
|
const [assetPath] = fullAssetPath.split('?'); // remove query params
|
|
56
72
|
// Clever normalization to avoid corner cases
|
|
57
73
|
const ext = extname(`x.${assetPath}`).toLowerCase().substring(1);
|
|
58
|
-
if (ext && fs.existsSync(assetPath)) {
|
|
74
|
+
if (ext && fs.existsSync(assetPath) && this.isWithinConfiguredRoots(resolve(assetPath))) {
|
|
59
75
|
const ownHash = hash(assetPath);
|
|
60
76
|
const mimeType = mimeLookup(assetPath);
|
|
61
77
|
const assetDef = {
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.24.
|
|
7
|
+
"version": "0.24.1",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
"build": "tsc -b"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@lwrjs/diagnostics": "0.24.
|
|
37
|
-
"@lwrjs/shared-utils": "0.24.
|
|
36
|
+
"@lwrjs/diagnostics": "0.24.1",
|
|
37
|
+
"@lwrjs/shared-utils": "0.24.1",
|
|
38
38
|
"fs-extra": "^11.2.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@lwrjs/types": "0.24.
|
|
41
|
+
"@lwrjs/types": "0.24.1",
|
|
42
42
|
"memfs": "^4.13.0"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=22.0.0"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "ebc0aaa310f5ebd008732d0203a15a1c51f77e5e"
|
|
48
48
|
}
|