scanoss 0.38.1 → 0.40.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/CHANGELOG.md +14 -0
- package/build/main/cli/commands/wfp.js +3 -3
- package/build/main/sdk/Decompress/DecompressionManager.d.ts +8 -4
- package/build/main/sdk/Decompress/DecompressionManager.js +48 -41
- package/build/main/sdk/scanner/Scannable/ScannableItem.d.ts +2 -1
- package/build/main/sdk/scanner/Scannable/ScannableItem.js +3 -2
- package/build/main/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +30 -15
- package/build/main/tsconfig.tsbuildinfo +1 -1
- package/build/module/cli/commands/wfp.js +3 -3
- package/build/module/sdk/Decompress/DecompressionManager.d.ts +8 -4
- package/build/module/sdk/Decompress/DecompressionManager.js +48 -41
- package/build/module/sdk/scanner/Scannable/ScannableItem.d.ts +2 -1
- package/build/module/sdk/scanner/Scannable/ScannableItem.js +4 -2
- package/build/module/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +30 -15
- package/build/module/tsconfig.module.tsbuildinfo +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
|
+
## [0.40.0] (2026-04-28)
|
|
7
|
+
### Fixed
|
|
8
|
+
- `WfpCalculator` no longer crashes with `RangeError: Invalid array length` when fingerprinting large binary files.
|
|
9
|
+
- `scanoss-js wfp` CLI now uses `ScanFilter` instead of `DependencyFilter` when building the file list
|
|
10
|
+
### Changed
|
|
11
|
+
- `WfpCalculator` now detects binary files via `isBinaryFileSync`. Binary files emit only the `file=` MD5 line.
|
|
12
|
+
|
|
13
|
+
## [0.39.0] (2026-04-23)
|
|
14
|
+
### Added
|
|
15
|
+
- `DecompressionManager.decompress()` now returns `skippedByDepth: Array<string>`, a list of supported archive paths encountered beyond `decompressionLevel` and therefore not expanded. Allows callers to report which nested archives were left unexpanded.
|
|
16
|
+
### Changed
|
|
17
|
+
- **BREAKING:** `DecompressionManager.decompressRecursive()` return type changed from `Array<{path, error}>` to `{ failedFiles: Array<{path, error}>, skippedByDepth: Array<string> }`. Callers consuming this method directly must update to read `.failedFiles`.
|
|
6
18
|
|
|
7
19
|
## [0.38.1] (2026-04-08)
|
|
8
20
|
### Fixed
|
|
@@ -293,3 +305,5 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
293
305
|
### [0.37.0](https://github.com/scanoss/scanoss.js/compare/v0.36.0...v0.37.0) (2026-03-02)
|
|
294
306
|
### [0.38.0](https://github.com/scanoss/scanoss.js/compare/v0.37.0...v0.38.0) (2026-03-12)
|
|
295
307
|
### [0.38.1](https://github.com/scanoss/scanoss.js/compare/v0.38.0...v0.38.1) (2026-04-08)
|
|
308
|
+
### [0.39.0](https://github.com/scanoss/scanoss.js/compare/v0.38.1...v0.39.0) (2026-04-23)
|
|
309
|
+
### [0.40.0](https://github.com/scanoss/scanoss.js/compare/v0.39.0...v0.40.0) (2026-04-28)
|
|
@@ -10,7 +10,7 @@ const helpers_1 = require("./helpers");
|
|
|
10
10
|
const ScannerTypes_1 = require("../../sdk/scanner/ScannerTypes");
|
|
11
11
|
const WfpCalculator_1 = require("../../sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator");
|
|
12
12
|
const Tree_1 = require("../../sdk/tree/Tree");
|
|
13
|
-
const
|
|
13
|
+
const ScanFilter_1 = require("../../sdk/tree/Filters/ScanFilter");
|
|
14
14
|
async function wfpHandler(rootPath, options) {
|
|
15
15
|
rootPath = rootPath.replace(/\/$/, ''); // Remove trailing slash if exists
|
|
16
16
|
rootPath = rootPath.replace(/^\./, process.env.PWD); // Convert relative path to absolute path.
|
|
@@ -20,7 +20,7 @@ async function wfpHandler(rootPath, options) {
|
|
|
20
20
|
if (pathIsFolder) {
|
|
21
21
|
const tree = new Tree_1.Tree(rootPath);
|
|
22
22
|
tree.build();
|
|
23
|
-
filesToFingerprint = tree.getFileList(new
|
|
23
|
+
filesToFingerprint = tree.getFileList(new ScanFilter_1.ScanFilter(""));
|
|
24
24
|
}
|
|
25
25
|
else {
|
|
26
26
|
filesToFingerprint.push(rootPath);
|
|
@@ -51,4 +51,4 @@ async function wfpHandler(rootPath, options) {
|
|
|
51
51
|
wfpInput.winnowingMode = ScannerTypes_1.WinnowingMode.FULL_WINNOWING_HPSM;
|
|
52
52
|
await wfpCalculator.start(wfpInput);
|
|
53
53
|
}
|
|
54
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
54
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ZwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NsaS9jb21tYW5kcy93ZnAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFhQSxnQ0E4Q0M7QUEzREQsNENBQW9CO0FBRXBCLGdFQUF1QztBQUV2Qyx1Q0FBcUM7QUFDckMsaUVBQThFO0FBRTlFLDZGQUEwRjtBQUUxRiw4Q0FBMkM7QUFDM0Msa0VBQStEO0FBR3hELEtBQUssVUFBVSxVQUFVLENBQUMsUUFBZ0IsRUFBRSxPQUFZO0lBRTdELFFBQVEsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFFLGtDQUFrQztJQUMzRSxRQUFRLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFFLDBDQUEwQztJQUNoRyxNQUFNLFlBQVksR0FBRyxNQUFNLElBQUEsa0JBQVEsRUFBQyxRQUFRLENBQUMsQ0FBQztJQUM5QyxNQUFNLGFBQWEsR0FBRyxJQUFJLDZCQUFhLEVBQUUsQ0FBQztJQUUxQyxJQUFJLGtCQUFrQixHQUFhLEVBQUUsQ0FBQztJQUN0QyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2pCLE1BQU0sSUFBSSxHQUFHLElBQUksV0FBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2hDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNiLGtCQUFrQixHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSx1QkFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDNUQsQ0FBQztTQUFNLENBQUM7UUFDTixrQkFBa0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDbkMsQ0FBQztJQUdELE1BQU0sT0FBTyxHQUFHLEVBQUUsTUFBTSxFQUFFLHlGQUF5RixFQUFFLENBQUM7SUFDdEgsTUFBTSxJQUFJLEdBQUcsSUFBSSxzQkFBVyxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsc0JBQVcsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDcEYsSUFBSSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFFekMsSUFBSSxZQUFZLEdBQUcsRUFBRSxDQUFDO0lBQ3RCLGFBQWEsQ0FBQyxFQUFFLENBQUMsNEJBQWEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLGtCQUFzQyxFQUFFLEVBQUU7UUFDL0YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQywyQkFBMkIsRUFBRSxDQUFDLENBQUM7UUFDakUsWUFBWSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUUsa0JBQWtCLENBQUMsVUFBVSxFQUFFLENBQUUsQ0FBQztJQUN4RSxDQUFDLENBQUMsQ0FBQztJQUVILElBQUksT0FBTyxDQUFDLE9BQU87UUFDakIsYUFBYSxDQUFDLEVBQUUsQ0FBQyw0QkFBYSxDQUFDLFlBQVksRUFBRSxDQUFDLEdBQVcsRUFBRSxFQUFFO1lBQzNELE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDckIsQ0FBQyxDQUFDLENBQUM7SUFFTCxhQUFhLENBQUMsRUFBRSxDQUFDLDRCQUFhLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxFQUFFO1FBQ3RELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNaLElBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2xCLFlBQUUsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUNqRCxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDNUIsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQXNCLEVBQUMsUUFBUSxFQUFFLGtCQUFrQixFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQTtJQUN2SCxJQUFHLE9BQU8sQ0FBQyxJQUFJO1FBQUUsUUFBUSxDQUFDLGFBQWEsR0FBRyw0QkFBYSxDQUFDLG1CQUFtQixDQUFDO0lBQzVFLE1BQU0sYUFBYSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUd0QyxDQUFDIn0=
|
|
@@ -13,9 +13,13 @@ export declare class DecompressionManager {
|
|
|
13
13
|
path: string;
|
|
14
14
|
error: string;
|
|
15
15
|
}>;
|
|
16
|
+
skippedByDepth: Array<string>;
|
|
17
|
+
}>;
|
|
18
|
+
decompressRecursive(archivePath: string, level: number): Promise<{
|
|
19
|
+
failedFiles: Array<{
|
|
20
|
+
path: string;
|
|
21
|
+
error: string;
|
|
22
|
+
}>;
|
|
23
|
+
skippedByDepth: Array<string>;
|
|
16
24
|
}>;
|
|
17
|
-
decompressRecursive(archivePath: string, level: number): Promise<Array<{
|
|
18
|
-
path: string;
|
|
19
|
-
error: string;
|
|
20
|
-
}>>;
|
|
21
25
|
}
|
|
@@ -37,59 +37,66 @@ class DecompressionManager {
|
|
|
37
37
|
}
|
|
38
38
|
async decompress(archivesPaths) {
|
|
39
39
|
const failedFiles = [];
|
|
40
|
+
const skippedByDepth = [];
|
|
40
41
|
for (const archivePath of archivesPaths) {
|
|
41
|
-
const
|
|
42
|
-
failedFiles.push(...
|
|
42
|
+
const result = await this.decompressRecursive(archivePath, 0);
|
|
43
|
+
failedFiles.push(...result.failedFiles);
|
|
44
|
+
skippedByDepth.push(...result.skippedByDepth);
|
|
43
45
|
}
|
|
44
46
|
const parentFolders = archivesPaths.map(archivePath => `${archivePath}${this.suffix}`);
|
|
45
|
-
return { parentFolders, failedFiles };
|
|
47
|
+
return { parentFolders, failedFiles, skippedByDepth };
|
|
46
48
|
}
|
|
47
49
|
async decompressRecursive(archivePath, level) {
|
|
48
50
|
const failedFiles = [];
|
|
49
|
-
|
|
50
|
-
return failedFiles;
|
|
51
|
-
const archiveRootPath = path_1.default.dirname(archivePath);
|
|
51
|
+
const skippedByDepth = [];
|
|
52
52
|
const archiveName = path_1.default.basename(archivePath);
|
|
53
|
-
let newFolderPath = `${archiveRootPath}${path_1.default.sep}${archiveName}${this.suffix}`;
|
|
54
53
|
const isSupported = this.decompressorList.some((d) => d.isSupported(archiveName));
|
|
55
|
-
if (isSupported)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
54
|
+
if (!isSupported)
|
|
55
|
+
return { failedFiles, skippedByDepth };
|
|
56
|
+
// Supported archive but configured depth exceeded — record and stop
|
|
57
|
+
if (level >= this.decompressionLevel) {
|
|
58
|
+
skippedByDepth.push(archivePath);
|
|
59
|
+
return { failedFiles, skippedByDepth };
|
|
60
|
+
}
|
|
61
|
+
const archiveRootPath = path_1.default.dirname(archivePath);
|
|
62
|
+
let newFolderPath = `${archiveRootPath}${path_1.default.sep}${archiveName}${this.suffix}`;
|
|
63
|
+
let i = 0;
|
|
64
|
+
const r = new RegExp("(?<=" + this.suffix + ")-\\d+$"); //Selects last -X where X is a number
|
|
65
|
+
while (!this.decompressOverride && fs_1.default.existsSync(newFolderPath)) { //Search for a free name
|
|
66
|
+
newFolderPath = newFolderPath.replace(r, "");
|
|
67
|
+
newFolderPath += `-${i}`;
|
|
68
|
+
i++;
|
|
69
|
+
}
|
|
70
|
+
await fs_1.default.promises.mkdir(newFolderPath, { recursive: true });
|
|
71
|
+
//Search for decompressor and extract archive
|
|
72
|
+
let extractionFailed = false;
|
|
73
|
+
for (const d of this.decompressorList) {
|
|
74
|
+
if (d.isSupported(archiveName)) {
|
|
75
|
+
try {
|
|
76
|
+
await d.run(archivePath, newFolderPath);
|
|
78
77
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const newFilesPath = tree.getFileList(new DecompressionFilter_1.DecompressionFilter(""));
|
|
85
|
-
for (const newFilePath of newFilesPath) {
|
|
86
|
-
const nestedFailed = await this.decompressRecursive(newFilePath, level + 1);
|
|
87
|
-
failedFiles.push(...nestedFailed);
|
|
78
|
+
catch (e) {
|
|
79
|
+
await fs_1.default.promises.rm(newFolderPath, { recursive: true, force: true });
|
|
80
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
81
|
+
failedFiles.push({ path: archivePath, error: message });
|
|
82
|
+
extractionFailed = true;
|
|
88
83
|
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//Search for new archives (only if extraction succeeded)
|
|
88
|
+
if (!extractionFailed) {
|
|
89
|
+
const tree = new Tree_1.Tree(newFolderPath);
|
|
90
|
+
tree.build();
|
|
91
|
+
const newFilesPath = tree.getFileList(new DecompressionFilter_1.DecompressionFilter(""));
|
|
92
|
+
for (const newFilePath of newFilesPath) {
|
|
93
|
+
const nested = await this.decompressRecursive(newFilePath, level + 1);
|
|
94
|
+
failedFiles.push(...nested.failedFiles);
|
|
95
|
+
skippedByDepth.push(...nested.skippedByDepth);
|
|
89
96
|
}
|
|
90
97
|
}
|
|
91
|
-
return failedFiles;
|
|
98
|
+
return { failedFiles, skippedByDepth };
|
|
92
99
|
}
|
|
93
100
|
}
|
|
94
101
|
exports.DecompressionManager = DecompressionManager;
|
|
95
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
102
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVjb21wcmVzc2lvbk1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2RrL0RlY29tcHJlc3MvRGVjb21wcmVzc2lvbk1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsZ0RBQXdCO0FBQ3hCLDRDQUFvQjtBQUNwQix1Q0FBb0M7QUFDcEMsNkVBQTBFO0FBRTFFLGtFQUE4RDtBQUM5RCxnRUFBNkQ7QUFDN0QsOEVBQTJFO0FBQzNFLDhEQUEyRDtBQUUzRCxNQUFhLG9CQUFvQjtJQVNPLGlIQUFpSDtJQUV2SixZQUFZLHFCQUE2QixDQUFDLEVBQUUsU0FBaUIsV0FBVyxFQUFFLHFCQUE4QixLQUFLO1FBQzNHLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxrQkFBa0IsQ0FBQztRQUM3QyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsa0JBQWtCLENBQUM7UUFDN0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLGdCQUFnQixHQUFHO1lBQ3RCLElBQUksNkJBQWEsRUFBRTtZQUNuQixJQUFJLDhCQUFhLEVBQUU7WUFDbkIsSUFBSSwyQ0FBb0IsRUFBRTtZQUMxQixJQUFJLDJCQUFZLEVBQUU7U0FDbkIsQ0FBQztJQUVKLENBQUM7SUFFTSxlQUFlLENBQUMsQ0FBZTtRQUNwQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFTSxtQkFBbUI7UUFDeEIsTUFBTSxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7UUFDNUIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1lBQ2xDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUE7UUFDbkQsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLGdCQUFnQixDQUFDO0lB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
|
|
@@ -6,7 +6,8 @@ export declare class ScannableItem {
|
|
|
6
6
|
private fingerprint;
|
|
7
7
|
private maxSizeWfp;
|
|
8
8
|
private lineOffset;
|
|
9
|
-
|
|
9
|
+
private isBinary;
|
|
10
|
+
constructor(content: Buffer, contentSource: string, winnowingMode: any, maxSizeWfp: number, isBinary?: boolean);
|
|
10
11
|
getContent(): Buffer<ArrayBufferLike>;
|
|
11
12
|
getContentSource(): string;
|
|
12
13
|
getFingerprint(): any;
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ScannableItem = void 0;
|
|
4
4
|
class ScannableItem {
|
|
5
|
-
constructor(content, contentSource, winnowingMode, maxSizeWfp) {
|
|
5
|
+
constructor(content, contentSource, winnowingMode, maxSizeWfp, isBinary = false) {
|
|
6
6
|
this.contentSource = contentSource;
|
|
7
7
|
this.content = content;
|
|
8
8
|
this.winnowingMode = winnowingMode;
|
|
9
9
|
this.maxSizeWfp = maxSizeWfp;
|
|
10
10
|
this.lineOffset = 0;
|
|
11
|
+
this.isBinary = isBinary;
|
|
11
12
|
}
|
|
12
13
|
getContent() {
|
|
13
14
|
return this.content;
|
|
@@ -32,4 +33,4 @@ class ScannableItem {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
exports.ScannableItem = ScannableItem;
|
|
35
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2Nhbm5hYmxlSXRlbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9zZGsvc2Nhbm5lci9TY2FubmFibGUvU2Nhbm5hYmxlSXRlbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxNQUFhLGFBQWE7SUFleEIsWUFBWSxPQUFlLEVBQUUsYUFBcUIsRUFBRSxhQUFrQixFQUFFLFVBQWtCLEVBQUUsUUFBUSxHQUFHLEtBQUs7UUFDMUcsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDbkMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDbkMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDN0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUM7UUFDcEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7SUFDM0IsQ0FBQztJQUVNLFVBQVU7UUFDZixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUVNLGdCQUFnQjtRQUNyQixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUM7SUFDNUIsQ0FBQztJQUVNLGNBQWM7UUFDbkIsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFCLENBQUM7SUFFTSxnQkFBZ0I7UUFDckIsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDO0lBQzVCLENBQUM7SUFFTSxhQUFhO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN6QixDQUFDO0lBRU0sYUFBYSxDQUFDLE1BQWM7UUFDakMsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUM7SUFDM0IsQ0FBQztJQUVNLGFBQWE7UUFDbEIsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7Q0FDRjtBQW5ERCxzQ0FtREMifQ==
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.WfpCalculator = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const isbinaryfile_1 = require("isbinaryfile");
|
|
8
9
|
const worker_threads_1 = require("worker_threads");
|
|
9
10
|
const ScannableItem_1 = require("../../Scannable/ScannableItem");
|
|
10
11
|
const ScannerCfg_1 = require("../../ScannerCfg");
|
|
@@ -22,18 +23,21 @@ parentPort.on('message', async (scannableItem) => {
|
|
|
22
23
|
fingerprint = wfp_for_content(
|
|
23
24
|
scannableItem.content,
|
|
24
25
|
scannableItem.contentSource,
|
|
25
|
-
scannableItem.maxSizeWfp
|
|
26
|
+
scannableItem.maxSizeWfp,
|
|
27
|
+
scannableItem.isBinary
|
|
26
28
|
);
|
|
27
29
|
} else if (scannableItem.winnowingMode === "FULL_WINNOWING_HPSM") {
|
|
28
30
|
fingerprint = wfp_hpsm_for_content(
|
|
29
31
|
scannableItem.content,
|
|
30
32
|
scannableItem.contentSource,
|
|
31
|
-
scannableItem.maxSizeWfp
|
|
33
|
+
scannableItem.maxSizeWfp,
|
|
34
|
+
scannableItem.isBinary
|
|
32
35
|
);
|
|
33
36
|
} else if (scannableItem.winnowingMode === "WINNOWING_ONLY_MD5") {
|
|
34
37
|
fingerprint = wfp_only_md5(
|
|
35
38
|
scannableItem.content,
|
|
36
|
-
scannableItem.contentSource
|
|
39
|
+
scannableItem.contentSource,
|
|
40
|
+
scannableItem.isBinary
|
|
37
41
|
);
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -296,18 +300,25 @@ function join_wfp_hpsm(wfp, hpsm) {
|
|
|
296
300
|
* @param {Buffer} content
|
|
297
301
|
* @param {string} contentSource
|
|
298
302
|
* @param {number} maxSize
|
|
303
|
+
* @param {boolean} isBinary When true, HPSM and snippet winnowing are skipped (binary content has no line/code semantics)
|
|
299
304
|
* @returns {string}
|
|
300
305
|
*/
|
|
301
|
-
function wfp_hpsm_for_content(content, contentSource, maxSize) {
|
|
302
|
-
let wfp = wfp_for_content(content, contentSource, maxSize)
|
|
306
|
+
function wfp_hpsm_for_content(content, contentSource, maxSize, isBinary) {
|
|
307
|
+
let wfp = wfp_for_content(content, contentSource, maxSize, isBinary)
|
|
308
|
+
if (isBinary) return truncate_string(wfp, maxSize)
|
|
303
309
|
let hpsm = calc_hpsm(content) //Returns a string
|
|
304
310
|
let wfp_hpsm_joined = join_wfp_hpsm(wfp, hpsm)
|
|
305
311
|
return truncate_string(wfp_hpsm_joined, maxSize)
|
|
306
312
|
}
|
|
307
313
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
314
|
+
// Snippet winnowing and HPSM are line/code semantics — meaningless on
|
|
315
|
+
// binary content (random bytes produce noise grams). Binary files emit
|
|
316
|
+
// only the file= MD5 line, matching the behavior of WINNOWING_ONLY_MD5.
|
|
317
|
+
function wfp_for_content(content, contentSource, maxSize, isBinary) {
|
|
318
|
+
let wfp = wfp_only_md5(content, contentSource, isBinary);
|
|
319
|
+
if (!isBinary) {
|
|
320
|
+
wfp += calc_wfp(content, maxSize);
|
|
321
|
+
}
|
|
311
322
|
return wfp;
|
|
312
323
|
}
|
|
313
324
|
|
|
@@ -416,14 +427,17 @@ function calculate_opposite_line_ending_hash(contents) {
|
|
|
416
427
|
return crypto.createHash('md5').update(opposite_contents).digest('hex');
|
|
417
428
|
}
|
|
418
429
|
|
|
419
|
-
function wfp_only_md5(contents, contentSource) {
|
|
430
|
+
function wfp_only_md5(contents, contentSource, isBinary) {
|
|
420
431
|
const file_md5 = crypto.createHash('md5').update(contents).digest('hex');
|
|
421
432
|
let wfp = 'file=' + String(file_md5) + ',' + String(contents.length) + ',' + String(contentSource)+ String.fromCharCode(10);
|
|
422
433
|
|
|
423
|
-
//
|
|
424
|
-
|
|
425
|
-
if (
|
|
426
|
-
|
|
434
|
+
// fh2 has no meaning on binary content (no line endings to flip) and the
|
|
435
|
+
// normalization loop blows past V8 limits on large buffers.
|
|
436
|
+
if (!isBinary) {
|
|
437
|
+
const opposite_hash = calculate_opposite_line_ending_hash(contents);
|
|
438
|
+
if (opposite_hash !== null) {
|
|
439
|
+
wfp += 'fh2=' + String(opposite_hash) + String.fromCharCode(10);
|
|
440
|
+
}
|
|
427
441
|
}
|
|
428
442
|
|
|
429
443
|
return wfp;
|
|
@@ -559,10 +573,11 @@ class WfpCalculator extends WfpProvider_1.WfpProvider {
|
|
|
559
573
|
const path = this.fileList[this.fileListIndex];
|
|
560
574
|
const contentSource = path.replace(`${this.folderRoot}`, '');
|
|
561
575
|
const content = await this.readFile(path);
|
|
576
|
+
const isBinary = content.length > 0 && (0, isbinaryfile_1.isBinaryFileSync)(path);
|
|
562
577
|
this.fileListIndex += 1;
|
|
563
578
|
if (!(this.fileListIndex % this.scannerCfg.WINNOWING_REPORT_STATUS_AFTER_X))
|
|
564
579
|
this.emit(ScannerTypes_1.ScannerEvents.WINNOWING_STATUS, this.scannerCfg.WINNOWING_REPORT_STATUS_AFTER_X);
|
|
565
|
-
const scannable = new ScannableItem_1.ScannableItem(content, contentSource, this.winnowingMode, this.scannerCfg.WFP_FILE_MAX_SIZE);
|
|
580
|
+
const scannable = new ScannableItem_1.ScannableItem(content, contentSource, this.winnowingMode, this.scannerCfg.WFP_FILE_MAX_SIZE, isBinary);
|
|
566
581
|
if (this.headerFilter && content.length > 0) {
|
|
567
582
|
const lineOffset = this.headerFilter.filter(path, content.toString('utf-8'));
|
|
568
583
|
scannable.setLineOffset(lineOffset);
|
|
@@ -640,4 +655,4 @@ class WfpCalculator extends WfpProvider_1.WfpProvider {
|
|
|
640
655
|
}
|
|
641
656
|
}
|
|
642
657
|
exports.WfpCalculator = WfpCalculator;
|
|
643
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
658
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ZwQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9zZGsvc2Nhbm5lci9XZnBQcm92aWRlci9XZnBDYWxjdWxhdG9yL1dmcENhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLCtDQUFnRDtBQUNoRCxtREFBd0M7QUFFeEMsaUVBQThEO0FBQzlELGlEQUE4QztBQUM5QyxxREFBZ0Y7QUFFaEYsOERBQTJEO0FBQzNELGdEQUFnRTtBQUNoRSxpREFBcUU7QUFFckUsTUFBTSxZQUFZLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0NBdWZwQixDQUFDO0FBRUYsTUFBYSxhQUFjLFNBQVEseUJBQVc7SUFTNUMsWUFBWSxVQUFVLEdBQUcsSUFBSSx1QkFBVSxFQUFFO1FBQ3ZDLEtBQUss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
|