diff --git a/src/utils/checkForPotentialSecrets.ts b/src/utils/checkForPotentialSecrets.ts index fb474a8..2a69e12 100644 --- a/src/utils/checkForPotentialSecrets.ts +++ b/src/utils/checkForPotentialSecrets.ts @@ -1,37 +1,18 @@ import { isArray, isObject, isString } from './utils'; import { stringOccurInObjectValues } from './stringOccurInObjectValue'; -export const checkForPotentialSecrets = (data: any) => { - return data - .map((argument: any) => { - if (isString(argument)) { - return stringOccurInObjectValues({ - needle: argument, - obj: process.env, - }); - } - - if (isObject(argument)) { - return checkForPotentialSecrets(Object.values(argument)); - } - - if (isArray(argument)) { - return checkForPotentialSecretInArrayItem(argument); - } - return null; - }) - .filter((key: string) => !!key); -}; - -function checkForPotentialSecretInArrayItem(argumentItem: any[]) { - return argumentItem.map((arrayValue: any) => { - if (isObject(arrayValue)) { - return checkForPotentialSecrets(arrayValue); +export const checkForPotentialSecrets = (data: any[]): string[] => { + return data.reduce((acc: string[], argument: any) => { + let result: string | string[] | null = []; + + if (isString(argument)) { + result = stringOccurInObjectValues({ needle: argument, obj: process.env }); + } else if (isObject(argument)) { + result = checkForPotentialSecrets(Object.values(argument)); + } else if (isArray(argument)) { + result = checkForPotentialSecrets(argument); } - if (isArray(arrayValue) || isString(arrayValue)) { - return checkForPotentialSecrets(arrayValue); - } - return arrayValue; - }); -} + return result ? acc.concat(result) : acc; + }, []); +}; diff --git a/src/utils/stringOccurInObjectValue.ts b/src/utils/stringOccurInObjectValue.ts index 19ed792..088bde9 100644 --- a/src/utils/stringOccurInObjectValue.ts +++ b/src/utils/stringOccurInObjectValue.ts @@ -3,13 +3,13 @@ import IOptions from '../interfaces/options.interface'; export const stringOccurInObjectValues = (data: { needle: string; obj: Record; -}) => { +}): string | null => { const { needle, obj } = data; if (needle) { return Object.keys(obj).find(secretKey => { const secretValue = (obj || {})[secretKey]; return secretValue.length > 1 && needle.includes(secretValue); - }); + }) ?? null; } return null; }; diff --git a/test/log.test.ts b/test/log.test.ts index cacb289..132ed2c 100644 --- a/test/log.test.ts +++ b/test/log.test.ts @@ -81,4 +81,32 @@ describe('Test console.log', () => { 'the value of the secret: "PORT", is being leaked!' ); }); + + it('should mask secrets when they are part of an object', () => { + secureLog.log('running on port', {secretPort: secrets.PORT}); + expect(mockObj.warn).toHaveBeenCalledWith( + 'the value of the secret: "PORT", is being leaked!' + ); + }); + + it('should mask secrets when they are part of an array', () => { + secureLog.log('running on port', [secrets.PORT]); + expect(mockObj.warn).toHaveBeenCalledWith( + 'the value of the secret: "PORT", is being leaked!' + ); + }); + + it('should mask secrets when they are part of a nested object', () => { + secureLog.log('running on port', {innerValue: {secretPort: secrets.PORT}}); + expect(mockObj.warn).toHaveBeenCalledWith( + 'the value of the secret: "PORT", is being leaked!' + ); + }); + + it('should mask secrets when they are part of a nested array', () => { + secureLog.log('running on port', {innerValue: [secrets.PORT]}); + expect(mockObj.warn).toHaveBeenCalledWith( + 'the value of the secret: "PORT", is being leaked!' + ); + }); });