11import { createReadStream , promises as fs , existsSync } from 'node:fs'
22import path from 'node:path'
3- import { createInterface } from 'node:readline'
43
54import { fdir } from 'fdir'
65import { minimatch } from 'minimatch'
@@ -19,7 +18,6 @@ interface ScanArgs {
1918 filePaths : string [ ]
2019 enhancedScanning ?: boolean
2120 omitValuesFromEnhancedScan ?: unknown [ ]
22- useMinimalChunks : boolean
2321}
2422
2523interface MatchResult {
@@ -303,7 +301,6 @@ export async function scanFilesForKeyValues({
303301 base,
304302 enhancedScanning,
305303 omitValuesFromEnhancedScan = [ ] ,
306- useMinimalChunks = false ,
307304} : ScanArgs ) : Promise < ScanResults > {
308305 const scanResults : ScanResults = {
309306 matches : [ ] ,
@@ -334,8 +331,6 @@ export async function scanFilesForKeyValues({
334331
335332 let settledPromises : PromiseSettledResult < MatchResult [ ] > [ ] = [ ]
336333
337- const searchStream = useMinimalChunks ? searchStreamMinimalChunks : searchStreamReadline
338-
339334 // process the scanning in batches to not run into memory issues by
340335 // processing all files at the same time.
341336 while ( filePaths . length > 0 ) {
@@ -345,7 +340,13 @@ export async function scanFilesForKeyValues({
345340 settledPromises = settledPromises . concat (
346341 await Promise . allSettled (
347342 batch . map ( ( file ) => {
348- return searchStream ( { basePath : base , file, keyValues, enhancedScanning, omitValuesFromEnhancedScan } )
343+ return searchStreamMinimalChunks ( {
344+ basePath : base ,
345+ file,
346+ keyValues,
347+ enhancedScanning,
348+ omitValuesFromEnhancedScan,
349+ } )
349350 } ) ,
350351 ) ,
351352 )
@@ -368,149 +369,6 @@ type SearchStreamOptions = {
368369 omitValuesFromEnhancedScan ?: unknown [ ]
369370}
370371
371- /**
372- * Search stream implementation using node:readline
373- */
374- const searchStreamReadline = ( {
375- basePath,
376- file,
377- keyValues,
378- enhancedScanning,
379- omitValuesFromEnhancedScan = [ ] ,
380- } : SearchStreamOptions ) : Promise < MatchResult [ ] > => {
381- return new Promise ( ( resolve , reject ) => {
382- const filePath = path . resolve ( basePath , file )
383-
384- const inStream = createReadStream ( filePath )
385- const rl = createInterface ( { input : inStream , terminal : false } )
386- const matches : MatchResult [ ] = [ ]
387-
388- const keyVals : string [ ] = ( [ ] as string [ ] ) . concat ( ...Object . values ( keyValues ) )
389-
390- function getKeyForValue ( val ) {
391- let key = ''
392- for ( const [ secretKeyName , valuePermutations ] of Object . entries ( keyValues ) ) {
393- if ( valuePermutations . includes ( val ) ) {
394- key = secretKeyName
395- }
396- }
397- return key
398- }
399-
400- // how many lines is the largest multiline string
401- let maxMultiLineCount = 1
402-
403- keyVals . forEach ( ( valVariant ) => {
404- maxMultiLineCount = Math . max ( maxMultiLineCount , valVariant . split ( '\n' ) . length )
405- } )
406-
407- const lines : string [ ] = [ ]
408-
409- let lineNumber = 0
410-
411- rl . on ( 'line' , function ( line ) {
412- // iterating here so the first line will always appear as line 1 to be human friendly
413- // and match what an IDE would show for a line number.
414- lineNumber ++
415- if ( typeof line === 'string' ) {
416- if ( enhancedScanning ) {
417- matches . push (
418- ...findLikelySecrets ( { text : line , omitValuesFromEnhancedScan } ) . map ( ( { prefix } ) => ( {
419- key : prefix ,
420- file,
421- lineNumber,
422- enhancedMatch : true ,
423- } ) ) ,
424- )
425- }
426- if ( maxMultiLineCount > 1 ) {
427- lines . push ( line )
428- }
429-
430- // only track the max number of lines needed to match our largest
431- // multiline value. If we get above that remove the first value from the list
432- if ( lines . length > maxMultiLineCount ) {
433- lines . shift ( )
434- }
435-
436- keyVals . forEach ( ( valVariant ) => {
437- // matching of single/whole values
438- if ( line . includes ( valVariant ) ) {
439- matches . push ( {
440- file,
441- lineNumber,
442- key : getKeyForValue ( valVariant ) ,
443- enhancedMatch : false ,
444- } )
445- return
446- }
447-
448- // matching of multiline values
449- if ( isMultiLineVal ( valVariant ) ) {
450- // drop empty values at beginning and end
451- const multiStringLines = valVariant . split ( '\n' )
452-
453- // drop early if we don't have enough lines for all values
454- if ( lines . length < multiStringLines . length ) {
455- return
456- }
457-
458- let stillMatches = true
459- let fullMatch = false
460-
461- multiStringLines . forEach ( ( valLine , valIndex ) => {
462- if ( valIndex === 0 ) {
463- // first lines have to end with the line value
464- if ( ! lines [ valIndex ] . endsWith ( valLine ) ) {
465- stillMatches = false
466- }
467- } else if ( valIndex !== multiStringLines . length - 1 ) {
468- // middle lines have to have full line match
469- // middle lines
470- if ( lines [ valIndex ] !== valLine ) {
471- stillMatches = false
472- }
473- } else {
474- // last lines have start with the value
475- if ( ! lines [ valIndex ] . startsWith ( valLine ) ) {
476- stillMatches = false
477- }
478-
479- if ( stillMatches === true ) {
480- fullMatch = true
481- }
482- }
483- } )
484-
485- if ( fullMatch ) {
486- matches . push ( {
487- file,
488- lineNumber : lineNumber - lines . length + 1 ,
489- key : getKeyForValue ( valVariant ) ,
490- enhancedMatch : false ,
491- } )
492- return
493- }
494- }
495- } )
496- }
497- } )
498-
499- rl . on ( 'error' , function ( error ) {
500- if ( error ?. code === 'EISDIR' ) {
501- // file path is a directory - do nothing
502- resolve ( matches )
503- } else {
504- reject ( error )
505- }
506- } )
507-
508- rl . on ( 'close' , function ( ) {
509- resolve ( matches )
510- } )
511- } )
512- }
513-
514372/**
515373 * Search stream implementation using just read stream that allows to buffer less content
516374 */
@@ -783,7 +641,3 @@ export function groupScanResultsByKeyAndScanType(scanResults: ScanResults): {
783641
784642 return { secretMatches : secretMatchesByKeys , enhancedSecretMatches : enhancedSecretMatchesByKeys }
785643}
786-
787- function isMultiLineVal ( v ) {
788- return typeof v === 'string' && v . includes ( '\n' )
789- }
0 commit comments