scanoss 0.24.0 → 0.26.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 +10 -0
- package/build/main/sdk/Clients/Cryptography/CryptographyHttpClient.js +2 -2
- package/build/main/sdk/Clients/Cryptography/ICryptographyClient.d.ts +1 -1
- package/build/main/sdk/Cryptography/Helper/ResultCollector/Component/ComponentCryptographyResultColletor.js +3 -6
- package/build/main/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +123 -12
- package/build/main/tsconfig.tsbuildinfo +1 -1
- package/build/module/sdk/Clients/Cryptography/CryptographyHttpClient.js +2 -2
- package/build/module/sdk/Clients/Cryptography/ICryptographyClient.d.ts +1 -1
- package/build/module/sdk/Cryptography/Helper/ResultCollector/Component/ComponentCryptographyResultColletor.js +3 -6
- package/build/module/sdk/scanner/WfpProvider/WfpCalculator/WfpCalculator.js +123 -12
- package/build/module/tsconfig.module.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -264,25 +264,24 @@ function calc_hpsm(content) {
|
|
|
264
264
|
* Create a wfp_hpsm package joining wfp (with md5 line) and a hpsm.
|
|
265
265
|
*
|
|
266
266
|
* Example:
|
|
267
|
-
* wfp = file=
|
|
268
|
-
*
|
|
267
|
+
* wfp = file=33d2b65d852100b7fc5e6dae95f07bde,118,/external/inc/crc32c.h
|
|
268
|
+
* fh2=91d5edea99e9cfcdeeb55e722d3aa67f
|
|
269
|
+
* 11=b19bdbfa
|
|
269
270
|
*
|
|
270
|
-
* hpsm = hpsm=
|
|
271
|
+
* hpsm = hpsm=5ac65706ff2d
|
|
271
272
|
*
|
|
272
|
-
* wfp_hpsm = file=
|
|
273
|
-
*
|
|
274
|
-
*
|
|
273
|
+
* wfp_hpsm = file=33d2b65d852100b7fc5e6dae95f07bde,118,/external/inc/crc32c.h
|
|
274
|
+
* fh2=91d5edea99e9cfcdeeb55e722d3aa67f
|
|
275
|
+
* hpsm=5ac65706ff2d
|
|
276
|
+
* 11=b19bdbfa
|
|
275
277
|
*
|
|
276
278
|
* @param {string} wfp Complete wfp string (with md5 line)
|
|
277
279
|
* @param {string} hpsm
|
|
278
280
|
* @returns {string}
|
|
279
281
|
*/
|
|
280
282
|
function join_wfp_hpsm(wfp, hpsm) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
header += hpsm;
|
|
284
|
-
wfp = wfp.replace(/file=.*/, "")
|
|
285
|
-
return header + wfp;
|
|
283
|
+
// Replace fh2= line with fh2= line + newline + hpsm line
|
|
284
|
+
return wfp.replace(/(fh2=.*)/, '$1' + String.fromCharCode(10) + hpsm);
|
|
286
285
|
}
|
|
287
286
|
|
|
288
287
|
/**
|
|
@@ -305,9 +304,121 @@ function wfp_for_content(content, contentSource, maxSize) {
|
|
|
305
304
|
return wfp;
|
|
306
305
|
}
|
|
307
306
|
|
|
307
|
+
/**
|
|
308
|
+
* Detect line ending types in buffer contents.
|
|
309
|
+
*
|
|
310
|
+
* @param {Buffer} contents - File contents as buffer
|
|
311
|
+
* @returns {Object} Object with has_crlf, has_standalone_lf, has_standalone_cr flags
|
|
312
|
+
*/
|
|
313
|
+
function detect_line_endings(contents) {
|
|
314
|
+
let has_crlf = false;
|
|
315
|
+
let has_standalone_lf = false;
|
|
316
|
+
let has_standalone_cr = false;
|
|
317
|
+
|
|
318
|
+
for (let i = 0; i < contents.length; i++) {
|
|
319
|
+
const byte = contents[i];
|
|
320
|
+
|
|
321
|
+
// Check for CRLF (\\r\\n) // Windows (CRLF)
|
|
322
|
+
if (byte === 0x0D && i + 1 < contents.length && contents[i + 1] === 0x0A) {
|
|
323
|
+
has_crlf = true;
|
|
324
|
+
i++; // Skip the next byte since we've already checked it
|
|
325
|
+
}
|
|
326
|
+
// Check for standalone LF (\\n) // Unix (LF) Linux
|
|
327
|
+
else if (byte === 0x0A) {
|
|
328
|
+
has_standalone_lf = true;
|
|
329
|
+
}
|
|
330
|
+
// Check for standalone CR (\\r) // Unix (CR) old MacOS
|
|
331
|
+
else if (byte === 0x0D) {
|
|
332
|
+
has_standalone_cr = true;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if(has_crlf && has_standalone_lf && has_standalone_cr) {
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return { has_crlf: has_crlf, has_standalone_lf: has_standalone_lf, has_standalone_cr: has_standalone_cr };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Calculate hash for contents with opposite line endings.
|
|
345
|
+
* If the file is primarily Unix (LF), calculates Windows (CRLF) hash.
|
|
346
|
+
* If the file is primarily Windows (CRLF), calculates Unix (LF) hash.
|
|
347
|
+
*
|
|
348
|
+
* @param {Buffer} contents - File contents as buffer
|
|
349
|
+
* @returns {string|null} Hash with opposite line endings as hex string, or null if no line endings detected
|
|
350
|
+
*/
|
|
351
|
+
function calculate_opposite_line_ending_hash(contents) {
|
|
352
|
+
const line_endings = detect_line_endings(contents);
|
|
353
|
+
const has_crlf = line_endings.has_crlf;
|
|
354
|
+
const has_standalone_lf = line_endings.has_standalone_lf;
|
|
355
|
+
const has_standalone_cr = line_endings.has_standalone_cr;
|
|
356
|
+
|
|
357
|
+
if (!has_crlf && !has_standalone_lf && !has_standalone_cr) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// First pass: normalize all line endings to LF
|
|
362
|
+
let normalized = [];
|
|
363
|
+
// Optimization: if file only has LF (no CR bytes at all), skip normalization
|
|
364
|
+
if (has_standalone_lf && !has_crlf && !has_standalone_cr) {
|
|
365
|
+
// File is pure Unix (LF only) - already normalized
|
|
366
|
+
normalized = Array.from(contents);
|
|
367
|
+
} else {
|
|
368
|
+
// File has CR bytes (CRLF or standalone CR) - need to normalize
|
|
369
|
+
normalized = [];
|
|
370
|
+
for (let i = 0; i < contents.length; i++) {
|
|
371
|
+
const byte = contents[i];
|
|
372
|
+
if (byte === 0x0D) {
|
|
373
|
+
// CR
|
|
374
|
+
if (i + 1 < contents.length && contents[i + 1] === 0x0A) {
|
|
375
|
+
// CRLF -> LF
|
|
376
|
+
normalized.push(0x0A);
|
|
377
|
+
i++; // Skip the LF
|
|
378
|
+
} else {
|
|
379
|
+
// Standalone CR -> LF
|
|
380
|
+
normalized.push(0x0A);
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
normalized.push(byte);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
let opposite_contents;
|
|
389
|
+
|
|
390
|
+
// Determine the dominant line ending type
|
|
391
|
+
if (has_crlf && !has_standalone_lf && !has_standalone_cr) {
|
|
392
|
+
// File is Windows (CRLF) - produce Unix (LF) hash
|
|
393
|
+
opposite_contents = Buffer.from(normalized);
|
|
394
|
+
} else {
|
|
395
|
+
// File is Unix (LF/CR) or mixed - produce Windows (CRLF) hash
|
|
396
|
+
const with_crlf = [];
|
|
397
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
398
|
+
if (normalized[i] === 0x0A) {
|
|
399
|
+
// LF -> CRLF
|
|
400
|
+
with_crlf.push(0x0D);
|
|
401
|
+
with_crlf.push(0x0A);
|
|
402
|
+
} else {
|
|
403
|
+
with_crlf.push(normalized[i]);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
opposite_contents = Buffer.from(with_crlf);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return crypto.createHash('md5').update(opposite_contents).digest('hex');
|
|
410
|
+
}
|
|
411
|
+
|
|
308
412
|
function wfp_only_md5(contents, contentSource) {
|
|
309
413
|
const file_md5 = crypto.createHash('md5').update(contents).digest('hex');
|
|
310
414
|
let wfp = 'file=' + String(file_md5) + ',' + String(contents.length) + ',' + String(contentSource)+ String.fromCharCode(10);
|
|
415
|
+
|
|
416
|
+
// Calculate and add opposite line ending hash if applicable
|
|
417
|
+
const opposite_hash = calculate_opposite_line_ending_hash(contents);
|
|
418
|
+
if (opposite_hash !== null) {
|
|
419
|
+
wfp += 'fh2=' + String(opposite_hash) + String.fromCharCode(10);
|
|
420
|
+
}
|
|
421
|
+
|
|
311
422
|
return wfp;
|
|
312
423
|
}
|
|
313
424
|
|
|
@@ -509,4 +620,4 @@ export class WfpCalculator extends WfpProvider {
|
|
|
509
620
|
this.sendFingerprint(fingerprint);
|
|
510
621
|
}
|
|
511
622
|
}
|
|
512
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
623
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ZwQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9zZGsvc2Nhbm5lci9XZnBQcm92aWRlci9XZnBDYWxjdWxhdG9yL1dmcENhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3BCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV4QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxhQUFhLEVBQStCLE1BQU0sb0JBQW9CLENBQUM7QUFFaEYsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDM0QsT0FBTyxFQUFxQixXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVoRSxNQUFNLFlBQVksR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7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
|