scanoss 0.2.26 → 0.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/.github/workflows/reuse.yml +15 -0
- package/.github/workflows/scanoss.yml +24 -0
- package/.gitignore +0 -1
- package/.idea/.gitignore +5 -0
- package/.idea/codeStyles/Project.xml +61 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/scanoss.js.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +366 -0
- package/.nyc_output/a25d3ac4-ee71-4c5e-926e-3a17714555cd.json +1 -0
- package/.nyc_output/processinfo/a25d3ac4-ee71-4c5e-926e-3a17714555cd.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/.reuse/dep5 +16 -0
- package/LICENSES/CC0-1.0.txt +121 -0
- package/LICENSES/MIT.txt +9 -0
- package/README.md +9 -0
- package/build/main/bin/cli-bin.js +5 -3
- package/build/main/commands/dep.js +1 -2
- package/build/main/commands/fingerprint.js +20 -12
- package/build/main/commands/helpers.js +1 -2
- package/build/main/commands/scan.js +7 -2
- package/build/main/index.js +1 -2
- package/build/main/lib/dependencies/DependencyScanner.d.ts +1 -1
- package/build/main/lib/dependencies/DependencyScanner.js +23 -12
- package/build/main/lib/dependencies/DependencyScannerCfg.js +1 -2
- package/build/main/lib/dependencies/DependencyTypes.js +0 -1
- package/build/main/lib/dependencies/LocalDependency/DependencyTypes.js +0 -1
- package/build/main/lib/dependencies/LocalDependency/LocalDependency.js +3 -2
- package/build/main/lib/dependencies/LocalDependency/parsers/golangParser.d.ts +1 -0
- package/build/main/lib/dependencies/LocalDependency/parsers/golangParser.js +50 -16
- package/build/main/lib/dependencies/LocalDependency/parsers/mavenParser.js +130 -15
- package/build/main/lib/dependencies/LocalDependency/parsers/npmParser.d.ts +10 -0
- package/build/main/lib/dependencies/LocalDependency/parsers/npmParser.js +146 -10
- package/build/main/lib/dependencies/LocalDependency/parsers/pyParser.js +1 -2
- package/build/main/lib/dependencies/LocalDependency/parsers/rubyParser.js +1 -2
- package/build/main/lib/dependencies/LocalDependency/parsers/utils.js +1 -2
- package/build/main/lib/filters/defaultFilter.js +1 -2
- package/build/main/lib/filters/filtering.js +1 -2
- package/build/main/lib/grpc/GrpcDependencyService.js +1 -2
- package/build/main/lib/grpc/scanoss/api/components/v2/scanoss-components_grpc_pb.d.ts +62 -0
- package/build/main/lib/grpc/scanoss/api/components/v2/scanoss-components_grpc_pb.js +128 -0
- package/build/main/lib/grpc/scanoss/api/components/v2/scanoss-components_pb.d.ts +1 -0
- package/build/main/lib/grpc/scanoss/api/components/v2/scanoss-components_pb.js +1403 -0
- package/build/main/lib/scanner/Dispatcher/DispatchableItem.d.ts +14 -5
- package/build/main/lib/scanner/Dispatcher/DispatchableItem.js +30 -10
- package/build/main/lib/scanner/Dispatcher/Dispatcher.d.ts +2 -2
- package/build/main/lib/scanner/Dispatcher/Dispatcher.js +10 -15
- package/build/main/lib/scanner/Dispatcher/DispatcherResponse.js +1 -2
- package/build/main/lib/scanner/Dispatcher/GlobalControllerAborter.js +1 -2
- package/build/main/lib/scanner/Scannable/ScannableItem.js +1 -2
- package/build/main/lib/scanner/Scanner.js +13 -9
- package/build/main/lib/scanner/ScannerCfg.js +2 -3
- package/build/main/lib/scanner/ScannerQueue.d.ts +3 -0
- package/build/main/lib/scanner/ScannerQueue.js +8 -0
- package/build/main/lib/scanner/ScannerTypes.d.ts +9 -2
- package/build/main/lib/scanner/ScannerTypes.js +8 -3
- package/build/main/lib/scanner/WfpProvider/FingerprintPackage.d.ts +9 -0
- package/build/main/lib/scanner/WfpProvider/FingerprintPackage.js +31 -0
- package/build/main/lib/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +178 -21
- package/build/main/lib/scanner/WfpProvider/WfpCalculator/Winnower.d.ts +3 -0
- package/build/main/lib/scanner/WfpProvider/WfpCalculator/Winnower.js +211 -0
- package/build/main/lib/scanner/WfpProvider/WfpProvider.d.ts +2 -2
- package/build/main/lib/scanner/WfpProvider/WfpProvider.js +6 -7
- package/build/main/lib/scanner/WfpProvider/WfpSplitter/WfpSplitter.js +1 -2
- package/build/main/lib/tree/File.js +1 -2
- package/build/main/lib/tree/Folder.js +1 -2
- package/build/main/lib/tree/Node.js +1 -2
- package/build/main/lib/tree/Tree.js +1 -2
- package/build/module/bin/cli-bin.js +5 -2
- package/build/module/commands/fingerprint.js +25 -16
- package/build/module/commands/scan.js +8 -2
- package/build/module/lib/dependencies/DependencyScanner.d.ts +1 -1
- package/build/module/lib/dependencies/DependencyScanner.js +23 -11
- package/build/module/lib/dependencies/LocalDependency/LocalDependency.js +5 -3
- package/build/module/lib/dependencies/LocalDependency/parsers/golangParser.d.ts +1 -0
- package/build/module/lib/dependencies/LocalDependency/parsers/golangParser.js +47 -14
- package/build/module/lib/dependencies/LocalDependency/parsers/mavenParser.js +130 -14
- package/build/module/lib/dependencies/LocalDependency/parsers/npmParser.d.ts +10 -0
- package/build/module/lib/dependencies/LocalDependency/parsers/npmParser.js +140 -8
- package/build/module/lib/grpc/scanoss/api/components/v2/scanoss-components_grpc_pb.d.ts +62 -0
- package/build/module/lib/grpc/scanoss/api/components/v2/scanoss-components_grpc_pb.js +128 -0
- package/build/module/lib/grpc/scanoss/api/components/v2/scanoss-components_pb.d.ts +1 -0
- package/build/module/lib/grpc/scanoss/api/components/v2/scanoss-components_pb.js +1403 -0
- package/build/module/lib/scanner/Dispatcher/DispatchableItem.d.ts +14 -5
- package/build/module/lib/scanner/Dispatcher/DispatchableItem.js +32 -10
- package/build/module/lib/scanner/Dispatcher/Dispatcher.d.ts +2 -2
- package/build/module/lib/scanner/Dispatcher/Dispatcher.js +10 -14
- package/build/module/lib/scanner/Scanner.js +12 -8
- package/build/module/lib/scanner/ScannerCfg.js +2 -2
- package/build/module/lib/scanner/ScannerQueue.d.ts +3 -0
- package/build/module/lib/scanner/ScannerQueue.js +4 -0
- package/build/module/lib/scanner/ScannerTypes.d.ts +9 -2
- package/build/module/lib/scanner/ScannerTypes.js +7 -1
- package/build/module/lib/scanner/WfpProvider/FingerprintPackage.d.ts +9 -0
- package/build/module/lib/scanner/WfpProvider/FingerprintPackage.js +30 -0
- package/build/module/lib/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +178 -20
- package/build/module/lib/scanner/WfpProvider/WfpCalculator/Winnower.d.ts +3 -0
- package/build/module/lib/scanner/WfpProvider/WfpCalculator/Winnower.js +211 -0
- package/build/module/lib/scanner/WfpProvider/WfpProvider.d.ts +2 -2
- package/build/module/lib/scanner/WfpProvider/WfpProvider.js +6 -6
- package/build/tsconfig.module.tsbuildinfo +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -17
- package/src/bin/cli-bin.ts +4 -1
- package/src/commands/fingerprint.ts +26 -17
- package/src/commands/scan.ts +16 -3
- package/src/lib/dependencies/DependencyScanner.ts +20 -13
- package/src/lib/dependencies/LocalDependency/LocalDependency.ts +8 -2
- package/src/lib/dependencies/LocalDependency/parsers/golangParser.ts +67 -15
- package/src/lib/dependencies/LocalDependency/parsers/mavenParser.ts +143 -16
- package/src/lib/dependencies/LocalDependency/parsers/npmParser.ts +182 -7
- package/src/lib/scanner/Dispatcher/DispatchableItem.ts +45 -11
- package/src/lib/scanner/Dispatcher/Dispatcher.ts +11 -14
- package/src/lib/scanner/Scanner.ts +17 -13
- package/src/lib/scanner/ScannerCfg.ts +2 -1
- package/src/lib/scanner/ScannerTypes.ts +10 -2
- package/src/lib/scanner/WfpProvider/{FingerprintPacket.ts → FingerprintPackage.ts} +4 -14
- package/src/lib/scanner/WfpProvider/WfpCalculator/WfpCalculator.ts +177 -20
- package/src/lib/scanner/WfpProvider/WfpProvider.ts +5 -5
- package/tests/WfpCalculator.spec.ts +103 -0
- package/tests/data/dependencies/Gemfile/1/Gemfile +6 -0
- package/tests/data/dependencies/Gemfile/1/Gemfile~ +0 -0
- package/tests/data/dependencies/Gemfile/2/Gemfile +3 -0
- package/tests/data/dependencies/Gemfile/2/Gemfile~ +6 -0
- package/tests/data/dependencies/Gemfile/3/Gemfile +7 -0
- package/tests/data/dependencies/Gemfile/3/Gemfile~ +6 -0
- package/tests/data/dependencies/Gemfile/4/Gemfile +31 -0
- package/tests/data/dependencies/Gemfile/4/Gemfile~ +7 -0
- package/tests/data/dependencies/Gemfile.lock/1/Gemfile.lock +180 -0
- package/tests/data/dependencies/Gemfile.lock/2/Gemfile.lock +60 -0
- package/tests/data/dependencies/Gemfile.lock/2/Gemfile.lock~ +0 -0
- package/tests/data/dependencies/go.sum/1/go.sum +119 -0
- package/tests/data/dependencies/go.sum/depJSON.sh +23 -0
- package/tests/data/dependencies/package-lock/1/package-lock.json +715 -0
- package/tests/data/dependencies/package-lock/2/package-lock.json +32069 -0
- package/tests/data/dependencies/package-lock/3/package-lock.json +9013 -0
- package/tests/data/dependencies/pom.xml/1/pom.xml +162 -0
- package/tests/data/dependencies/yarn-lock/generate_expected_output.sh +4 -0
- package/tests/data/dependencies/yarn-lock/v1/yarn.lock +50 -0
- package/tests/data/dependencies/yarn-lock/v1/yarn.lock-expected +13 -0
- package/tests/data/dependencies/yarn-lock/v1-complex/yarn.lock +27 -0
- package/tests/data/dependencies/yarn-lock/v1-complex/yarn.lock-expected +8 -0
- package/tests/data/dependencies/yarn-lock/v1-complex2/yarn.lock +220 -0
- package/tests/data/dependencies/yarn-lock/v2/yarn.lock +31 -0
- package/tests/data/dependencies/yarn-lock/v2/yarn.lock-expected +57 -0
- package/tests/data/dependencies/yarn-lock/v2-local/yarn.lock +11 -0
- package/tests/data/dependencies/yarn-lock/v2-local/yarn.lock-expected +27204 -0
- package/tests/data/scanner/file1.c +41 -0
- package/tests/data/scanner/file2.go +87 -0
- package/tests/dependencies/golangParser.goModParser.specs.ts +146 -0
- package/tests/dependencies/npmParser.spec.ts +133 -0
- package/tsconfig.json +4 -3
- package/yarn.lock +4596 -5321
- package/examples/defaultFilter.json +0 -203
- package/package-lock.json +0 -18588
- package/src/lib/scanner/Winnower/WinnowerExtractor.ts +0 -37
|
@@ -16,7 +16,6 @@ export function packageParser(fileContent: string, filePath: string): ILocalDepe
|
|
|
16
16
|
const o = JSON.parse(fileContent);
|
|
17
17
|
let devDeps = Object.keys(o.devDependencies || {});
|
|
18
18
|
let deps = Object.keys(o.dependencies || {});
|
|
19
|
-
let listDeps = [...deps, ...devDeps];
|
|
20
19
|
|
|
21
20
|
for(const name of deps){
|
|
22
21
|
const purlString = new PackageURL(PURL_TYPE, undefined, name, undefined, undefined, undefined).toString();
|
|
@@ -34,18 +33,194 @@ export function packageParser(fileContent: string, filePath: string): ILocalDepe
|
|
|
34
33
|
|
|
35
34
|
// Parse a package-lock.json file from node projects
|
|
36
35
|
// See reference on: https://docs.npmjs.com/cli/v8/configuring-npm/package-json
|
|
37
|
-
const MANIFEST_FILE_1 = 'package-lock.json';
|
|
38
36
|
export function packagelockParser(fileContent: string, filePath: string): ILocalDependency {
|
|
39
37
|
|
|
40
38
|
const results: ILocalDependency = {file: filePath, purls: []};
|
|
41
|
-
|
|
39
|
+
|
|
40
|
+
if(path.basename(filePath) != 'package-lock.json')
|
|
42
41
|
return results;
|
|
43
42
|
|
|
44
|
-
const
|
|
45
|
-
|
|
43
|
+
const packages = JSON.parse(fileContent)?.packages;
|
|
44
|
+
|
|
45
|
+
if(!packages) return results;
|
|
46
|
+
|
|
47
|
+
for (const [key, value] of Object.entries(packages)) {
|
|
46
48
|
if(!key) continue;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
const keySplit = key.split("/")
|
|
51
|
+
const depName = keySplit[keySplit.length-1]
|
|
52
|
+
|
|
53
|
+
let purl = new PackageURL(PURL_TYPE, undefined, depName,undefined, undefined, undefined).toString();
|
|
54
|
+
let req = value['version'];
|
|
55
|
+
results.purls.push({purl: purl, requirement: req});
|
|
49
56
|
}
|
|
57
|
+
|
|
58
|
+
return results;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
export function yarnLockParser(fileContent: string, filePath: string): ILocalDependency {
|
|
64
|
+
const results: ILocalDependency = {file: filePath, purls: []};
|
|
65
|
+
|
|
66
|
+
if(path.basename(filePath) != 'yarn.lock')
|
|
50
67
|
return results;
|
|
68
|
+
|
|
69
|
+
const yarnVersion = yarnLockRecognizeVersion(fileContent)
|
|
70
|
+
if (yarnVersion === YarnLockVersionEnum.V1) return yarnLockV1Parser(fileContent, filePath)
|
|
71
|
+
else if (yarnVersion === YarnLockVersionEnum.V2) return yarnLockV2Parser(fileContent, filePath)
|
|
72
|
+
|
|
73
|
+
return results;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
enum YarnLockVersionEnum {
|
|
77
|
+
"V1" ,
|
|
78
|
+
"V2",
|
|
79
|
+
UnknownYarnLockFormat
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
The start of v1 file has this:
|
|
84
|
+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
85
|
+
# yarn lockfile v1
|
|
86
|
+
|
|
87
|
+
The start of v2 file has this:
|
|
88
|
+
# This file is generated by running "yarn install" inside your project.
|
|
89
|
+
# Manual changes might be lost - proceed with caution!
|
|
90
|
+
|
|
91
|
+
__metadata:
|
|
92
|
+
*/
|
|
93
|
+
export function yarnLockRecognizeVersion(fileContent: string): YarnLockVersionEnum {
|
|
94
|
+
|
|
95
|
+
const yarn = fileContent.split("\n", 10) //Check only the first 10 lines;
|
|
96
|
+
for (const line of yarn) {
|
|
97
|
+
if ( line.includes('__metadata:') ) return YarnLockVersionEnum.V2
|
|
98
|
+
if ( line.includes('yarn lockfile v1') ) return YarnLockVersionEnum.V1
|
|
99
|
+
}
|
|
100
|
+
return YarnLockVersionEnum.UnknownYarnLockFormat
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function yarnLockV1Parser(fileContent: string, filePath: string): ILocalDependency {
|
|
104
|
+
|
|
105
|
+
const results: ILocalDependency = {file: filePath, purls: []};
|
|
106
|
+
|
|
107
|
+
//Yield an array with each element is a dependency
|
|
108
|
+
/*
|
|
109
|
+
"@babel/core@^7.1.0", "@babel/core@^7.3.4":
|
|
110
|
+
version "7.3.4"
|
|
111
|
+
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
|
|
112
|
+
integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==
|
|
113
|
+
dependencies:
|
|
114
|
+
"@babel/code-frame" "^7.0.0"
|
|
115
|
+
"@babel/generator" "^7.3.4"
|
|
116
|
+
*/
|
|
117
|
+
const yl_dependencies = fileContent.split("\n\n");
|
|
118
|
+
|
|
119
|
+
for (const yl_dependency of yl_dependencies) {
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
const dependencyData: Record<string, string> = {}
|
|
124
|
+
const topRequirements = [];
|
|
125
|
+
|
|
126
|
+
const dep_lines = yl_dependency.split("\n");
|
|
127
|
+
if (dep_lines.every((line) => line.trim().startsWith("#") == true)) continue //All lines are coments
|
|
128
|
+
if (dep_lines.every((line) => line.trim() == "")) continue //All lines are empty lines
|
|
129
|
+
|
|
130
|
+
for (const dep_line of dep_lines) {
|
|
131
|
+
|
|
132
|
+
// Clean comments and empty lines
|
|
133
|
+
const trimmed = dep_line.trim();
|
|
134
|
+
const comment = trimmed.startsWith('#');
|
|
135
|
+
if (!trimmed || comment) continue
|
|
136
|
+
|
|
137
|
+
// Do nothing with it's own dependencies
|
|
138
|
+
// "@babel/code-frame" "^7.0.0"
|
|
139
|
+
// "@babel/generator" "^7.3.4"
|
|
140
|
+
if (dep_line.startsWith(' '.repeat(4))) {}
|
|
141
|
+
|
|
142
|
+
// version "7.3.4"
|
|
143
|
+
// resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
|
|
144
|
+
// integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==
|
|
145
|
+
// dependencies:
|
|
146
|
+
else if (dep_line.startsWith(' '.repeat(2))) {
|
|
147
|
+
const dep = trimmed.split(" ")
|
|
148
|
+
const key = dep[0].trim();
|
|
149
|
+
if (key !== "dependencies:") {
|
|
150
|
+
dependencyData[key] = dep[1].replace(/"|'/g, "");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// the first line of a dependency has the name and requirements
|
|
155
|
+
//"@babel/core@^7.1.0", "@babel/core@^7.3.4":
|
|
156
|
+
else if (!dep_line.startsWith(' ')){
|
|
157
|
+
const dep = dep_line.replace(/:/g, "").split(",");
|
|
158
|
+
const requirements = dep.map(line => line.trim().replace(/"|'/g, ""));
|
|
159
|
+
|
|
160
|
+
for (const req of requirements) {
|
|
161
|
+
|
|
162
|
+
const atIndex = req.lastIndexOf("@")
|
|
163
|
+
|
|
164
|
+
let constraint = req.slice(atIndex+1) // gets ^7.1.0
|
|
165
|
+
constraint = constraint.replace(/"|'/g, "");
|
|
166
|
+
|
|
167
|
+
const ns_name = req.slice(0, atIndex)
|
|
168
|
+
|
|
169
|
+
let ns = '';
|
|
170
|
+
let name = ns_name;
|
|
171
|
+
if (ns_name.includes("/")) {
|
|
172
|
+
const slashIndex = req.lastIndexOf("/")
|
|
173
|
+
ns = ns_name.slice(0,slashIndex);
|
|
174
|
+
name = ns_name.slice(slashIndex+1)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
topRequirements.push({constraint: constraint, ns: ns, name: name });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//Make sure that name and namespace are equal for the same dependency
|
|
186
|
+
const isNsNameEqual = topRequirements.every((topRequirement) => {
|
|
187
|
+
return topRequirement.ns === topRequirements[0].ns && topRequirement.name === topRequirements[0].name
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
if (!isNsNameEqual) {
|
|
191
|
+
console.error("Different names for same dependency is not supported")
|
|
192
|
+
continue
|
|
193
|
+
}
|
|
194
|
+
const topRequirement = topRequirements[0];
|
|
195
|
+
const namespace = topRequirement.ns;
|
|
196
|
+
const name = topRequirement.name;
|
|
197
|
+
const version = dependencyData['version'];
|
|
198
|
+
const purl = new PackageURL(PURL_TYPE, namespace, name, version, undefined, undefined).toString()
|
|
199
|
+
|
|
200
|
+
let requirement = ''
|
|
201
|
+
for (const topRequirement of topRequirements) {
|
|
202
|
+
requirement += topRequirement.constraint + ", "
|
|
203
|
+
}
|
|
204
|
+
if (requirement.endsWith(", ")) {
|
|
205
|
+
requirement = requirement.slice(0, requirement.length-2)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
results.purls.push({purl: purl, requirement: requirement})
|
|
209
|
+
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
return results;
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
export function yarnLockV2Parser(fileContent: string, filePath: string): ILocalDependency {
|
|
220
|
+
|
|
221
|
+
const results: ILocalDependency = {file: filePath, purls: []};
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
return results;
|
|
225
|
+
|
|
51
226
|
}
|
|
@@ -1,28 +1,62 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FingerprintPackage } from '../WfpProvider/FingerprintPackage';
|
|
2
|
+
import FormData from 'form-data';
|
|
3
|
+
import { SbomMode } from '../ScannerTypes';
|
|
4
|
+
|
|
2
5
|
export class DispatchableItem {
|
|
3
|
-
private
|
|
6
|
+
private readonly form: FormData;
|
|
4
7
|
|
|
5
8
|
private errorCounter: number;
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
private fingerprintPackage: FingerprintPackage;
|
|
11
|
+
|
|
12
|
+
private engineFlags: number;
|
|
13
|
+
|
|
14
|
+
private sbom: string;
|
|
15
|
+
|
|
16
|
+
private sbomMode: SbomMode;
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
9
19
|
this.errorCounter = 0;
|
|
20
|
+
this.form = new FormData();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public getForm(): FormData {
|
|
24
|
+
this.form.append('filename', Buffer.from(this.fingerprintPackage.getContent()), 'data.wfp');
|
|
25
|
+
if(this.engineFlags) this.form.append('flags', this.engineFlags);
|
|
26
|
+
|
|
27
|
+
if(this.sbomMode && this.sbom) {
|
|
28
|
+
this.form.append('assets', this.sbom);
|
|
29
|
+
this.form.append('type', this.sbomMode);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return this.form;
|
|
10
33
|
}
|
|
11
34
|
|
|
12
|
-
increaseErrorCounter() {
|
|
35
|
+
public increaseErrorCounter() {
|
|
13
36
|
this.errorCounter += 1;
|
|
14
37
|
}
|
|
15
38
|
|
|
16
|
-
public
|
|
17
|
-
return this.
|
|
39
|
+
public getErrorCounter() {
|
|
40
|
+
return this.errorCounter;
|
|
18
41
|
}
|
|
19
42
|
|
|
20
|
-
|
|
21
|
-
|
|
43
|
+
public setFingerprintPackage(fingerprintPackage: FingerprintPackage) {
|
|
44
|
+
this.fingerprintPackage = fingerprintPackage;
|
|
22
45
|
}
|
|
23
46
|
|
|
24
|
-
|
|
25
|
-
return this.
|
|
47
|
+
public getFingerprintPackage(): FingerprintPackage {
|
|
48
|
+
return this.fingerprintPackage;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public setEngineFlags(engineFlags: number) {
|
|
52
|
+
this.engineFlags = engineFlags;
|
|
26
53
|
}
|
|
27
54
|
|
|
55
|
+
public setSbom(sbom: string, sbomMode: SbomMode) {
|
|
56
|
+
this.sbom = sbom;
|
|
57
|
+
this.sbomMode = sbomMode;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
28
62
|
}
|
|
@@ -11,6 +11,8 @@ import { ScannerCfg } from "../ScannerCfg";
|
|
|
11
11
|
import { GlobalControllerAborter } from "./GlobalControllerAborter";
|
|
12
12
|
import { DispatchableItem } from './DispatchableItem';
|
|
13
13
|
|
|
14
|
+
const MAX_CONCURRENT_REQUEST = 30;
|
|
15
|
+
|
|
14
16
|
export class Dispatcher extends EventEmitter {
|
|
15
17
|
private scannerCfg: ScannerCfg;
|
|
16
18
|
|
|
@@ -27,6 +29,9 @@ export class Dispatcher extends EventEmitter {
|
|
|
27
29
|
constructor(scannerCfg = new ScannerCfg()) {
|
|
28
30
|
super();
|
|
29
31
|
this.scannerCfg = scannerCfg;
|
|
32
|
+
if(this.scannerCfg.CONCURRENCY_LIMIT > MAX_CONCURRENT_REQUEST)
|
|
33
|
+
this.scannerCfg.CONCURRENCY_LIMIT = MAX_CONCURRENT_REQUEST;
|
|
34
|
+
|
|
30
35
|
this.init();
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -64,8 +69,8 @@ export class Dispatcher extends EventEmitter {
|
|
|
64
69
|
this.globalAbortController.abortAll();
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
public dispatchItem(
|
|
68
|
-
this.pQueue.add(() => this.dispatch(
|
|
72
|
+
public dispatchItem(item: DispatchableItem): void {
|
|
73
|
+
this.pQueue.add(() => this.dispatch(item));
|
|
69
74
|
|
|
70
75
|
if (
|
|
71
76
|
this.pQueue.size + this.pQueue.pending >= this.scannerCfg.DISPATCHER_QUEUE_SIZE_MAX_LIMIT &&
|
|
@@ -96,7 +101,6 @@ export class Dispatcher extends EventEmitter {
|
|
|
96
101
|
if (this.scannerCfg.ABORT_ON_MAX_RETRIES) this.handleUnrecoverableError(error, disptItem);
|
|
97
102
|
return;
|
|
98
103
|
}
|
|
99
|
-
// const leftRetry = this.scannerCfg.MAX_RETRIES_FOR_RECOVERABLES_ERRORS - disptItem.getErrorCounter();
|
|
100
104
|
this.emit(ScannerEvents.DISPATCHER_LOG,`[ SCANNER ]: Recoverable error happened sending WFP content to server. Reason: ${error.code || error.name}`);
|
|
101
105
|
this.dispatchItem(disptItem);
|
|
102
106
|
return;
|
|
@@ -105,21 +109,14 @@ export class Dispatcher extends EventEmitter {
|
|
|
105
109
|
}
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
async dispatch(
|
|
112
|
+
async dispatch(item: DispatchableItem) {
|
|
109
113
|
const timeoutController = this.globalAbortController.getAbortController();
|
|
110
114
|
const timeoutId = setTimeout(() => timeoutController.abort(), this.scannerCfg.TIMEOUT);
|
|
111
115
|
try {
|
|
112
|
-
const form = new FormData();
|
|
113
|
-
|
|
114
|
-
form.append('filename', Buffer.from(disptItem.getContent()), 'data.wfp');
|
|
115
|
-
|
|
116
|
-
const engineFlag = disptItem.getWinnowerResponse().getEngineFlags();
|
|
117
|
-
if(engineFlag) form.append('flags', engineFlag);
|
|
118
|
-
|
|
119
116
|
this.emit(ScannerEvents.DISPATCHER_WFP_SENDED);
|
|
120
117
|
const response = await fetch(this.scannerCfg.API_URL, {
|
|
121
118
|
method: 'post',
|
|
122
|
-
body:
|
|
119
|
+
body: item.getForm(),
|
|
123
120
|
headers: { 'User-Agent': this.scannerCfg.CLIENT_TIMESTAMP, 'X-Session': this.scannerCfg.API_KEY },
|
|
124
121
|
signal: timeoutController.signal,
|
|
125
122
|
});
|
|
@@ -138,13 +135,13 @@ export class Dispatcher extends EventEmitter {
|
|
|
138
135
|
const dataAsText = await response.text();
|
|
139
136
|
const dataAsObj = JSON.parse(dataAsText);
|
|
140
137
|
|
|
141
|
-
const dispatcherResponse = new DispatcherResponse(dataAsObj,
|
|
138
|
+
const dispatcherResponse = new DispatcherResponse(dataAsObj, item.getFingerprintPackage().getContent());
|
|
142
139
|
this.emit(ScannerEvents.DISPATCHER_NEW_DATA, dispatcherResponse);
|
|
143
140
|
return Promise.resolve();
|
|
144
141
|
} catch (e) {
|
|
145
142
|
clearTimeout(timeoutId);
|
|
146
143
|
this.globalAbortController.removeAbortController(timeoutController);
|
|
147
|
-
this.errorHandler(e,
|
|
144
|
+
this.errorHandler(e, item);
|
|
148
145
|
return Promise.resolve();
|
|
149
146
|
}
|
|
150
147
|
}
|
|
@@ -15,15 +15,13 @@ import { ScannerEvents, ScannerInput } from './ScannerTypes';
|
|
|
15
15
|
import sortPaths from 'sort-paths';
|
|
16
16
|
|
|
17
17
|
import { WfpProvider } from './WfpProvider/WfpProvider';
|
|
18
|
-
import {
|
|
18
|
+
import { FingerprintPackage } from './WfpProvider/FingerprintPackage';
|
|
19
19
|
import { WfpCalculator } from './WfpProvider/WfpCalculator/WfpCalculator';
|
|
20
20
|
import { WfpSplitter } from './WfpProvider/WfpSplitter/WfpSplitter';
|
|
21
21
|
|
|
22
22
|
let finishPromiseResolve;
|
|
23
23
|
let finishPromiseReject;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
25
|
export class Scanner extends EventEmitter {
|
|
28
26
|
private scannerCfg: ScannerCfg;
|
|
29
27
|
|
|
@@ -88,12 +86,18 @@ export class Scanner extends EventEmitter {
|
|
|
88
86
|
}
|
|
89
87
|
|
|
90
88
|
setWinnowerListeners() {
|
|
91
|
-
this.wfpProvider.on(ScannerEvents.WINNOWING_NEW_CONTENT, (
|
|
92
|
-
this.emit(ScannerEvents.WINNOWING_NEW_CONTENT,
|
|
89
|
+
this.wfpProvider.on(ScannerEvents.WINNOWING_NEW_CONTENT, (fingerprintPackage: FingerprintPackage) => {
|
|
90
|
+
this.emit(ScannerEvents.WINNOWING_NEW_CONTENT, fingerprintPackage);
|
|
93
91
|
this.reportLog(`[ SCANNER ]: New WFP content`);
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
92
|
+
|
|
93
|
+
const item = new DispatchableItem();
|
|
94
|
+
item.setFingerprintPackage(fingerprintPackage);
|
|
95
|
+
if(this.scannerInput[0]?.engineFlags) item.setEngineFlags(this.scannerInput[0]?.engineFlags);
|
|
96
|
+
|
|
97
|
+
if(this.scannerInput[0]?.sbom && this.scannerInput[0]?.sbomMode)
|
|
98
|
+
item.setSbom(this.scannerInput[0]?.sbom, this.scannerInput[0]?.sbomMode);
|
|
99
|
+
|
|
100
|
+
this.dispatcher.dispatchItem(item);
|
|
97
101
|
});
|
|
98
102
|
|
|
99
103
|
this.wfpProvider.on(ScannerEvents.WINNOWER_LOG, (msg) => {
|
|
@@ -116,7 +120,7 @@ export class Scanner extends EventEmitter {
|
|
|
116
120
|
this.wfpProvider.resume();
|
|
117
121
|
});
|
|
118
122
|
|
|
119
|
-
this.dispatcher.on(ScannerEvents.DISPATCHER_NEW_DATA, async (response) => {
|
|
123
|
+
this.dispatcher.on(ScannerEvents.DISPATCHER_NEW_DATA, async (response: DispatcherResponse) => {
|
|
120
124
|
this.processingNewData = true;
|
|
121
125
|
this.processedFiles += response.getNumberOfFilesScanned();
|
|
122
126
|
this.reportLog(`[ SCANNER ]: Received results of ${response.getNumberOfFilesScanned()} files`);
|
|
@@ -134,8 +138,8 @@ export class Scanner extends EventEmitter {
|
|
|
134
138
|
}
|
|
135
139
|
});
|
|
136
140
|
|
|
137
|
-
this.dispatcher.on(ScannerEvents.DISPATCHER_ITEM_NO_DISPATCHED, (disptItem) => {
|
|
138
|
-
const filesNotScanned = disptItem.
|
|
141
|
+
this.dispatcher.on(ScannerEvents.DISPATCHER_ITEM_NO_DISPATCHED, (disptItem: DispatchableItem) => {
|
|
142
|
+
const filesNotScanned = disptItem.getFingerprintPackage().getFilesFingerprinted();
|
|
139
143
|
this.appendFilesToNotScanned(filesNotScanned);
|
|
140
144
|
});
|
|
141
145
|
|
|
@@ -143,8 +147,8 @@ export class Scanner extends EventEmitter {
|
|
|
143
147
|
this.reportLog(msg);
|
|
144
148
|
});
|
|
145
149
|
|
|
146
|
-
this.dispatcher.on(ScannerEvents.ERROR, (error, disptItem) => {
|
|
147
|
-
const wfpContent = disptItem.
|
|
150
|
+
this.dispatcher.on(ScannerEvents.ERROR, (error: Error, disptItem: DispatchableItem) => {
|
|
151
|
+
const wfpContent = disptItem.getFingerprintPackage().getContent();
|
|
148
152
|
fs.writeFileSync(`${this.workDirectory}/failed.wfp`, wfpContent, 'utf8');
|
|
149
153
|
this.errorHandler(error, ScannerEvents.MODULE_DISPATCHER);
|
|
150
154
|
});
|
|
@@ -20,10 +20,11 @@ export class ScannerCfg {
|
|
|
20
20
|
|
|
21
21
|
ABORT_ON_MAX_RETRIES = true;
|
|
22
22
|
|
|
23
|
-
// Persist results after [ X ]
|
|
23
|
+
// Persist results after [ X ] server responses
|
|
24
24
|
MAX_RESPONSES_IN_BUFFER = 300;
|
|
25
25
|
|
|
26
26
|
DISPATCHER_QUEUE_SIZE_MAX_LIMIT = 300;
|
|
27
27
|
|
|
28
28
|
DISPATCHER_QUEUE_SIZE_MIN_LIMIT = 200;
|
|
29
|
+
|
|
29
30
|
};
|
|
@@ -30,13 +30,21 @@ export enum ScannerEvents {
|
|
|
30
30
|
|
|
31
31
|
export enum WinnowingMode {
|
|
32
32
|
FULL_WINNOWING = 'FULL_WINNOWING',
|
|
33
|
+
FULL_WINNOWING_HPSM = 'FULL_WINNOWING_HPSM',
|
|
33
34
|
WINNOWING_ONLY_MD5 = 'WINNOWING_ONLY_MD5',
|
|
34
35
|
};
|
|
35
36
|
|
|
37
|
+
export enum SbomMode {
|
|
38
|
+
SBOM_IGNORE = 'blacklist',
|
|
39
|
+
SBOM_IDENTIFY = 'identify'
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
export interface ScannerInput {
|
|
37
|
-
engineFlags?: number;
|
|
38
|
-
folderRoot?: string;
|
|
39
43
|
fileList: Array<string>;
|
|
44
|
+
folderRoot?: string;
|
|
45
|
+
engineFlags?: number;
|
|
40
46
|
winnowingMode?: WinnowingMode; // Enable winnowing algorithm, otherwise is scanned only MD5
|
|
41
47
|
wfpPath?: string;
|
|
48
|
+
sbom?: string;
|
|
49
|
+
sbomMode?: SbomMode;
|
|
42
50
|
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class FingerprintPackage {
|
|
2
2
|
private wfpContent: string;
|
|
3
3
|
|
|
4
|
-
private engineFlags: number;
|
|
5
|
-
|
|
6
4
|
private scanRoot: string;
|
|
7
5
|
|
|
8
6
|
constructor(wfpContent: string, scanRoot = '') {
|
|
@@ -10,22 +8,14 @@ export class FingerprintPacket {
|
|
|
10
8
|
this.scanRoot = scanRoot;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
public isEqual(
|
|
14
|
-
return this.getContent() ===
|
|
11
|
+
public isEqual(fingerprintPackage: FingerprintPackage): boolean {
|
|
12
|
+
return this.getContent() === fingerprintPackage.getContent();
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
public getContent() {
|
|
15
|
+
public getContent(): string {
|
|
18
16
|
return this.wfpContent;
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
public setEngineFlags(engineFlags: number): void {
|
|
22
|
-
this.engineFlags = engineFlags;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public getEngineFlags(): number {
|
|
26
|
-
return this.engineFlags;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
19
|
public getNumberFilesFingerprinted() {
|
|
30
20
|
const match = this.getContent().match(/file=/g);
|
|
31
21
|
if(!match) return 0;
|