@n8n/scan-community-package 0.5.0 → 0.7.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/package.json +2 -2
- package/scanner/scanner.mjs +36 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@n8n/scan-community-package",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Static code analyser for n8n community packages",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"bin": "scanner/cli.mjs",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"axios": "1.12.0",
|
|
16
16
|
"semver": "^7.5.4",
|
|
17
17
|
"tmp": "0.2.4",
|
|
18
|
-
"@n8n/eslint-plugin-community-nodes": "0.
|
|
18
|
+
"@n8n/eslint-plugin-community-nodes": "0.6.0"
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://n8n.io",
|
|
21
21
|
"author": {
|
package/scanner/scanner.mjs
CHANGED
|
@@ -16,6 +16,40 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
16
16
|
const TEMP_DIR = tmp.dirSync({ unsafeCleanup: true }).name;
|
|
17
17
|
const registry = 'https://registry.npmjs.org/';
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Checks if the given childPath is contained within the parentPath. Resolves
|
|
21
|
+
* the paths before comparing them, so that relative paths are also supported.
|
|
22
|
+
*/
|
|
23
|
+
export function isContainedWithin(parentPath, childPath) {
|
|
24
|
+
parentPath = path.resolve(parentPath);
|
|
25
|
+
childPath = path.resolve(childPath);
|
|
26
|
+
|
|
27
|
+
if (parentPath === childPath) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return childPath.startsWith(parentPath + path.sep);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Joins the given paths to the parentPath, ensuring that the resulting path
|
|
36
|
+
* is still contained within the parentPath. If not, it throws an error to
|
|
37
|
+
* prevent path traversal vulnerabilities.
|
|
38
|
+
*
|
|
39
|
+
* @throws {UnexpectedError} If the resulting path is not contained within the parentPath.
|
|
40
|
+
*/
|
|
41
|
+
export function safeJoinPath(parentPath, ...paths) {
|
|
42
|
+
const candidate = path.join(parentPath, ...paths);
|
|
43
|
+
|
|
44
|
+
if (!isContainedWithin(parentPath, candidate)) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Path traversal detected, refusing to join paths: ${parentPath} and ${JSON.stringify(paths)}`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return candidate;
|
|
51
|
+
}
|
|
52
|
+
|
|
19
53
|
export const resolvePackage = (packageSpec) => {
|
|
20
54
|
// Validate input to prevent command injection
|
|
21
55
|
if (!/^[a-zA-Z0-9@/_.-]+$/.test(packageSpec)) {
|
|
@@ -57,7 +91,7 @@ const downloadAndExtractPackage = async (packageName, version) => {
|
|
|
57
91
|
}
|
|
58
92
|
|
|
59
93
|
// Unpack the tarball
|
|
60
|
-
const packageDir =
|
|
94
|
+
const packageDir = safeJoinPath(TEMP_DIR, `${packageName}-${version}`);
|
|
61
95
|
fs.mkdirSync(packageDir, { recursive: true });
|
|
62
96
|
const tarResult = spawnSync(
|
|
63
97
|
'tar',
|
|
@@ -70,7 +104,7 @@ const downloadAndExtractPackage = async (packageName, version) => {
|
|
|
70
104
|
if (tarResult.status !== 0) {
|
|
71
105
|
throw new Error(`tar extraction failed: ${tarResult.stderr?.toString()}`);
|
|
72
106
|
}
|
|
73
|
-
fs.unlinkSync(
|
|
107
|
+
fs.unlinkSync(safeJoinPath(TEMP_DIR, tarballName));
|
|
74
108
|
|
|
75
109
|
return packageDir;
|
|
76
110
|
} catch (error) {
|