1+ import { _stringMapEntries } from '@naturalcycles/js-lib'
12import { nanoid } from '@naturalcycles/nodejs-lib'
23import {
34 bcryptStringScrubber ,
78 charsFromRightScrubberSQL ,
89 isoDateStringScrubber ,
910 isoDateStringScrubberSQL ,
11+ saltedHashSubstringScrubber ,
1012 preserveOriginalScrubber ,
1113 preserveOriginalScrubberSQL ,
1214 randomEmailInContentScrubber ,
@@ -25,6 +27,8 @@ import {
2527 undefinedScrubberSQL ,
2628 unixTimestampScrubber ,
2729 unixTimestampScrubberSQL ,
30+ defaultScrubbers ,
31+ defaultScrubbersSQL ,
2832} from './scrubbers'
2933
3034const bryptStr1 = '$2a$12$HYNzBb8XYOZZeRwZDiVux.orKNqkSVAoXBDc9Gw7nSxr8rcZupbRK'
@@ -434,3 +438,76 @@ test('bcryptStringScrubberSQL', () => {
434438 bcryptStringScrubberSQL ( { replacements : '$2a$10$:$2a$10$456,$2a$12$:$2a$12$123' } ) ,
435439 ) . toMatchSnapshot ( )
436440} )
441+
442+ describe ( 'saltedHashSubstringScrubber' , ( ) => {
443+ const initializationVector = nanoid ( )
444+
445+ test ( 'should scrub the matching substring with a hash' , ( ) => {
446+ const result = saltedHashSubstringScrubber ( 'foo|00:00:00:00:00:00|bar' , {
447+ regex : '00:00:00:00:00:00' ,
448+ initializationVector,
449+ } )
450+
451+ expect ( result ) . toMatch ( / f o o \| .{ 64 } \| b a r / )
452+ expect ( result ) . not . toContain ( '00:00:00:00:00:00' )
453+ } )
454+
455+ test ( 'should scrub the same value with the same hash' , ( ) => {
456+ const result1 = saltedHashSubstringScrubber ( 'foo|00:00:00:00:00:00|bar' , {
457+ regex : '00:00:00:00:00:00' ,
458+ initializationVector,
459+ } )
460+
461+ const result2 = saltedHashSubstringScrubber ( 'bee|00:00:00:00:00:00|boo' , {
462+ regex : '00:00:00:00:00:00' ,
463+ initializationVector,
464+ } )
465+
466+ expect ( result1 ?. substring ( 4 , 64 ) ) . toBe ( result2 ?. substring ( 4 , 64 ) )
467+ } )
468+
469+ test ( 'should scrub substring using regex' , ( ) => {
470+ const result = saltedHashSubstringScrubber ( 'foo|00:00:00:00:00:00|bar' , {
471+ regex :
472+ '[0-9a-zA-Z]{2}:[0-9a-zA-Z]{2}:[0-9a-zA-Z]{2}:[0-9a-zA-Z]{2}:[0-9a-zA-Z]{2}:[0-9a-zA-Z]{2}' ,
473+ initializationVector,
474+ } )
475+
476+ expect ( result ) . toMatch ( / f o o \| .{ 64 } \| b a r / )
477+ expect ( result ) . not . toContain ( '00:00:00:00:00:00' )
478+ } )
479+
480+ test ( 'should scrub multiple occurrences' , ( ) => {
481+ const result = saltedHashSubstringScrubber ( 'foo|max|bar|max|boo' , {
482+ regex : 'max' ,
483+ initializationVector,
484+ } )
485+
486+ expect ( result ) . not . toContain ( 'max' )
487+ } )
488+
489+ test ( 'should throw when the salt is missing' , ( ) => {
490+ expect ( ( ) => saltedHashSubstringScrubber ( 'foo|max|bar' , { regex : 'max' } as any ) ) . toThrow (
491+ 'Initialization vector is missing' ,
492+ )
493+ } )
494+
495+ test ( 'should throw when the regex or substring is missing' , ( ) => {
496+ expect ( ( ) =>
497+ saltedHashSubstringScrubber ( 'foo|max|bar' , {
498+ initializationVector,
499+ } as any ) ,
500+ ) . toThrow ( 'Substring or regex is missing' )
501+ } )
502+ } )
503+
504+ const scrubberNames = _stringMapEntries ( defaultScrubbers ) . map ( ( [ k ] ) => k )
505+ test . each ( scrubberNames ) ( 'the %s should have its SQL scrubber counterpart' , scrubberName => {
506+ console . log ( scrubberName , defaultScrubbersSQL [ scrubberName ] )
507+ expect ( defaultScrubbersSQL [ scrubberName ] ) . toBeDefined ( )
508+ } )
509+
510+ const sqlScrubberNames = _stringMapEntries ( defaultScrubbersSQL ) . map ( ( [ k ] ) => k )
511+ test . each ( sqlScrubberNames ) ( 'the %s should have its scrubber counterpart' , scrubberName => {
512+ expect ( defaultScrubbers [ scrubberName ] ) . toBeDefined ( )
513+ } )
0 commit comments