@nodesecure/scanner 3.2.1 → 3.3.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 +2 -2
- package/index.js +63 -63
- package/package.json +86 -86
- package/src/depWalker.js +11 -5
- package/src/tarball.js +173 -173
- package/types/api.d.ts +15 -15
- package/types/scanner.d.ts +185 -185
package/README.md
CHANGED
|
@@ -49,9 +49,9 @@ await Promise.allSettled(promises);
|
|
|
49
49
|
See `types/api.d.ts` for a complete TypeScript definition.
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
|
-
function cwd(
|
|
52
|
+
function cwd(location: string, options?: Scanner.Options): Promise<Scanner.Payload>;
|
|
53
53
|
function from(packageName: string, options?: Scanner.Options): Promise<Scanner.Payload>;
|
|
54
|
-
function verify(packageName
|
|
54
|
+
function verify(packageName?: string | null): Promise<Scanner.VerifyPayload>;
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
`Options` is described with the following TypeScript interface:
|
package/index.js
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
// Import Node.js Dependencies
|
|
2
|
-
import path from "path";
|
|
3
|
-
import fs from "fs/promises";
|
|
4
|
-
import timers from "timers/promises";
|
|
5
|
-
import os from "os";
|
|
6
|
-
|
|
7
|
-
// Import Third-party Dependencies
|
|
8
|
-
import pacote from "pacote";
|
|
9
|
-
import { getLocalRegistryURL } from "@nodesecure/npm-registry-sdk";
|
|
10
|
-
|
|
11
|
-
// Import Internal Dependencies
|
|
12
|
-
import { depWalker } from "./src/depWalker.js";
|
|
13
|
-
import { NPM_TOKEN } from "./src/utils/index.js";
|
|
14
|
-
import { ScannerLoggerEvents } from "./src/constants.js";
|
|
15
|
-
import Logger from "./src/class/logger.class.js";
|
|
16
|
-
import * as tarball from "./src/tarball.js";
|
|
17
|
-
|
|
18
|
-
// CONSTANTS
|
|
19
|
-
const kDefaultCwdOptions = { forceRootAnalysis: true, usePackageLock: true };
|
|
20
|
-
|
|
21
|
-
export async function cwd(
|
|
22
|
-
const finalizedOptions = Object.assign({}, kDefaultCwdOptions, options);
|
|
23
|
-
|
|
24
|
-
logger.start(ScannerLoggerEvents.manifest.read);
|
|
25
|
-
const packagePath = path.join(
|
|
26
|
-
const str = await fs.readFile(packagePath, "utf-8");
|
|
27
|
-
logger.end(ScannerLoggerEvents.manifest.read);
|
|
28
|
-
|
|
29
|
-
return depWalker(JSON.parse(str), finalizedOptions, logger);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function from(packageName, options, logger = new Logger()) {
|
|
33
|
-
logger.start(ScannerLoggerEvents.manifest.fetch);
|
|
34
|
-
const manifest = await pacote.manifest(packageName, {
|
|
35
|
-
...NPM_TOKEN, registry: getLocalRegistryURL(), cache: `${os.homedir()}/.npm`
|
|
36
|
-
});
|
|
37
|
-
logger.end(ScannerLoggerEvents.manifest.fetch);
|
|
38
|
-
|
|
39
|
-
return depWalker(manifest, options, logger);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export async function verify(packageName = null) {
|
|
43
|
-
if (typeof packageName === "undefined" || packageName === null) {
|
|
44
|
-
return await tarball.scanPackage(process.cwd());
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const tmpLocation = await fs.mkdtemp(path.join(os.tmpdir(), "/"));
|
|
48
|
-
const dest = path.join(tmpLocation, packageName);
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
await pacote.extract(packageName, dest, {
|
|
52
|
-
...NPM_TOKEN, registry: getLocalRegistryURL(), cache: `${os.homedir()}/.npm`
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return await tarball.scanPackage(dest, packageName);
|
|
56
|
-
}
|
|
57
|
-
finally {
|
|
58
|
-
await timers.setImmediate();
|
|
59
|
-
await fs.rm(tmpLocation, { recursive: true, force: true });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export { depWalker, tarball, Logger, ScannerLoggerEvents };
|
|
1
|
+
// Import Node.js Dependencies
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs/promises";
|
|
4
|
+
import timers from "timers/promises";
|
|
5
|
+
import os from "os";
|
|
6
|
+
|
|
7
|
+
// Import Third-party Dependencies
|
|
8
|
+
import pacote from "pacote";
|
|
9
|
+
import { getLocalRegistryURL } from "@nodesecure/npm-registry-sdk";
|
|
10
|
+
|
|
11
|
+
// Import Internal Dependencies
|
|
12
|
+
import { depWalker } from "./src/depWalker.js";
|
|
13
|
+
import { NPM_TOKEN } from "./src/utils/index.js";
|
|
14
|
+
import { ScannerLoggerEvents } from "./src/constants.js";
|
|
15
|
+
import Logger from "./src/class/logger.class.js";
|
|
16
|
+
import * as tarball from "./src/tarball.js";
|
|
17
|
+
|
|
18
|
+
// CONSTANTS
|
|
19
|
+
const kDefaultCwdOptions = { forceRootAnalysis: true, usePackageLock: true };
|
|
20
|
+
|
|
21
|
+
export async function cwd(location = process.cwd(), options = {}, logger = new Logger()) {
|
|
22
|
+
const finalizedOptions = Object.assign({ location }, kDefaultCwdOptions, options);
|
|
23
|
+
|
|
24
|
+
logger.start(ScannerLoggerEvents.manifest.read);
|
|
25
|
+
const packagePath = path.join(location, "package.json");
|
|
26
|
+
const str = await fs.readFile(packagePath, "utf-8");
|
|
27
|
+
logger.end(ScannerLoggerEvents.manifest.read);
|
|
28
|
+
|
|
29
|
+
return depWalker(JSON.parse(str), finalizedOptions, logger);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function from(packageName, options, logger = new Logger()) {
|
|
33
|
+
logger.start(ScannerLoggerEvents.manifest.fetch);
|
|
34
|
+
const manifest = await pacote.manifest(packageName, {
|
|
35
|
+
...NPM_TOKEN, registry: getLocalRegistryURL(), cache: `${os.homedir()}/.npm`
|
|
36
|
+
});
|
|
37
|
+
logger.end(ScannerLoggerEvents.manifest.fetch);
|
|
38
|
+
|
|
39
|
+
return depWalker(manifest, options, logger);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function verify(packageName = null) {
|
|
43
|
+
if (typeof packageName === "undefined" || packageName === null) {
|
|
44
|
+
return await tarball.scanPackage(process.cwd());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const tmpLocation = await fs.mkdtemp(path.join(os.tmpdir(), "/"));
|
|
48
|
+
const dest = path.join(tmpLocation, packageName);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await pacote.extract(packageName, dest, {
|
|
52
|
+
...NPM_TOKEN, registry: getLocalRegistryURL(), cache: `${os.homedir()}/.npm`
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return await tarball.scanPackage(dest, packageName);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
await timers.setImmediate();
|
|
59
|
+
await fs.rm(tmpLocation, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { depWalker, tarball, Logger, ScannerLoggerEvents };
|
package/package.json
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@nodesecure/scanner",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "A package API to run a static analysis of your module's dependencies.",
|
|
5
|
-
"exports": "./index.js",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": ">=16"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"lint": "eslint src test",
|
|
11
|
-
"prepublishOnly": "pkg-ok",
|
|
12
|
-
"test": "npm run lint && npm run test-only",
|
|
13
|
-
"test-only": "cross-env esm-tape-runner 'test/**/*.spec.js' | tap-monkey",
|
|
14
|
-
"coverage": "c8 -r html npm run test-only"
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"src",
|
|
18
|
-
"types",
|
|
19
|
-
"index.js",
|
|
20
|
-
"index.d.ts"
|
|
21
|
-
],
|
|
22
|
-
"repository": {
|
|
23
|
-
"type": "git",
|
|
24
|
-
"url": "git+https://github.com/NodeSecure/scanner.git"
|
|
25
|
-
},
|
|
26
|
-
"keywords": [
|
|
27
|
-
"node",
|
|
28
|
-
"nodejs",
|
|
29
|
-
"security",
|
|
30
|
-
"cli",
|
|
31
|
-
"sast",
|
|
32
|
-
"scanner",
|
|
33
|
-
"static",
|
|
34
|
-
"code",
|
|
35
|
-
"analysis",
|
|
36
|
-
"node_modules",
|
|
37
|
-
"tree",
|
|
38
|
-
"npm",
|
|
39
|
-
"registry",
|
|
40
|
-
"graph",
|
|
41
|
-
"visualization",
|
|
42
|
-
"dependencies"
|
|
43
|
-
],
|
|
44
|
-
"author": "NodeSecure",
|
|
45
|
-
"license": "MIT",
|
|
46
|
-
"bugs": {
|
|
47
|
-
"url": "https://github.com/NodeSecure/scanner/issues"
|
|
48
|
-
},
|
|
49
|
-
"homepage": "https://github.com/NodeSecure/scanner#readme",
|
|
50
|
-
"devDependencies": {
|
|
51
|
-
"@nodesecure/eslint-config": "^1.3.
|
|
52
|
-
"@slimio/is": "^1.5.1",
|
|
53
|
-
"@small-tech/esm-tape-runner": "^1.0.3",
|
|
54
|
-
"@small-tech/tap-monkey": "^1.3.0",
|
|
55
|
-
"@types/node": "^
|
|
56
|
-
"c8": "^7.
|
|
57
|
-
"cross-env": "^7.0.3",
|
|
58
|
-
"dotenv": "^
|
|
59
|
-
"eslint": "^8.
|
|
60
|
-
"get-folder-size": "^3.1.0",
|
|
61
|
-
"pkg-ok": "^2.3.1",
|
|
62
|
-
"sinon": "^12.0.1",
|
|
63
|
-
"snap-shot-core": "^10.2.4",
|
|
64
|
-
"tape": "^5.
|
|
65
|
-
},
|
|
66
|
-
"dependencies": {
|
|
67
|
-
"@nodesecure/flags": "^2.2.0",
|
|
68
|
-
"@nodesecure/fs-walk": "^1.0.0",
|
|
69
|
-
"@nodesecure/i18n": "^1.2.1",
|
|
70
|
-
"@nodesecure/js-x-ray": "^4.2.0",
|
|
71
|
-
"@nodesecure/npm-registry-sdk": "^1.3.0",
|
|
72
|
-
"@nodesecure/ntlp": "^2.1.0",
|
|
73
|
-
"@nodesecure/utils": "^1.0.0",
|
|
74
|
-
"@nodesecure/vuln": "^1.
|
|
75
|
-
"@npm/types": "^1.0.1",
|
|
76
|
-
"@npmcli/arborist": "^4.
|
|
77
|
-
"@slimio/lock": "^1.0.0",
|
|
78
|
-
"builtins": "^4.0.0",
|
|
79
|
-
"combine-async-iterators": "^2.0.1",
|
|
80
|
-
"itertools": "^1.7.1",
|
|
81
|
-
"lodash.difference": "^4.5.0",
|
|
82
|
-
"pacote": "^12.0.
|
|
83
|
-
"semver": "^7.3.4"
|
|
84
|
-
},
|
|
85
|
-
"type": "module"
|
|
86
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@nodesecure/scanner",
|
|
3
|
+
"version": "3.3.0",
|
|
4
|
+
"description": "A package API to run a static analysis of your module's dependencies.",
|
|
5
|
+
"exports": "./index.js",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=16"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"lint": "eslint src test",
|
|
11
|
+
"prepublishOnly": "pkg-ok",
|
|
12
|
+
"test": "npm run lint && npm run test-only",
|
|
13
|
+
"test-only": "cross-env esm-tape-runner 'test/**/*.spec.js' | tap-monkey",
|
|
14
|
+
"coverage": "c8 -r html npm run test-only"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"src",
|
|
18
|
+
"types",
|
|
19
|
+
"index.js",
|
|
20
|
+
"index.d.ts"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/NodeSecure/scanner.git"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"node",
|
|
28
|
+
"nodejs",
|
|
29
|
+
"security",
|
|
30
|
+
"cli",
|
|
31
|
+
"sast",
|
|
32
|
+
"scanner",
|
|
33
|
+
"static",
|
|
34
|
+
"code",
|
|
35
|
+
"analysis",
|
|
36
|
+
"node_modules",
|
|
37
|
+
"tree",
|
|
38
|
+
"npm",
|
|
39
|
+
"registry",
|
|
40
|
+
"graph",
|
|
41
|
+
"visualization",
|
|
42
|
+
"dependencies"
|
|
43
|
+
],
|
|
44
|
+
"author": "NodeSecure",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/NodeSecure/scanner/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/NodeSecure/scanner#readme",
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@nodesecure/eslint-config": "^1.3.1",
|
|
52
|
+
"@slimio/is": "^1.5.1",
|
|
53
|
+
"@small-tech/esm-tape-runner": "^1.0.3",
|
|
54
|
+
"@small-tech/tap-monkey": "^1.3.0",
|
|
55
|
+
"@types/node": "^17.0.13",
|
|
56
|
+
"c8": "^7.11.0",
|
|
57
|
+
"cross-env": "^7.0.3",
|
|
58
|
+
"dotenv": "^14.3.2",
|
|
59
|
+
"eslint": "^8.7.0",
|
|
60
|
+
"get-folder-size": "^3.1.0",
|
|
61
|
+
"pkg-ok": "^2.3.1",
|
|
62
|
+
"sinon": "^12.0.1",
|
|
63
|
+
"snap-shot-core": "^10.2.4",
|
|
64
|
+
"tape": "^5.5.0"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@nodesecure/flags": "^2.2.0",
|
|
68
|
+
"@nodesecure/fs-walk": "^1.0.0",
|
|
69
|
+
"@nodesecure/i18n": "^1.2.1",
|
|
70
|
+
"@nodesecure/js-x-ray": "^4.2.0",
|
|
71
|
+
"@nodesecure/npm-registry-sdk": "^1.3.0",
|
|
72
|
+
"@nodesecure/ntlp": "^2.1.0",
|
|
73
|
+
"@nodesecure/utils": "^1.0.0",
|
|
74
|
+
"@nodesecure/vuln": "^1.5.0",
|
|
75
|
+
"@npm/types": "^1.0.1",
|
|
76
|
+
"@npmcli/arborist": "^4.3.0",
|
|
77
|
+
"@slimio/lock": "^1.0.0",
|
|
78
|
+
"builtins": "^4.0.0",
|
|
79
|
+
"combine-async-iterators": "^2.0.1",
|
|
80
|
+
"itertools": "^1.7.1",
|
|
81
|
+
"lodash.difference": "^4.5.0",
|
|
82
|
+
"pacote": "^12.0.3",
|
|
83
|
+
"semver": "^7.3.4"
|
|
84
|
+
},
|
|
85
|
+
"type": "module"
|
|
86
|
+
}
|
package/src/depWalker.js
CHANGED
|
@@ -113,7 +113,7 @@ export async function* deepReadEdges(currentPackageName, { to, parent, exclude,
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
export async function* getRootDependencies(manifest, options) {
|
|
116
|
-
const { maxDepth = 4, exclude, usePackageLock, fullLockMode } = options;
|
|
116
|
+
const { maxDepth = 4, exclude, usePackageLock, fullLockMode, location } = options;
|
|
117
117
|
|
|
118
118
|
const { dependencies, customResolvers } = mergeDependencies(manifest, void 0);
|
|
119
119
|
const parent = new Dependency(manifest.name, manifest.version);
|
|
@@ -124,19 +124,23 @@ export async function* getRootDependencies(manifest, options) {
|
|
|
124
124
|
if (usePackageLock) {
|
|
125
125
|
const arb = new Arborist({
|
|
126
126
|
...NPM_TOKEN,
|
|
127
|
+
path: location,
|
|
127
128
|
registry: getLocalRegistryURL()
|
|
128
129
|
});
|
|
129
130
|
let tree;
|
|
130
131
|
try {
|
|
131
|
-
await fs.access(path.join(
|
|
132
|
+
await fs.access(path.join(location, "node_modules"));
|
|
132
133
|
tree = await arb.loadActual();
|
|
133
134
|
}
|
|
134
135
|
catch {
|
|
135
136
|
tree = await arb.loadVirtual();
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
iterators =
|
|
139
|
-
.
|
|
139
|
+
iterators = [
|
|
140
|
+
...iter.filter(tree.edgesOut.entries(), ([, { to }]) => to !== null && (!to.dev || to.isWorkspace))
|
|
141
|
+
.map(([packageName, { to }]) => [packageName, to.isWorkspace ? to.target : to])
|
|
142
|
+
.map(([packageName, to]) => deepReadEdges(packageName, { to, parent, fullLockMode, exclude }))
|
|
143
|
+
];
|
|
140
144
|
}
|
|
141
145
|
else {
|
|
142
146
|
const configRef = { exclude, maxDepth, parent };
|
|
@@ -176,6 +180,7 @@ export async function depWalker(manifest, options = {}, logger = new Logger()) {
|
|
|
176
180
|
usePackageLock = false,
|
|
177
181
|
fullLockMode = false,
|
|
178
182
|
maxDepth,
|
|
183
|
+
location,
|
|
179
184
|
vulnerabilityStrategy = vuln.strategies.NONE
|
|
180
185
|
} = options;
|
|
181
186
|
|
|
@@ -205,7 +210,7 @@ export async function depWalker(manifest, options = {}, logger = new Logger()) {
|
|
|
205
210
|
const tarballLocker = new Lock({ maxConcurrent: 5 });
|
|
206
211
|
tarballLocker.on("freeOne", () => logger.tick(ScannerLoggerEvents.analysis.tarball));
|
|
207
212
|
|
|
208
|
-
const rootDepsOptions = { maxDepth, exclude, usePackageLock, fullLockMode };
|
|
213
|
+
const rootDepsOptions = { maxDepth, exclude, usePackageLock, fullLockMode, location };
|
|
209
214
|
for await (const currentDep of getRootDependencies(manifest, rootDepsOptions)) {
|
|
210
215
|
const { name, version } = currentDep;
|
|
211
216
|
const current = currentDep.exportAsPlainObject(name === manifest.name ? 0 : void 0);
|
|
@@ -246,6 +251,7 @@ export async function depWalker(manifest, options = {}, logger = new Logger()) {
|
|
|
246
251
|
|
|
247
252
|
promisesToWait.push(scanDirOrArchive(name, version, {
|
|
248
253
|
ref: current.versions[version],
|
|
254
|
+
location,
|
|
249
255
|
tmpLocation: forceRootAnalysis && name === manifest.name ? null : tmpLocation,
|
|
250
256
|
locker: tarballLocker,
|
|
251
257
|
logger
|
package/src/tarball.js
CHANGED
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
// Import Node.js Dependencies
|
|
2
|
-
import path from "path";
|
|
3
|
-
import os from "os";
|
|
4
|
-
import timers from "timers/promises";
|
|
5
|
-
|
|
6
|
-
// Import Third-party Dependencies
|
|
7
|
-
import { runASTAnalysisOnFile } from "@nodesecure/js-x-ray";
|
|
8
|
-
import pacote from "pacote";
|
|
9
|
-
import ntlp from "@nodesecure/ntlp";
|
|
10
|
-
|
|
11
|
-
// Import Internal Dependencies
|
|
12
|
-
import {
|
|
13
|
-
getTarballComposition, isSensitiveFile, filterDependencyKind, analyzeDependencies, booleanToFlags,
|
|
14
|
-
NPM_TOKEN
|
|
15
|
-
} from "./utils/index.js";
|
|
16
|
-
import * as manifest from "./manifest.js";
|
|
17
|
-
import { getLocalRegistryURL } from "@nodesecure/npm-registry-sdk";
|
|
18
|
-
|
|
19
|
-
// CONSTANTS
|
|
20
|
-
const kNativeCodeExtensions = new Set([".gyp", ".c", ".cpp", ".node", ".so", ".h"]);
|
|
21
|
-
const kJsExtname = new Set([".js", ".mjs", ".cjs"]);
|
|
22
|
-
|
|
23
|
-
export async function scanJavascriptFile(dest, file, packageName) {
|
|
24
|
-
const result = await runASTAnalysisOnFile(path.join(dest, file), { packageName });
|
|
25
|
-
|
|
26
|
-
const warnings = result.warnings.map((curr) => Object.assign({}, curr, { file }));
|
|
27
|
-
if (!result.ok) {
|
|
28
|
-
return {
|
|
29
|
-
file,
|
|
30
|
-
warnings,
|
|
31
|
-
isMinified: false,
|
|
32
|
-
tryDependencies: [],
|
|
33
|
-
dependencies: [],
|
|
34
|
-
filesDependencies: []
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
const { packages, files } = filterDependencyKind(result.dependencies, path.dirname(file));
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
file,
|
|
41
|
-
warnings,
|
|
42
|
-
isMinified: result.isMinified,
|
|
43
|
-
tryDependencies: [...result.dependencies.getDependenciesInTryStatement()],
|
|
44
|
-
dependencies: packages,
|
|
45
|
-
filesDependencies: files
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function scanDirOrArchive(name, version, options) {
|
|
50
|
-
const { ref, tmpLocation, locker } = options;
|
|
51
|
-
|
|
52
|
-
const isNpmTarball = !(tmpLocation === null);
|
|
53
|
-
const dest = isNpmTarball ? path.join(tmpLocation, `${name}@${version}`) :
|
|
54
|
-
const free = await locker.acquireOne();
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
// If this is an NPM tarball then we extract it on the disk with pacote.
|
|
58
|
-
if (isNpmTarball) {
|
|
59
|
-
await pacote.extract(ref.flags.includes("isGit") ? ref.gitUrl : `${name}@${version}`, dest, {
|
|
60
|
-
...NPM_TOKEN,
|
|
61
|
-
registry: getLocalRegistryURL(),
|
|
62
|
-
cache: `${os.homedir()}/.npm`
|
|
63
|
-
});
|
|
64
|
-
await timers.setImmediate();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Read the package.json at the root of the directory or archive.
|
|
68
|
-
const { packageDeps, packageDevDeps, author, description, hasScript, hasNativeElements } = await manifest.readAnalyze(dest);
|
|
69
|
-
ref.author = author;
|
|
70
|
-
ref.description = description;
|
|
71
|
-
|
|
72
|
-
// Get the composition of the (extracted) directory
|
|
73
|
-
const { ext, files, size } = await getTarballComposition(dest);
|
|
74
|
-
ref.size = size;
|
|
75
|
-
ref.composition.extensions.push(...ext);
|
|
76
|
-
ref.composition.files.push(...files);
|
|
77
|
-
const hasBannedFile = files.some((path) => isSensitiveFile(path));
|
|
78
|
-
const hasNativeCode = hasNativeElements || files.some((file) => kNativeCodeExtensions.has(path.extname(file)));
|
|
79
|
-
|
|
80
|
-
// Search for minified and runtime dependencies
|
|
81
|
-
// Run a JS-X-Ray analysis on each JavaScript files of the project!
|
|
82
|
-
const fileAnalysisRaw = await Promise.allSettled(
|
|
83
|
-
files
|
|
84
|
-
.filter((name) => kJsExtname.has(path.extname(name)))
|
|
85
|
-
.map((file) => scanJavascriptFile(dest, file, name))
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
const fileAnalysisResults = fileAnalysisRaw
|
|
89
|
-
.filter((promiseSettledResult) => promiseSettledResult.status === "fulfilled")
|
|
90
|
-
.map((promiseSettledResult) => promiseSettledResult.value);
|
|
91
|
-
|
|
92
|
-
ref.warnings.push(...fileAnalysisResults.flatMap((row) => row.warnings));
|
|
93
|
-
|
|
94
|
-
const dependencies = [...new Set(fileAnalysisResults.flatMap((row) => row.dependencies))];
|
|
95
|
-
const filesDependencies = [...new Set(fileAnalysisResults.flatMap((row) => row.filesDependencies))];
|
|
96
|
-
const tryDependencies = new Set(fileAnalysisResults.flatMap((row) => row.tryDependencies));
|
|
97
|
-
const minifiedFiles = fileAnalysisResults.filter((row) => row.isMinified).flatMap((row) => row.file);
|
|
98
|
-
|
|
99
|
-
const {
|
|
100
|
-
nodeDependencies, thirdPartyDependencies, missingDependencies, unusedDependencies, flags
|
|
101
|
-
} = analyzeDependencies(dependencies, { packageDeps, packageDevDeps, tryDependencies });
|
|
102
|
-
|
|
103
|
-
ref.composition.required_thirdparty = thirdPartyDependencies;
|
|
104
|
-
ref.composition.unused.push(...unusedDependencies);
|
|
105
|
-
ref.composition.missing.push(...missingDependencies);
|
|
106
|
-
ref.composition.required_files = filesDependencies;
|
|
107
|
-
ref.composition.required_nodejs = nodeDependencies;
|
|
108
|
-
ref.composition.minified = minifiedFiles;
|
|
109
|
-
|
|
110
|
-
// License
|
|
111
|
-
await timers.setImmediate();
|
|
112
|
-
const licenses = await ntlp(dest);
|
|
113
|
-
const uniqueLicenseIds = Array.isArray(licenses.uniqueLicenseIds) ? licenses.uniqueLicenseIds : [];
|
|
114
|
-
ref.license = licenses;
|
|
115
|
-
ref.license.uniqueLicenseIds = uniqueLicenseIds;
|
|
116
|
-
|
|
117
|
-
ref.flags.push(...booleanToFlags({
|
|
118
|
-
...flags,
|
|
119
|
-
hasNoLicense: uniqueLicenseIds.length === 0,
|
|
120
|
-
hasMultipleLicenses: licenses.hasMultipleLicenses,
|
|
121
|
-
hasMinifiedCode: minifiedFiles.length > 0,
|
|
122
|
-
hasWarnings: ref.warnings.length > 0 && !ref.flags.includes("hasWarnings"),
|
|
123
|
-
hasBannedFile,
|
|
124
|
-
hasNativeCode,
|
|
125
|
-
hasScript
|
|
126
|
-
}));
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
// Ignore
|
|
130
|
-
}
|
|
131
|
-
finally {
|
|
132
|
-
free();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export async function scanPackage(dest, packageName) {
|
|
137
|
-
const { type = "script", name } = await manifest.read(dest);
|
|
138
|
-
|
|
139
|
-
await timers.setImmediate();
|
|
140
|
-
const { ext, files, size } = await getTarballComposition(dest);
|
|
141
|
-
ext.delete("");
|
|
142
|
-
|
|
143
|
-
// Search for runtime dependencies
|
|
144
|
-
const dependencies = Object.create(null);
|
|
145
|
-
const [minified, warnings] = [[], []];
|
|
146
|
-
|
|
147
|
-
const JSFiles = files.filter((name) => kJsExtname.has(path.extname(name)));
|
|
148
|
-
for (const file of JSFiles) {
|
|
149
|
-
const result = await runASTAnalysisOnFile(path.join(dest, file), {
|
|
150
|
-
packageName: packageName ?? name,
|
|
151
|
-
module: type === "module"
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
warnings.push(...result.warnings.map((curr) => Object.assign({}, curr, { file })));
|
|
155
|
-
if (!result.ok) {
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
dependencies[file] = result.dependencies.dependencies;
|
|
160
|
-
result.isMinified && minified.push(file);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
await timers.setImmediate();
|
|
164
|
-
const { uniqueLicenseIds, licenses } = await ntlp(dest);
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
files: { list: files, extensions: [...ext], minified },
|
|
168
|
-
directorySize: size,
|
|
169
|
-
uniqueLicenseIds,
|
|
170
|
-
licenses,
|
|
171
|
-
ast: { dependencies, warnings }
|
|
172
|
-
};
|
|
173
|
-
}
|
|
1
|
+
// Import Node.js Dependencies
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import timers from "timers/promises";
|
|
5
|
+
|
|
6
|
+
// Import Third-party Dependencies
|
|
7
|
+
import { runASTAnalysisOnFile } from "@nodesecure/js-x-ray";
|
|
8
|
+
import pacote from "pacote";
|
|
9
|
+
import ntlp from "@nodesecure/ntlp";
|
|
10
|
+
|
|
11
|
+
// Import Internal Dependencies
|
|
12
|
+
import {
|
|
13
|
+
getTarballComposition, isSensitiveFile, filterDependencyKind, analyzeDependencies, booleanToFlags,
|
|
14
|
+
NPM_TOKEN
|
|
15
|
+
} from "./utils/index.js";
|
|
16
|
+
import * as manifest from "./manifest.js";
|
|
17
|
+
import { getLocalRegistryURL } from "@nodesecure/npm-registry-sdk";
|
|
18
|
+
|
|
19
|
+
// CONSTANTS
|
|
20
|
+
const kNativeCodeExtensions = new Set([".gyp", ".c", ".cpp", ".node", ".so", ".h"]);
|
|
21
|
+
const kJsExtname = new Set([".js", ".mjs", ".cjs"]);
|
|
22
|
+
|
|
23
|
+
export async function scanJavascriptFile(dest, file, packageName) {
|
|
24
|
+
const result = await runASTAnalysisOnFile(path.join(dest, file), { packageName });
|
|
25
|
+
|
|
26
|
+
const warnings = result.warnings.map((curr) => Object.assign({}, curr, { file }));
|
|
27
|
+
if (!result.ok) {
|
|
28
|
+
return {
|
|
29
|
+
file,
|
|
30
|
+
warnings,
|
|
31
|
+
isMinified: false,
|
|
32
|
+
tryDependencies: [],
|
|
33
|
+
dependencies: [],
|
|
34
|
+
filesDependencies: []
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const { packages, files } = filterDependencyKind(result.dependencies, path.dirname(file));
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
file,
|
|
41
|
+
warnings,
|
|
42
|
+
isMinified: result.isMinified,
|
|
43
|
+
tryDependencies: [...result.dependencies.getDependenciesInTryStatement()],
|
|
44
|
+
dependencies: packages,
|
|
45
|
+
filesDependencies: files
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function scanDirOrArchive(name, version, options) {
|
|
50
|
+
const { ref, location = process.cwd(), tmpLocation, locker } = options;
|
|
51
|
+
|
|
52
|
+
const isNpmTarball = !(tmpLocation === null);
|
|
53
|
+
const dest = isNpmTarball ? path.join(tmpLocation, `${name}@${version}`) : location;
|
|
54
|
+
const free = await locker.acquireOne();
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
// If this is an NPM tarball then we extract it on the disk with pacote.
|
|
58
|
+
if (isNpmTarball) {
|
|
59
|
+
await pacote.extract(ref.flags.includes("isGit") ? ref.gitUrl : `${name}@${version}`, dest, {
|
|
60
|
+
...NPM_TOKEN,
|
|
61
|
+
registry: getLocalRegistryURL(),
|
|
62
|
+
cache: `${os.homedir()}/.npm`
|
|
63
|
+
});
|
|
64
|
+
await timers.setImmediate();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Read the package.json at the root of the directory or archive.
|
|
68
|
+
const { packageDeps, packageDevDeps, author, description, hasScript, hasNativeElements } = await manifest.readAnalyze(dest);
|
|
69
|
+
ref.author = author;
|
|
70
|
+
ref.description = description;
|
|
71
|
+
|
|
72
|
+
// Get the composition of the (extracted) directory
|
|
73
|
+
const { ext, files, size } = await getTarballComposition(dest);
|
|
74
|
+
ref.size = size;
|
|
75
|
+
ref.composition.extensions.push(...ext);
|
|
76
|
+
ref.composition.files.push(...files);
|
|
77
|
+
const hasBannedFile = files.some((path) => isSensitiveFile(path));
|
|
78
|
+
const hasNativeCode = hasNativeElements || files.some((file) => kNativeCodeExtensions.has(path.extname(file)));
|
|
79
|
+
|
|
80
|
+
// Search for minified and runtime dependencies
|
|
81
|
+
// Run a JS-X-Ray analysis on each JavaScript files of the project!
|
|
82
|
+
const fileAnalysisRaw = await Promise.allSettled(
|
|
83
|
+
files
|
|
84
|
+
.filter((name) => kJsExtname.has(path.extname(name)))
|
|
85
|
+
.map((file) => scanJavascriptFile(dest, file, name))
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const fileAnalysisResults = fileAnalysisRaw
|
|
89
|
+
.filter((promiseSettledResult) => promiseSettledResult.status === "fulfilled")
|
|
90
|
+
.map((promiseSettledResult) => promiseSettledResult.value);
|
|
91
|
+
|
|
92
|
+
ref.warnings.push(...fileAnalysisResults.flatMap((row) => row.warnings));
|
|
93
|
+
|
|
94
|
+
const dependencies = [...new Set(fileAnalysisResults.flatMap((row) => row.dependencies))];
|
|
95
|
+
const filesDependencies = [...new Set(fileAnalysisResults.flatMap((row) => row.filesDependencies))];
|
|
96
|
+
const tryDependencies = new Set(fileAnalysisResults.flatMap((row) => row.tryDependencies));
|
|
97
|
+
const minifiedFiles = fileAnalysisResults.filter((row) => row.isMinified).flatMap((row) => row.file);
|
|
98
|
+
|
|
99
|
+
const {
|
|
100
|
+
nodeDependencies, thirdPartyDependencies, missingDependencies, unusedDependencies, flags
|
|
101
|
+
} = analyzeDependencies(dependencies, { packageDeps, packageDevDeps, tryDependencies });
|
|
102
|
+
|
|
103
|
+
ref.composition.required_thirdparty = thirdPartyDependencies;
|
|
104
|
+
ref.composition.unused.push(...unusedDependencies);
|
|
105
|
+
ref.composition.missing.push(...missingDependencies);
|
|
106
|
+
ref.composition.required_files = filesDependencies;
|
|
107
|
+
ref.composition.required_nodejs = nodeDependencies;
|
|
108
|
+
ref.composition.minified = minifiedFiles;
|
|
109
|
+
|
|
110
|
+
// License
|
|
111
|
+
await timers.setImmediate();
|
|
112
|
+
const licenses = await ntlp(dest);
|
|
113
|
+
const uniqueLicenseIds = Array.isArray(licenses.uniqueLicenseIds) ? licenses.uniqueLicenseIds : [];
|
|
114
|
+
ref.license = licenses;
|
|
115
|
+
ref.license.uniqueLicenseIds = uniqueLicenseIds;
|
|
116
|
+
|
|
117
|
+
ref.flags.push(...booleanToFlags({
|
|
118
|
+
...flags,
|
|
119
|
+
hasNoLicense: uniqueLicenseIds.length === 0,
|
|
120
|
+
hasMultipleLicenses: licenses.hasMultipleLicenses,
|
|
121
|
+
hasMinifiedCode: minifiedFiles.length > 0,
|
|
122
|
+
hasWarnings: ref.warnings.length > 0 && !ref.flags.includes("hasWarnings"),
|
|
123
|
+
hasBannedFile,
|
|
124
|
+
hasNativeCode,
|
|
125
|
+
hasScript
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Ignore
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
free();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function scanPackage(dest, packageName) {
|
|
137
|
+
const { type = "script", name } = await manifest.read(dest);
|
|
138
|
+
|
|
139
|
+
await timers.setImmediate();
|
|
140
|
+
const { ext, files, size } = await getTarballComposition(dest);
|
|
141
|
+
ext.delete("");
|
|
142
|
+
|
|
143
|
+
// Search for runtime dependencies
|
|
144
|
+
const dependencies = Object.create(null);
|
|
145
|
+
const [minified, warnings] = [[], []];
|
|
146
|
+
|
|
147
|
+
const JSFiles = files.filter((name) => kJsExtname.has(path.extname(name)));
|
|
148
|
+
for (const file of JSFiles) {
|
|
149
|
+
const result = await runASTAnalysisOnFile(path.join(dest, file), {
|
|
150
|
+
packageName: packageName ?? name,
|
|
151
|
+
module: type === "module"
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
warnings.push(...result.warnings.map((curr) => Object.assign({}, curr, { file })));
|
|
155
|
+
if (!result.ok) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
dependencies[file] = result.dependencies.dependencies;
|
|
160
|
+
result.isMinified && minified.push(file);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
await timers.setImmediate();
|
|
164
|
+
const { uniqueLicenseIds, licenses } = await ntlp(dest);
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
files: { list: files, extensions: [...ext], minified },
|
|
168
|
+
directorySize: size,
|
|
169
|
+
uniqueLicenseIds,
|
|
170
|
+
licenses,
|
|
171
|
+
ast: { dependencies, warnings }
|
|
172
|
+
};
|
|
173
|
+
}
|
package/types/api.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import Scanner from "./scanner";
|
|
2
|
-
import { Logger, LoggerEvents } from "./logger";
|
|
3
|
-
|
|
4
|
-
export {
|
|
5
|
-
cwd,
|
|
6
|
-
from,
|
|
7
|
-
verify,
|
|
8
|
-
ScannerLoggerEvents
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
declare const ScannerLoggerEvents: LoggerEvents;
|
|
12
|
-
|
|
13
|
-
declare function cwd(
|
|
14
|
-
declare function from(packageName: string, options?: Scanner.Options, logger?: Logger): Promise<Scanner.Payload>;
|
|
15
|
-
declare function verify(packageName
|
|
1
|
+
import Scanner from "./scanner";
|
|
2
|
+
import { Logger, LoggerEvents } from "./logger";
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
cwd,
|
|
6
|
+
from,
|
|
7
|
+
verify,
|
|
8
|
+
ScannerLoggerEvents
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare const ScannerLoggerEvents: LoggerEvents;
|
|
12
|
+
|
|
13
|
+
declare function cwd(location: string, options?: Scanner.Options, logger?: Logger): Promise<Scanner.Payload>;
|
|
14
|
+
declare function from(packageName: string, options?: Scanner.Options, logger?: Logger): Promise<Scanner.Payload>;
|
|
15
|
+
declare function verify(packageName?: string | null): Promise<Scanner.VerifyPayload>;
|
package/types/scanner.d.ts
CHANGED
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
// Import NodeSecure Dependencies
|
|
2
|
-
import * as JSXRay from "@nodesecure/js-x-ray";
|
|
3
|
-
import { license as License } from "@nodesecure/ntlp";
|
|
4
|
-
import * as Vuln from "@nodesecure/vuln";
|
|
5
|
-
import { Flags } from "@nodesecure/flags";
|
|
6
|
-
|
|
7
|
-
// Import Third-party Dependencies
|
|
8
|
-
import { Maintainer } from "@npm/types";
|
|
9
|
-
|
|
10
|
-
export = Scanner;
|
|
11
|
-
|
|
12
|
-
declare namespace Scanner {
|
|
13
|
-
export interface Publisher {
|
|
14
|
-
/**
|
|
15
|
-
* Publisher npm user name.
|
|
16
|
-
*/
|
|
17
|
-
name: string;
|
|
18
|
-
/**
|
|
19
|
-
* Publisher npm user email.
|
|
20
|
-
*/
|
|
21
|
-
email: string;
|
|
22
|
-
/**
|
|
23
|
-
* First version published.
|
|
24
|
-
*/
|
|
25
|
-
version: string;
|
|
26
|
-
/**
|
|
27
|
-
* Date of the first publication
|
|
28
|
-
* @example 2021-08-10T20:45:08.342Z
|
|
29
|
-
*/
|
|
30
|
-
at: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface DependencyVersion {
|
|
34
|
-
/** Id of the package (useful for usedBy relation) */
|
|
35
|
-
id: number;
|
|
36
|
-
/** By whom (id) is used the package */
|
|
37
|
-
usedBy: Record<string, string>;
|
|
38
|
-
/** Size on disk of the extracted tarball (in bytes) */
|
|
39
|
-
size: number;
|
|
40
|
-
/** Package description */
|
|
41
|
-
description: string;
|
|
42
|
-
/** Author of the package. This information is not trustable and can be empty. */
|
|
43
|
-
author: Maintainer;
|
|
44
|
-
/**
|
|
45
|
-
* JS-X-Ray warnings
|
|
46
|
-
*
|
|
47
|
-
* @see https://github.com/NodeSecure/js-x-ray/blob/master/WARNINGS.md
|
|
48
|
-
*/
|
|
49
|
-
warnings: JSXRay.Warning<JSXRay.BaseWarning>[];
|
|
50
|
-
/** Tarball composition (files and dependencies) */
|
|
51
|
-
composition: {
|
|
52
|
-
/** Files extensions (.js, .md, .exe etc..) */
|
|
53
|
-
extensions: string[];
|
|
54
|
-
files: string[];
|
|
55
|
-
/** Minified files (foo.min.js etc..) */
|
|
56
|
-
minified: string[];
|
|
57
|
-
required_files: string[];
|
|
58
|
-
required_thirdparty: string[];
|
|
59
|
-
required_nodejs: string[];
|
|
60
|
-
unused: string[];
|
|
61
|
-
missing: string[];
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Package licenses with SPDX expression.
|
|
65
|
-
*
|
|
66
|
-
* @see https://github.com/NodeSecure/licenses-conformance
|
|
67
|
-
* @see https://github.com/NodeSecure/npm-tarball-license-parser
|
|
68
|
-
*/
|
|
69
|
-
license: License[];
|
|
70
|
-
/**
|
|
71
|
-
* Flags (Array of string)
|
|
72
|
-
*
|
|
73
|
-
* @see https://github.com/NodeSecure/flags/blob/main/FLAGS.md
|
|
74
|
-
*/
|
|
75
|
-
flags: Flags[];
|
|
76
|
-
/**
|
|
77
|
-
* If the dependency is a GIT repository
|
|
78
|
-
*/
|
|
79
|
-
gitUrl: null | string;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export interface Dependency {
|
|
83
|
-
/** NPM Registry metadata */
|
|
84
|
-
metadata: {
|
|
85
|
-
/** Count of dependencies */
|
|
86
|
-
dependencyCount: number;
|
|
87
|
-
/** Number of releases published on npm */
|
|
88
|
-
publishedCount: number;
|
|
89
|
-
lastUpdateAt: number;
|
|
90
|
-
/** Last version SemVer */
|
|
91
|
-
lastVersion: number;
|
|
92
|
-
hasChangedAuthor: boolean;
|
|
93
|
-
hasManyPublishers: boolean;
|
|
94
|
-
hasReceivedUpdateInOneYear: boolean;
|
|
95
|
-
/** Author of the package. This information is not trustable and can be empty. */
|
|
96
|
-
author: Maintainer;
|
|
97
|
-
/** Package home page */
|
|
98
|
-
homepage: string | null;
|
|
99
|
-
/**
|
|
100
|
-
* List of maintainers (list of people in the organization related to the package)
|
|
101
|
-
*/
|
|
102
|
-
maintainers: { name: string, email: string }[];
|
|
103
|
-
/**
|
|
104
|
-
* List of people who published this package
|
|
105
|
-
*/
|
|
106
|
-
publishers: Publisher[];
|
|
107
|
-
}
|
|
108
|
-
/** List of versions of this package available in the dependency tree (In the payload) */
|
|
109
|
-
versions: Record<string, DependencyVersion>;
|
|
110
|
-
/**
|
|
111
|
-
* Vulnerabilities fetched dependending on the selected vulnerabilityStrategy
|
|
112
|
-
*
|
|
113
|
-
* @see https://github.com/NodeSecure/vuln
|
|
114
|
-
*/
|
|
115
|
-
vulnerabilities: Vuln.Strategy.StandardVulnerability[];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export type GlobalWarning = string[];
|
|
119
|
-
export type Dependencies = Record<string, Dependency>;
|
|
120
|
-
|
|
121
|
-
export interface Payload {
|
|
122
|
-
/** Payload unique id */
|
|
123
|
-
id: string;
|
|
124
|
-
/** Name of the analyzed package */
|
|
125
|
-
rootDependencyName: string;
|
|
126
|
-
/** Global warnings list */
|
|
127
|
-
warnings: GlobalWarning[];
|
|
128
|
-
/** All the dependencies of the package (flattened) */
|
|
129
|
-
dependencies: Dependencies;
|
|
130
|
-
/** Version of the scanner used to generate the result */
|
|
131
|
-
scannerVersion: string;
|
|
132
|
-
/** Vulnerability strategy name (npm, snyk, node) */
|
|
133
|
-
vulnerabilityStrategy: Vuln.Strategy.Kind;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface VerifyPayload {
|
|
137
|
-
files: {
|
|
138
|
-
list: string[];
|
|
139
|
-
extensions: string[];
|
|
140
|
-
minified: string[];
|
|
141
|
-
};
|
|
142
|
-
directorySize: number;
|
|
143
|
-
uniqueLicenseIds: string[];
|
|
144
|
-
licenses: License[];
|
|
145
|
-
ast: {
|
|
146
|
-
dependencies: Record<string, JSXRay.Dependency>;
|
|
147
|
-
warnings: JSXRay.Warning<JSXRay.BaseWarning>[];
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface Options {
|
|
152
|
-
/**
|
|
153
|
-
* Maximum tree depth
|
|
154
|
-
*
|
|
155
|
-
* @default 4
|
|
156
|
-
*/
|
|
157
|
-
readonly maxDepth?: number;
|
|
158
|
-
/**
|
|
159
|
-
* Use root package-lock.json. This will have the effect of triggering the Arborist package.
|
|
160
|
-
*
|
|
161
|
-
* @default false for from() API
|
|
162
|
-
* @default true for cwd() API
|
|
163
|
-
*/
|
|
164
|
-
readonly usePackageLock?: boolean;
|
|
165
|
-
/**
|
|
166
|
-
* Vulnerability strategy name (npm, snyk, node)
|
|
167
|
-
*
|
|
168
|
-
* @default NONE
|
|
169
|
-
*/
|
|
170
|
-
readonly vulnerabilityStrategy: Vuln.Strategy.Kind;
|
|
171
|
-
/**
|
|
172
|
-
* Analyze root package.
|
|
173
|
-
*
|
|
174
|
-
* @default false for from() API
|
|
175
|
-
* @default true for cwd() API
|
|
176
|
-
*/
|
|
177
|
-
readonly forceRootAnalysis?: boolean;
|
|
178
|
-
/**
|
|
179
|
-
* Deeper dependencies analysis with cwd() API.
|
|
180
|
-
*
|
|
181
|
-
* @default false
|
|
182
|
-
*/
|
|
183
|
-
readonly fullLockMode?: boolean;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
1
|
+
// Import NodeSecure Dependencies
|
|
2
|
+
import * as JSXRay from "@nodesecure/js-x-ray";
|
|
3
|
+
import { license as License } from "@nodesecure/ntlp";
|
|
4
|
+
import * as Vuln from "@nodesecure/vuln";
|
|
5
|
+
import { Flags } from "@nodesecure/flags";
|
|
6
|
+
|
|
7
|
+
// Import Third-party Dependencies
|
|
8
|
+
import { Maintainer } from "@npm/types";
|
|
9
|
+
|
|
10
|
+
export = Scanner;
|
|
11
|
+
|
|
12
|
+
declare namespace Scanner {
|
|
13
|
+
export interface Publisher {
|
|
14
|
+
/**
|
|
15
|
+
* Publisher npm user name.
|
|
16
|
+
*/
|
|
17
|
+
name: string;
|
|
18
|
+
/**
|
|
19
|
+
* Publisher npm user email.
|
|
20
|
+
*/
|
|
21
|
+
email: string;
|
|
22
|
+
/**
|
|
23
|
+
* First version published.
|
|
24
|
+
*/
|
|
25
|
+
version: string;
|
|
26
|
+
/**
|
|
27
|
+
* Date of the first publication
|
|
28
|
+
* @example 2021-08-10T20:45:08.342Z
|
|
29
|
+
*/
|
|
30
|
+
at: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface DependencyVersion {
|
|
34
|
+
/** Id of the package (useful for usedBy relation) */
|
|
35
|
+
id: number;
|
|
36
|
+
/** By whom (id) is used the package */
|
|
37
|
+
usedBy: Record<string, string>;
|
|
38
|
+
/** Size on disk of the extracted tarball (in bytes) */
|
|
39
|
+
size: number;
|
|
40
|
+
/** Package description */
|
|
41
|
+
description: string;
|
|
42
|
+
/** Author of the package. This information is not trustable and can be empty. */
|
|
43
|
+
author: Maintainer;
|
|
44
|
+
/**
|
|
45
|
+
* JS-X-Ray warnings
|
|
46
|
+
*
|
|
47
|
+
* @see https://github.com/NodeSecure/js-x-ray/blob/master/WARNINGS.md
|
|
48
|
+
*/
|
|
49
|
+
warnings: JSXRay.Warning<JSXRay.BaseWarning>[];
|
|
50
|
+
/** Tarball composition (files and dependencies) */
|
|
51
|
+
composition: {
|
|
52
|
+
/** Files extensions (.js, .md, .exe etc..) */
|
|
53
|
+
extensions: string[];
|
|
54
|
+
files: string[];
|
|
55
|
+
/** Minified files (foo.min.js etc..) */
|
|
56
|
+
minified: string[];
|
|
57
|
+
required_files: string[];
|
|
58
|
+
required_thirdparty: string[];
|
|
59
|
+
required_nodejs: string[];
|
|
60
|
+
unused: string[];
|
|
61
|
+
missing: string[];
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Package licenses with SPDX expression.
|
|
65
|
+
*
|
|
66
|
+
* @see https://github.com/NodeSecure/licenses-conformance
|
|
67
|
+
* @see https://github.com/NodeSecure/npm-tarball-license-parser
|
|
68
|
+
*/
|
|
69
|
+
license: License[];
|
|
70
|
+
/**
|
|
71
|
+
* Flags (Array of string)
|
|
72
|
+
*
|
|
73
|
+
* @see https://github.com/NodeSecure/flags/blob/main/FLAGS.md
|
|
74
|
+
*/
|
|
75
|
+
flags: Flags[];
|
|
76
|
+
/**
|
|
77
|
+
* If the dependency is a GIT repository
|
|
78
|
+
*/
|
|
79
|
+
gitUrl: null | string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface Dependency {
|
|
83
|
+
/** NPM Registry metadata */
|
|
84
|
+
metadata: {
|
|
85
|
+
/** Count of dependencies */
|
|
86
|
+
dependencyCount: number;
|
|
87
|
+
/** Number of releases published on npm */
|
|
88
|
+
publishedCount: number;
|
|
89
|
+
lastUpdateAt: number;
|
|
90
|
+
/** Last version SemVer */
|
|
91
|
+
lastVersion: number;
|
|
92
|
+
hasChangedAuthor: boolean;
|
|
93
|
+
hasManyPublishers: boolean;
|
|
94
|
+
hasReceivedUpdateInOneYear: boolean;
|
|
95
|
+
/** Author of the package. This information is not trustable and can be empty. */
|
|
96
|
+
author: Maintainer;
|
|
97
|
+
/** Package home page */
|
|
98
|
+
homepage: string | null;
|
|
99
|
+
/**
|
|
100
|
+
* List of maintainers (list of people in the organization related to the package)
|
|
101
|
+
*/
|
|
102
|
+
maintainers: { name: string, email: string }[];
|
|
103
|
+
/**
|
|
104
|
+
* List of people who published this package
|
|
105
|
+
*/
|
|
106
|
+
publishers: Publisher[];
|
|
107
|
+
}
|
|
108
|
+
/** List of versions of this package available in the dependency tree (In the payload) */
|
|
109
|
+
versions: Record<string, DependencyVersion>;
|
|
110
|
+
/**
|
|
111
|
+
* Vulnerabilities fetched dependending on the selected vulnerabilityStrategy
|
|
112
|
+
*
|
|
113
|
+
* @see https://github.com/NodeSecure/vuln
|
|
114
|
+
*/
|
|
115
|
+
vulnerabilities: Vuln.Strategy.StandardVulnerability[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type GlobalWarning = string[];
|
|
119
|
+
export type Dependencies = Record<string, Dependency>;
|
|
120
|
+
|
|
121
|
+
export interface Payload {
|
|
122
|
+
/** Payload unique id */
|
|
123
|
+
id: string;
|
|
124
|
+
/** Name of the analyzed package */
|
|
125
|
+
rootDependencyName: string;
|
|
126
|
+
/** Global warnings list */
|
|
127
|
+
warnings: GlobalWarning[];
|
|
128
|
+
/** All the dependencies of the package (flattened) */
|
|
129
|
+
dependencies: Dependencies;
|
|
130
|
+
/** Version of the scanner used to generate the result */
|
|
131
|
+
scannerVersion: string;
|
|
132
|
+
/** Vulnerability strategy name (npm, snyk, node) */
|
|
133
|
+
vulnerabilityStrategy: Vuln.Strategy.Kind;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface VerifyPayload {
|
|
137
|
+
files: {
|
|
138
|
+
list: string[];
|
|
139
|
+
extensions: string[];
|
|
140
|
+
minified: string[];
|
|
141
|
+
};
|
|
142
|
+
directorySize: number;
|
|
143
|
+
uniqueLicenseIds: string[];
|
|
144
|
+
licenses: License[];
|
|
145
|
+
ast: {
|
|
146
|
+
dependencies: Record<string, JSXRay.Dependency>;
|
|
147
|
+
warnings: JSXRay.Warning<JSXRay.BaseWarning>[];
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface Options {
|
|
152
|
+
/**
|
|
153
|
+
* Maximum tree depth
|
|
154
|
+
*
|
|
155
|
+
* @default 4
|
|
156
|
+
*/
|
|
157
|
+
readonly maxDepth?: number;
|
|
158
|
+
/**
|
|
159
|
+
* Use root package-lock.json. This will have the effect of triggering the Arborist package.
|
|
160
|
+
*
|
|
161
|
+
* @default false for from() API
|
|
162
|
+
* @default true for cwd() API
|
|
163
|
+
*/
|
|
164
|
+
readonly usePackageLock?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Vulnerability strategy name (npm, snyk, node)
|
|
167
|
+
*
|
|
168
|
+
* @default NONE
|
|
169
|
+
*/
|
|
170
|
+
readonly vulnerabilityStrategy: Vuln.Strategy.Kind;
|
|
171
|
+
/**
|
|
172
|
+
* Analyze root package.
|
|
173
|
+
*
|
|
174
|
+
* @default false for from() API
|
|
175
|
+
* @default true for cwd() API
|
|
176
|
+
*/
|
|
177
|
+
readonly forceRootAnalysis?: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Deeper dependencies analysis with cwd() API.
|
|
180
|
+
*
|
|
181
|
+
* @default false
|
|
182
|
+
*/
|
|
183
|
+
readonly fullLockMode?: boolean;
|
|
184
|
+
}
|
|
185
|
+
}
|