@lumigo/node-core
Advanced tools
Comparing version 1.13.1 to 1.14.0
import { HttpRawRequest, HttpRawResponse, RequestRawData } from '../types/spans'; | ||
import { ScrubContext } from './secrets'; | ||
/** | ||
* @deprecated Pass a `ScrubContext` instance to `scrub` or `payloadStringify` | ||
*/ | ||
export declare const keyToOmitRegexes: (regexesEnvVarName?: string) => RegExp[]; | ||
import { ScrubContext, SkipPath } from './secrets'; | ||
export declare const prune: (str: string | object, maxLength: number) => string; | ||
export declare const payloadStringify: (payload: any, maxPayloadSize?: number, skipScrubPath?: any, truncated?: boolean, scrubContext?: ScrubContext) => string; | ||
export declare const payloadStringify: (payload: any, scrubContext?: ScrubContext, maxScrubbedPayloadCharacterCount?: number, skipScrubPath?: SkipPath, truncated?: boolean) => any; | ||
export declare function scrub(payload: any, headers: any, sizeLimit: number, truncated?: boolean, scrubContext?: ScrubContext.HTTP_REQUEST_BODY | ScrubContext.HTTP_RESPONSE_BODY): string; | ||
@@ -10,0 +6,0 @@ export declare function scrubRequestDataPayload(requestData: HttpRawRequest | HttpRawResponse, scrubContext?: ScrubContext.HTTP_REQUEST_BODY | ScrubContext.HTTP_RESPONSE_BODY): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.decodeHttpBody = exports.spanHasErrors = exports.scrubRequestDataPayload = exports.scrub = exports.payloadStringify = exports.prune = exports.keyToOmitRegexes = void 0; | ||
exports.decodeHttpBody = exports.spanHasErrors = exports.scrubRequestDataPayload = exports.scrub = exports.payloadStringify = exports.prune = void 0; | ||
const utils_1 = require("../utils"); | ||
const utils_2 = require("../utils"); | ||
const logger_1 = require("../logger"); | ||
@@ -10,31 +9,2 @@ const untruncateJson_1 = require("../tools/untruncateJson"); | ||
const secrets_1 = require("./secrets"); | ||
const nativeTypes = ['string', 'bigint', 'number', 'undefined', 'boolean']; | ||
const SCRUBBED_TEXT = '****'; | ||
const TRUNCATED_TEXT = '...[too long]'; | ||
const isNativeType = (obj) => nativeTypes.includes(typeof obj); | ||
const keyToRegexes = (regexesList = utils_1.OMITTING_KEYS_REGEXES, backwardCompRegexEnvVarName = utils_1.LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP, regexesEnvVarName = utils_1.LUMIGO_SECRET_MASKING_REGEX) => { | ||
if (process.env[backwardCompRegexEnvVarName]) { | ||
const parseResponse = (0, utils_1.parseJsonFromEnvVar)(backwardCompRegexEnvVarName, true); | ||
if (parseResponse) { | ||
regexesList = parseResponse; | ||
} | ||
} | ||
else if (process.env[regexesEnvVarName]) { | ||
const parseResponse = (0, utils_1.parseJsonFromEnvVar)(regexesEnvVarName, true); | ||
if (parseResponse) { | ||
regexesList = parseResponse; | ||
} | ||
} | ||
return regexesList.map((x) => new RegExp(x, 'i')); | ||
}; | ||
/** | ||
* @deprecated Pass a `ScrubContext` instance to `scrub` or `payloadStringify` | ||
*/ | ||
const keyToOmitRegexes = (regexesEnvVarName = utils_1.LUMIGO_SECRET_MASKING_REGEX) => { | ||
return keyToRegexes(); | ||
}; | ||
exports.keyToOmitRegexes = keyToOmitRegexes; | ||
const whitelistKeysRegexes = () => { | ||
return keyToRegexes([], null, utils_1.LUMIGO_WHITELIST_KEYS_REGEXES); | ||
}; | ||
const prune = (str, maxLength) => { | ||
@@ -46,114 +16,57 @@ let toPrune = str; | ||
} | ||
return toPrune.substr(0, maxLength); | ||
return toPrune.substring(0, maxLength); | ||
}; | ||
exports.prune = prune; | ||
const keyContainsRegex = (regexes, key) => { | ||
if (!isNaN(key)) { | ||
//optimization for arrays | ||
return false; | ||
const JSON_TRUNCATION_MARKER = '✂'; | ||
const JSON_CIRCULAR_REFERENCE_MARKER = '⟳'; | ||
const getValue = (value) => { | ||
if (value === secrets_1.CIRCULAR_REFERENCE_SYMBOL) { | ||
return JSON_CIRCULAR_REFERENCE_MARKER; | ||
} | ||
return !!regexes.some((regex) => regex.test(key)); | ||
if ((0, secrets_1.isTruncationSymbol)(value)) { | ||
const truncatedValue = (0, secrets_1.getTruncatedValue)(value); | ||
return truncatedValue === undefined | ||
? JSON_TRUNCATION_MARKER | ||
: /* | ||
* We accept the false positive that, if the value is an un-truncated | ||
* string ending with the '✂' character, it will be uncorrectly marked | ||
* as truncated. | ||
*/ | ||
`${truncatedValue}${JSON_TRUNCATION_MARKER}`; | ||
} | ||
return value; | ||
}; | ||
//Base64 calculation taken from : https://stackoverflow.com/questions/13378815/base64-length-calculation | ||
const getNativeVarSize = (obj) => (obj ? (obj.toString().length * 4) / 3 : 0); | ||
const getItemsInPath = (0, utils_2.safeExecute)((payload, path) => { | ||
if (!payload || !path) { | ||
return []; | ||
} | ||
if (Array.isArray(path[0]) && Array.isArray(payload)) { | ||
const newPath = path.slice(1); | ||
return [].concat(...payload.map((i) => getItemsInPath(i, newPath))); | ||
} | ||
else if (payload[path[0]]) { | ||
if (path.length === 1) { | ||
return [payload]; | ||
const payloadStringify = (payload, scrubContext = secrets_1.ScrubContext.DEFAULT, maxScrubbedPayloadCharacterCount = (0, utils_1.getEventEntitySize)(), skipScrubPath = [], truncated = false) => { | ||
try { | ||
const { scrubbedPayload } = (0, secrets_1.scrubWithApproximateMaxPayloadSize)(payload, maxScrubbedPayloadCharacterCount, scrubContext, skipScrubPath); | ||
if ((0, utils_1.isSymbol)(scrubbedPayload)) { | ||
if ((0, secrets_1.isTruncationSymbol)(scrubbedPayload) || scrubbedPayload === secrets_1.CIRCULAR_REFERENCE_SYMBOL) { | ||
return getValue(scrubbedPayload); | ||
} | ||
} | ||
return getItemsInPath(payload[path[0]], path.slice(1)); | ||
} | ||
return []; | ||
}, 'Failed to find items to skip scrubbing', (0, logger_1.getLogger)().LOG_LEVELS.WARNING, []); | ||
const payloadStringify = (payload, maxPayloadSize = (0, utils_1.getEventEntitySize)(), skipScrubPath = null, truncated = false, scrubContext = secrets_1.ScrubContext.DEFAULT) => { | ||
let totalSize = 0; | ||
const refsFound = []; | ||
let secretScrubber; | ||
switch (scrubContext) { | ||
case secrets_1.ScrubContext.HTTP_REQUEST_BODY: { | ||
secretScrubber = secrets_1.httpRequestBodiesSecretScrubber; | ||
break; | ||
let result = JSON.stringify(scrubbedPayload, (_, value) => getValue(value)); | ||
if (truncated && !result.endsWith(JSON_TRUNCATION_MARKER)) { | ||
// Payload already came in truncated | ||
result = `${result}${JSON_TRUNCATION_MARKER}`; | ||
} | ||
case secrets_1.ScrubContext.HTTP_REQUEST_HEADERS: { | ||
secretScrubber = secrets_1.httpRequestHeadersSecretScrubber; | ||
break; | ||
} | ||
case secrets_1.ScrubContext.HTTP_REQUEST_QUERY: { | ||
secretScrubber = secrets_1.httpQueryParamsSecretScrubber; | ||
break; | ||
} | ||
case secrets_1.ScrubContext.HTTP_RESPONSE_BODY: { | ||
secretScrubber = secrets_1.httpResponseBodiesSecretScrubber; | ||
break; | ||
} | ||
case secrets_1.ScrubContext.HTTP_RESPONSE_HEADERS: { | ||
secretScrubber = secrets_1.httpResponseHeadersSecretScrubber; | ||
break; | ||
} | ||
case secrets_1.ScrubContext.PROCESS_ENVIRONMENT: { | ||
secretScrubber = secrets_1.processEnvironmentSecretScrubber; | ||
break; | ||
} | ||
default: { | ||
secretScrubber = secrets_1.defaultSecretScrubber; | ||
break; | ||
} | ||
return result || ''; | ||
} | ||
const secretsRegexes = secretScrubber.expressions; | ||
const whitelistRegexes = whitelistKeysRegexes(); | ||
const secretItemsToSkipScrubbing = new Set(getItemsInPath(payload, skipScrubPath)); | ||
let isPruned = false; | ||
let result = JSON.stringify(payload, function (key, value) { | ||
const type = typeof value; | ||
const isObj = type === 'object'; | ||
const isStr = type === 'string'; | ||
const shouldSkipSecretScrub = skipScrubPath && | ||
skipScrubPath[skipScrubPath.length - 1] === key && | ||
secretItemsToSkipScrubbing.has(this); | ||
if (!(isObj && refsFound.includes(value))) { | ||
if (totalSize < maxPayloadSize) { | ||
if (!shouldSkipSecretScrub && | ||
!keyContainsRegex(whitelistRegexes, key) && | ||
keyContainsRegex(secretsRegexes, key)) | ||
return SCRUBBED_TEXT; | ||
if (isNativeType(value)) { | ||
totalSize += getNativeVarSize(value); | ||
} | ||
if (isObj) { | ||
refsFound.push(value); | ||
} | ||
if (value && isStr && value.length > maxPayloadSize) { | ||
isPruned = true; | ||
return (0, exports.prune)(value, maxPayloadSize); | ||
} | ||
if (value instanceof Error) | ||
return { | ||
stack: (0, exports.prune)(value.stack, maxPayloadSize), | ||
message: value.message, | ||
}; | ||
return value; | ||
} | ||
else | ||
isPruned = true; | ||
catch (err) { | ||
try { | ||
const res = payload.toString(); | ||
(0, logger_1.getLogger)().warn('Cannot stringify payload, falling back on Object.toString(); the payload will not have secrets scrubbed in Lumigo and what will be displayed depends on its implementation of .toString()'); | ||
return res; | ||
} | ||
else { | ||
isPruned = true; | ||
catch (err) { | ||
(0, logger_1.getLogger)().warn('Cannot JSON.stringify payload, and invoking toString() on payload failed as well; the payload will not be available in Lumigo'); | ||
return ''; | ||
} | ||
}); | ||
if (result && (isPruned || truncated)) { | ||
result = result.replace(/,null/g, ''); | ||
result = result.concat(TRUNCATED_TEXT); | ||
} | ||
return result || ''; | ||
}; | ||
exports.payloadStringify = payloadStringify; | ||
const isJsonContent = (payload, headers) => { | ||
return (0, utils_1.isString)(payload) && headers['content-type'] && headers['content-type'].includes('json'); | ||
return ((0, utils_1.isString)(payload) && | ||
(0, utils_1.isNonNullObject)(headers) && | ||
headers['content-type'] && | ||
headers['content-type'].includes('json')); | ||
}; | ||
@@ -165,10 +78,10 @@ function scrub(payload, headers, sizeLimit, truncated = false, scrubContext) { | ||
payload = (0, untruncateJson_1.default)(payload); | ||
return (0, exports.payloadStringify)(JSON.parse(payload), sizeLimit, null, truncated, scrubContext); | ||
return (0, exports.payloadStringify)(JSON.parse(payload), scrubContext, sizeLimit, null, truncated); | ||
} | ||
else { | ||
return (0, exports.payloadStringify)(payload, sizeLimit, null, truncated, scrubContext); | ||
return (0, exports.payloadStringify)(payload, scrubContext, sizeLimit, null, truncated); | ||
} | ||
} | ||
catch (e) { | ||
return (0, exports.payloadStringify)(payload, sizeLimit, null, truncated, scrubContext); | ||
return (0, exports.payloadStringify)(payload, scrubContext, sizeLimit, null, truncated); | ||
} | ||
@@ -175,0 +88,0 @@ } |
export * from './httpUtils'; | ||
export * from './generalUtils'; | ||
export * from './functionUtils'; | ||
export { ScrubContext } from './secrets'; | ||
export { scrub, ScrubContext } from './secrets'; | ||
export * from '../utils'; |
@@ -17,3 +17,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ScrubContext = void 0; | ||
exports.ScrubContext = exports.scrub = void 0; | ||
__exportStar(require("./httpUtils"), exports); | ||
@@ -23,4 +23,5 @@ __exportStar(require("./generalUtils"), exports); | ||
var secrets_1 = require("./secrets"); | ||
Object.defineProperty(exports, "scrub", { enumerable: true, get: function () { return secrets_1.scrub; } }); | ||
Object.defineProperty(exports, "ScrubContext", { enumerable: true, get: function () { return secrets_1.ScrubContext; } }); | ||
__exportStar(require("../utils"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -10,16 +10,14 @@ export declare enum ScrubContext { | ||
} | ||
export interface SecretScrubber { | ||
readonly expressions: RegExp[]; | ||
export declare const TRUNCATED_SYMBOL: unique symbol; | ||
export declare const isTruncationSymbol: (x: any) => x is Symbol; | ||
export declare const getTruncatedValue: (x: Symbol) => string | undefined; | ||
export declare const CIRCULAR_REFERENCE_SYMBOL: unique symbol; | ||
export declare type SkipPath = (string | SkipPath)[]; | ||
interface ScrubResult<T> { | ||
scrubbedPayload: T | Symbol; | ||
hasScrubbed: boolean; | ||
hasTruncated: boolean; | ||
} | ||
declare class EnvironmentVariableBasedSecretScrubber implements SecretScrubber { | ||
readonly expressions: RegExp[]; | ||
constructor(overrideEnvVarName?: string); | ||
} | ||
export declare const httpRequestBodiesSecretScrubber: EnvironmentVariableBasedSecretScrubber; | ||
export declare const httpRequestHeadersSecretScrubber: EnvironmentVariableBasedSecretScrubber; | ||
export declare const httpResponseBodiesSecretScrubber: EnvironmentVariableBasedSecretScrubber; | ||
export declare const httpResponseHeadersSecretScrubber: EnvironmentVariableBasedSecretScrubber; | ||
export declare const httpQueryParamsSecretScrubber: EnvironmentVariableBasedSecretScrubber; | ||
export declare const processEnvironmentSecretScrubber: EnvironmentVariableBasedSecretScrubber; | ||
export declare const defaultSecretScrubber: EnvironmentVariableBasedSecretScrubber; | ||
export declare const scrub: (payload: any, scrubContext?: ScrubContext, skipScrubPaths?: SkipPath) => any; | ||
export declare const scrubWithApproximateMaxPayloadSize: (payload: any, maxPayloadCharacterCount?: number, scrubContext?: ScrubContext, skipScrubPaths?: SkipPath) => ScrubResult<string> | ScrubResult<any>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.defaultSecretScrubber = exports.processEnvironmentSecretScrubber = exports.httpQueryParamsSecretScrubber = exports.httpResponseHeadersSecretScrubber = exports.httpResponseBodiesSecretScrubber = exports.httpRequestHeadersSecretScrubber = exports.httpRequestBodiesSecretScrubber = exports.ScrubContext = void 0; | ||
exports.scrubWithApproximateMaxPayloadSize = exports.scrub = exports.CIRCULAR_REFERENCE_SYMBOL = exports.getTruncatedValue = exports.isTruncationSymbol = exports.TRUNCATED_SYMBOL = exports.ScrubContext = void 0; | ||
const logger_1 = require("../logger"); | ||
const utils_1 = require("../utils"); | ||
const utils_2 = require("../utils"); | ||
var ScrubContext; | ||
@@ -16,39 +17,565 @@ (function (ScrubContext) { | ||
})(ScrubContext = exports.ScrubContext || (exports.ScrubContext = {})); | ||
const SCRUBBED_TEXT = '****'; | ||
const SCRUBBING_IN_PROCESS_SYMBOL = Symbol.for('lumigo_scrub_in_progress'); | ||
const SCRUBBING_SYMBOL = Symbol.for('lumigo_scrub'); | ||
const APPROXIMATE_SIZE_SYMBOL = Symbol.for('lumigo_scrub_apprx_size'); | ||
const TRUNCATED_SYMBOL_PREFIX = 'lumigo_truncated'; | ||
exports.TRUNCATED_SYMBOL = Symbol.for(TRUNCATED_SYMBOL_PREFIX); | ||
const createTruncatedSymbol = (x, keepLength) => keepLength > 0 | ||
? Symbol(TRUNCATED_SYMBOL_PREFIX + ':' + x.substring(0, keepLength)) | ||
: exports.TRUNCATED_SYMBOL; | ||
const isTruncationSymbol = (x) => { | ||
var _a; | ||
return (0, utils_2.isSymbol)(x) && (exports.TRUNCATED_SYMBOL === x || ((_a = x.description) === null || _a === void 0 ? void 0 : _a.startsWith('lumigo_truncated:'))); | ||
}; | ||
exports.isTruncationSymbol = isTruncationSymbol; | ||
const getTruncatedValue = (x) => { | ||
if (x === exports.TRUNCATED_SYMBOL) { | ||
return undefined; | ||
} | ||
if ((0, exports.isTruncationSymbol)(x)) { | ||
return x.description.substring(TRUNCATED_SYMBOL_PREFIX.length + 1); | ||
} | ||
}; | ||
exports.getTruncatedValue = getTruncatedValue; | ||
exports.CIRCULAR_REFERENCE_SYMBOL = Symbol.for('lumigo_circular_reference'); | ||
const matchesRegexps = (key, regexes) => { | ||
return !!regexes.some((regex) => regex.test(key)); | ||
}; | ||
const isImmuneFromScrubbing = (value) => typeof value === 'undefined' || value === null || Number.isNaN(value) || (0, utils_2.isBlankString)(value); | ||
const ALLOW_LIST_REGEXPS = (0, utils_2.safeExecute)(() => (0, utils_2.parseJsonFromEnvVar)(utils_2.LUMIGO_WHITELIST_KEYS_REGEXES, true, []).map((regExp) => new RegExp(regExp, 'i')), 'Cannot parse secret-scrubbing allow-list regexps', logger_1.LOG_LEVELS.WARNING, [])(); | ||
const parseExpressions = (overrideEnvVarName) => { | ||
let sourceEnvVar; | ||
if (overrideEnvVarName && process.env[overrideEnvVarName]) { | ||
sourceEnvVar = overrideEnvVarName; | ||
} | ||
else if (process.env[utils_2.LUMIGO_SECRET_MASKING_REGEX]) { | ||
sourceEnvVar = utils_2.LUMIGO_SECRET_MASKING_REGEX; | ||
} | ||
else if (process.env[utils_2.LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP]) { | ||
sourceEnvVar = utils_2.LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP; | ||
} | ||
const regExps = sourceEnvVar ? process.env[sourceEnvVar] : ''; | ||
let expressionStrings = utils_2.OMITTING_KEYS_REGEXES; | ||
if (regExps === utils_2.LUMIGO_SECRET_MASKING_ALL_MAGIC) { | ||
return { | ||
sourceEnvVar, | ||
regExps, | ||
}; | ||
} | ||
else if (regExps) { | ||
try { | ||
expressionStrings = JSON.parse(regExps); | ||
} | ||
catch (err) { | ||
(0, logger_1.getLogger)().warn(`Failed to parse the masking regex: '${regExps}' set in the '${sourceEnvVar}' environment variable; ` + | ||
'it must either be "all" or a stringified JSON array of regular expressions, e.g.: \'["a.*","b.*"]\'. ' + | ||
`Falling back to default: '${utils_2.OMITTING_KEYS_REGEXES}'`); | ||
} | ||
} | ||
try { | ||
return { | ||
sourceEnvVar, | ||
regExps, | ||
expressions: expressionStrings.map((e) => new RegExp(e, 'i')), | ||
}; | ||
} | ||
catch (err) { | ||
(0, logger_1.getLogger)().warn(`Failed to parse the masking regex: '${regExps}' set in the '${sourceEnvVar}' environment variable; ` + | ||
'it must either be "all" or a stringified JSON array of regular expressions, e.g.: \'["a.*","b.*"]\'. ' + | ||
`Falling back to default: '${utils_2.OMITTING_KEYS_REGEXES}'`); | ||
return { | ||
expressions: utils_2.OMITTING_KEYS_REGEXES.map((e) => new RegExp(e, 'i')), | ||
}; | ||
} | ||
}; | ||
const defaultScrubResult = (payload) => ({ | ||
scrubbedPayload: payload, | ||
hasScrubbed: false, | ||
hasTruncated: false, | ||
}); | ||
const getApproximateKeyValuePairSizeAsJSON = (key, value, isParentArray, approximateValueSizeAsJSON) => { | ||
let approximatePayloadSizeAsJSON = approximateValueSizeAsJSON !== undefined | ||
? approximateValueSizeAsJSON | ||
: (0, utils_2.getValueLengthAsJSON)(value); | ||
if (!isParentArray) { | ||
/* | ||
* Key length, double-quotes around key and the colon | ||
* between key and value. | ||
*/ | ||
approximatePayloadSizeAsJSON += key.length + 3; | ||
} | ||
return approximatePayloadSizeAsJSON; | ||
}; | ||
class EnvironmentVariableBasedSecretScrubber { | ||
constructor(overrideEnvVarName) { | ||
let sourceEnvVar; | ||
if (overrideEnvVarName && process.env[overrideEnvVarName]) { | ||
sourceEnvVar = overrideEnvVarName; | ||
const { expressions, regExps } = (0, utils_2.safeExecute)(() => parseExpressions(overrideEnvVarName), `Cannot parse '${overrideEnvVarName}' secret scrubbing settings`, logger_1.LOG_LEVELS.WARNING)(); | ||
this.expressions = expressions; | ||
this.regExps = regExps; | ||
} | ||
scrub(payload, skipScrubPath = [], maxScrubbedPayloadAsJSONCharacterCount = Number.MAX_VALUE) { | ||
if (this.regExps === utils_2.LUMIGO_SECRET_MASKING_ALL_MAGIC) { | ||
return isImmuneFromScrubbing(payload) | ||
? defaultScrubResult(payload) | ||
: { | ||
scrubbedPayload: SCRUBBED_TEXT, | ||
hasScrubbed: true, | ||
hasTruncated: false, | ||
}; | ||
} | ||
else if (process.env[utils_1.LUMIGO_SECRET_MASKING_REGEX]) { | ||
sourceEnvVar = utils_1.LUMIGO_SECRET_MASKING_REGEX; | ||
if ((0, utils_2.isPrimitiveType)(payload) || isImmuneFromScrubbing(payload)) { | ||
/* | ||
* We never scrub numbers, strings, etc that are not nested in an object | ||
* unless LUMIGO_SECRET_MASKING_ALL_MAGIC is set. | ||
*/ | ||
if ((0, utils_1.isString)(payload) && payload.length > maxScrubbedPayloadAsJSONCharacterCount + 2) { | ||
return { | ||
scrubbedPayload: createTruncatedSymbol(payload, maxScrubbedPayloadAsJSONCharacterCount - 2), | ||
hasScrubbed: false, | ||
hasTruncated: true, | ||
}; | ||
} | ||
return defaultScrubResult(payload); | ||
} | ||
else if (process.env[utils_1.LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP]) { | ||
sourceEnvVar = utils_1.LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP; | ||
return (0, utils_2.safeExecute)(() => { | ||
const seenFrozenReferences = new Map(); | ||
const isPayloadFrozen = Object.isFrozen(payload); | ||
const touchedObjects = new Array(); | ||
/* | ||
* Ensure the payload is marked as being scrubbed, this ensure we detect | ||
* circular references early. | ||
*/ | ||
if (isPayloadFrozen) { | ||
seenFrozenReferences.set(payload, { ref: SCRUBBING_IN_PROCESS_SYMBOL }); | ||
} | ||
else { | ||
payload[SCRUBBING_SYMBOL] = SCRUBBING_IN_PROCESS_SYMBOL; | ||
touchedObjects.push(payload); | ||
} | ||
const { scrubbedPayload, hasScrubbed, hasTruncated, circularReferences, touchedObjects: nestedTouchedObjects, } = this.doScrubObject(payload, seenFrozenReferences, skipScrubPath, maxScrubbedPayloadAsJSONCharacterCount); | ||
if (nestedTouchedObjects === null || nestedTouchedObjects === void 0 ? void 0 : nestedTouchedObjects.length) { | ||
touchedObjects.push(...nestedTouchedObjects); | ||
} | ||
/* | ||
* There is at least one modification that has to be applied somewhere, let's | ||
* clean after ourselves. | ||
*/ | ||
circularReferences === null || circularReferences === void 0 ? void 0 : circularReferences.forEach(({ targetObject, targetKey }) => { | ||
if (!Object.isFrozen(targetObject)) { | ||
targetObject[targetKey] = exports.CIRCULAR_REFERENCE_SYMBOL; | ||
/* | ||
* We are no using the valueToReplace, so we need to clean up the markers | ||
* on the original object. | ||
*/ | ||
delete targetObject[SCRUBBING_SYMBOL]; | ||
delete targetObject[APPROXIMATE_SIZE_SYMBOL]; | ||
} | ||
}); | ||
/* | ||
* Restore the freeziness of objects as it was in the original | ||
* payload. | ||
*/ | ||
for (const { ref } of seenFrozenReferences.values()) { | ||
/* | ||
* Frozen replacements in circular dependencies are | ||
* likely to have our symbols, we must scrub them before | ||
* freezing. | ||
*/ | ||
delete ref[SCRUBBING_SYMBOL]; | ||
delete ref[APPROXIMATE_SIZE_SYMBOL]; | ||
Object.freeze(ref); | ||
} | ||
touchedObjects === null || touchedObjects === void 0 ? void 0 : touchedObjects.forEach((o) => { | ||
delete o[SCRUBBING_SYMBOL]; | ||
delete o[APPROXIMATE_SIZE_SYMBOL]; | ||
}); | ||
return { | ||
scrubbedPayload, | ||
hasScrubbed, | ||
hasTruncated, | ||
}; | ||
}, 'Cannot scrub payload', logger_1.LOG_LEVELS.WARNING, defaultScrubResult(payload))(); | ||
} | ||
doScrubObject(payload, | ||
/* | ||
* For frozen objects we cannot keep references by adding a property | ||
* to them, so we have to keep the reference outside in a less efficient map. | ||
*/ | ||
seenFrozenReferences, skipScrubPath = [], approximateScrubbedPayloadSizeAsJSONBudget) { | ||
var _a, _b; | ||
if (approximateScrubbedPayloadSizeAsJSONBudget < 1) { | ||
/* | ||
* No way we can do anything here | ||
*/ | ||
return { | ||
approximatePayloadSize: 0, | ||
hasScrubbed: false, | ||
hasTruncated: true, | ||
scrubbedPayload: exports.TRUNCATED_SYMBOL, | ||
}; | ||
} | ||
const regExps = sourceEnvVar ? process.env[sourceEnvVar] : ''; | ||
let expressionStrings = utils_1.OMITTING_KEYS_REGEXES; | ||
if (regExps === utils_1.LUMIGO_SECRET_MASKING_ALL_MAGIC) { | ||
expressionStrings = ['.*']; | ||
let touchedObjects = null; | ||
function queueTouchedObjects(...refs) { | ||
if (!touchedObjects) { | ||
touchedObjects = [...refs]; | ||
} | ||
else { | ||
touchedObjects.push(...refs); | ||
} | ||
} | ||
else if (regExps) { | ||
/* | ||
* We initialize these lazily. We should avoid allocate empty arrays | ||
* on hot code paths. | ||
*/ | ||
let circularReferences = null; | ||
function queueCircularReferences(...refs) { | ||
if (!circularReferences) { | ||
circularReferences = [...refs]; | ||
} | ||
else { | ||
circularReferences.push(...refs); | ||
} | ||
} | ||
let hasScrubbed = false; | ||
let hasTruncated = false; | ||
let approximatePayloadSizeAsJSON = 2; // Either square or curly brackets | ||
/* | ||
* Lazy-initialized array containing keys and values we need to change, e.g., | ||
* | ||
* [key1, value1, key2, value2, ...] | ||
*/ | ||
let modifiedKeysToNewValues; | ||
function queueModifiedKey(key, value, approximateValueSize, canTruncate = true) { | ||
if (!modifiedKeysToNewValues) { | ||
modifiedKeysToNewValues = {}; | ||
} | ||
if (!canTruncate || (0, exports.isTruncationSymbol)(value)) { | ||
approximatePayloadSizeAsJSON = approximateScrubbedPayloadSizeAsJSONBudget; | ||
modifiedKeysToNewValues[key] = value; | ||
hasTruncated = true; | ||
} | ||
else { | ||
const approximateKeyValuePairSizeAsJSON = getApproximateKeyValuePairSizeAsJSON(key, value, isPayloadArray, approximateValueSize); | ||
if (canTruncate && | ||
approximatePayloadSizeAsJSON + approximateKeyValuePairSizeAsJSON > | ||
approximateScrubbedPayloadSizeAsJSONBudget) { | ||
const valueSizeAsJSON = (0, utils_2.getValueLengthAsJSON)(value); | ||
const keyAndAccessoriesLength = approximateKeyValuePairSizeAsJSON - valueSizeAsJSON; | ||
modifiedKeysToNewValues[key] = (0, utils_1.isString)(value) | ||
? createTruncatedSymbol(value, approximateScrubbedPayloadSizeAsJSONBudget - | ||
approximatePayloadSizeAsJSON - | ||
keyAndAccessoriesLength) | ||
: exports.TRUNCATED_SYMBOL; | ||
approximatePayloadSizeAsJSON = approximateScrubbedPayloadSizeAsJSONBudget; | ||
hasTruncated = true; | ||
} | ||
else { | ||
hasScrubbed = true; | ||
modifiedKeysToNewValues[key] = value; | ||
approximatePayloadSizeAsJSON += approximateKeyValuePairSizeAsJSON; | ||
} | ||
} | ||
} | ||
function truncateKeyValueIfNecessary(key, value) { | ||
const approximateKeyValuePairSizeAsJSON = getApproximateKeyValuePairSizeAsJSON(key, value, isPayloadArray); | ||
if (!(0, utils_2.isSymbol)(value) && | ||
approximatePayloadSizeAsJSON + approximateKeyValuePairSizeAsJSON > | ||
approximateScrubbedPayloadSizeAsJSONBudget) { | ||
queueModifiedKey(key, value); | ||
} | ||
else { | ||
approximatePayloadSizeAsJSON += approximateKeyValuePairSizeAsJSON; | ||
} | ||
} | ||
/* | ||
* Errors in Node are special, and the `message` and `stack` properties | ||
* are not yielded by the `Object.getOwnPropertyNames` that is used as | ||
* iterator by `for(const key in ...)`. | ||
*/ | ||
let objectToIterateOn; | ||
if (payload instanceof Error) { | ||
/* | ||
* Prioritize message and stack, in this order, as those values are | ||
* generally more useful to the end user. We might end up assigning | ||
* message and/or stack twice, but it is anyhow faster than using a | ||
* set, and it preserves the order | ||
*/ | ||
objectToIterateOn = {}; | ||
['message', 'stack', ...Object.getOwnPropertyNames(payload)].forEach((propertyName) => { | ||
objectToIterateOn[propertyName] = payload[propertyName]; | ||
}); | ||
} | ||
else { | ||
objectToIterateOn = payload; | ||
} | ||
/* | ||
* Keep track of the last processed key, so that if we need to create a | ||
* new object to return AND we need to truncate, we can spare ourselves | ||
* from recalculating the approximate size. | ||
*/ | ||
let lastProcessedKey; | ||
const isPayloadArray = Array.isArray(payload); | ||
/* | ||
* The iteration order must be repeatable, so that we can construct the | ||
* the current scrubbedPayload when truncating. | ||
*/ | ||
for (const key in objectToIterateOn) { | ||
if (hasTruncated) { | ||
/* | ||
* Check that the previous key does not also point to a truncation marker, | ||
* i.e., the truncation did not occur directly at the value of the previous | ||
* key. | ||
*/ | ||
const lastProcessedValue = modifiedKeysToNewValues === null || modifiedKeysToNewValues === void 0 ? void 0 : modifiedKeysToNewValues[lastProcessedKey]; | ||
if (lastProcessedValue != exports.CIRCULAR_REFERENCE_SYMBOL && | ||
!(0, exports.isTruncationSymbol)(lastProcessedValue)) { | ||
/* | ||
* The last key we processed, where truncation occurred, was not the last | ||
* key: add a truncation marker as the next item. | ||
*/ | ||
queueModifiedKey(key, exports.TRUNCATED_SYMBOL, 0, false); | ||
lastProcessedKey = key; | ||
} | ||
break; | ||
} | ||
if (lastProcessedKey) { | ||
/* | ||
* This is not the first key we process, the JSON will have an addional | ||
* comma before this key. | ||
*/ | ||
approximatePayloadSizeAsJSON += 1; | ||
} | ||
lastProcessedKey = key; | ||
const value = payload[key]; | ||
const valueLengthAsJSON = (0, utils_2.getValueLengthAsJSON)(value); | ||
if (isImmuneFromScrubbing(value)) { | ||
/* | ||
* No scrubbing needed on this key | ||
*/ | ||
truncateKeyValueIfNecessary(key, value); | ||
continue; | ||
} | ||
if (value === payload) { | ||
/* | ||
* A circular reference involving the payload refering itself | ||
* as a property value? Oh my stars! | ||
* | ||
* We do not increase the approximatePayloadSizeAsJSON, the | ||
* reference we set will be replaced. | ||
*/ | ||
queueModifiedKey(key, exports.CIRCULAR_REFERENCE_SYMBOL); | ||
continue; | ||
} | ||
let isKeyOnSkipPath = false; | ||
if (skipScrubPath === null || skipScrubPath === void 0 ? void 0 : skipScrubPath.length) { | ||
if (Array.isArray(skipScrubPath[0])) { | ||
isKeyOnSkipPath = Array.isArray(payload); | ||
} | ||
else { | ||
isKeyOnSkipPath = skipScrubPath[0] === key; | ||
} | ||
} | ||
const shouldScrubKey = !isKeyOnSkipPath && | ||
!matchesRegexps(key, ALLOW_LIST_REGEXPS) && | ||
matchesRegexps(key, this.expressions); | ||
if (shouldScrubKey) { | ||
queueModifiedKey(key, SCRUBBED_TEXT); | ||
hasScrubbed = true; | ||
continue; | ||
} | ||
if (approximateScrubbedPayloadSizeAsJSONBudget < | ||
approximatePayloadSizeAsJSON + valueLengthAsJSON) { | ||
/* | ||
* We ran out of juice, time to wrap up. To ensure we do not export | ||
* in the scrubbedPayload data we have not scrubbed due to truncation, | ||
* we mark this key as one to have undefined value or the truncation mark, | ||
* depending on the settings. | ||
*/ | ||
truncateKeyValueIfNecessary(key, value); | ||
break; | ||
} | ||
if ((0, utils_2.isPrimitiveType)(value)) { | ||
truncateKeyValueIfNecessary(key, value); | ||
continue; | ||
} | ||
/* | ||
* Value is a complex object with fields | ||
*/ | ||
const isValueFrozen = Object.isFrozen(value); | ||
const seenReference = isValueFrozen | ||
? (_a = seenFrozenReferences.get(value)) === null || _a === void 0 ? void 0 : _a.ref | ||
: value[SCRUBBING_SYMBOL]; | ||
if (seenReference === SCRUBBING_IN_PROCESS_SYMBOL) { | ||
/* | ||
* This is a circular reference we are handling at a previous | ||
* recursion level. | ||
*/ | ||
const circularReference = { | ||
targetObject: payload, | ||
targetKey: key, | ||
valueToReplace: value, | ||
}; | ||
queueCircularReferences(circularReference); | ||
/* | ||
* For simplicity, we are counting the circular reference as | ||
* an unnmodified key using the Symbol for the sake of payload | ||
* size estimation. | ||
*/ | ||
truncateKeyValueIfNecessary(key, exports.CIRCULAR_REFERENCE_SYMBOL); | ||
continue; | ||
} | ||
if (seenReference) { | ||
/* | ||
* It's a reference we have seen before AND it is not a circular | ||
* reference being processed. We reuse the scrubbed value we | ||
* produced before. | ||
*/ | ||
queueModifiedKey(key, seenReference, isValueFrozen | ||
? seenFrozenReferences.get(value).approximateSize | ||
: parseInt(value[APPROXIMATE_SIZE_SYMBOL])); | ||
continue; | ||
} | ||
/* | ||
* No scrub marker yet, it's the first time we encounter this value. | ||
* We need to mark the object as being scrubbed and recursively scrub | ||
* its keys. | ||
*/ | ||
if (isValueFrozen) { | ||
seenFrozenReferences.set(value, { ref: SCRUBBING_IN_PROCESS_SYMBOL }); | ||
} | ||
else { | ||
value[SCRUBBING_SYMBOL] = SCRUBBING_IN_PROCESS_SYMBOL; | ||
queueTouchedObjects(value); | ||
} | ||
let nextLevelScrubPath = []; | ||
try { | ||
expressionStrings = JSON.parse(regExps); | ||
if (isKeyOnSkipPath && (skipScrubPath === null || skipScrubPath === void 0 ? void 0 : skipScrubPath.length)) { | ||
nextLevelScrubPath = skipScrubPath.slice(1); | ||
} | ||
} | ||
catch (err) { | ||
(0, logger_1.getLogger)().warn(`Failed to parse the masking regex: '${regExps}' set in the '${sourceEnvVar}' environment variable; ` + | ||
'it must either be "all" or a stringified JSON array of regular expressions, e.g.: \'["a.*","b.*"]\'. ' + | ||
`Falling back to default: '${utils_1.OMITTING_KEYS_REGEXES}'`); | ||
(0, logger_1.getLogger)().warn('Failed to find items to skip scrubbing'); | ||
} | ||
const { scrubbedPayload: scrubbedValue, hasScrubbed: wasValueScrubbed, hasTruncated: wasValueTruncated, circularReferences: nextLevelCircularReferences, touchedObjects: nextLevelTouchedObjects, approximatePayloadSize: nextLevelApproximatePayloadSize, } = this.doScrubObject(value, seenFrozenReferences, nextLevelScrubPath, approximateScrubbedPayloadSizeAsJSONBudget - approximatePayloadSizeAsJSON); | ||
if (value !== scrubbedValue) { | ||
queueModifiedKey(key, scrubbedValue, nextLevelApproximatePayloadSize, !wasValueTruncated); | ||
} | ||
hasScrubbed || (hasScrubbed = wasValueScrubbed); | ||
hasTruncated || (hasTruncated = wasValueTruncated); | ||
if (isValueFrozen) { | ||
seenFrozenReferences.set(value, { | ||
ref: scrubbedValue, | ||
approximateSize: nextLevelApproximatePayloadSize, | ||
}); | ||
} | ||
else { | ||
value[SCRUBBING_SYMBOL] = scrubbedValue; | ||
value[APPROXIMATE_SIZE_SYMBOL] = nextLevelApproximatePayloadSize; | ||
} | ||
if (nextLevelTouchedObjects === null || nextLevelTouchedObjects === void 0 ? void 0 : nextLevelTouchedObjects.length) { | ||
queueTouchedObjects(...nextLevelTouchedObjects); | ||
} | ||
if (nextLevelCircularReferences === null || nextLevelCircularReferences === void 0 ? void 0 : nextLevelCircularReferences.length) { | ||
queueCircularReferences(...nextLevelCircularReferences); | ||
} | ||
approximatePayloadSizeAsJSON += nextLevelApproximatePayloadSize; | ||
} | ||
this.expressions = expressionStrings.map((e) => new RegExp(e, 'i')); | ||
const isPayloadFrozen = Object.isFrozen(payload); | ||
const seenPayloadReference = isPayloadFrozen | ||
? (_b = seenFrozenReferences.get(payload)) === null || _b === void 0 ? void 0 : _b.ref | ||
: payload[SCRUBBING_SYMBOL]; | ||
const isPayloadACircularReference = seenPayloadReference === SCRUBBING_IN_PROCESS_SYMBOL; | ||
const createNewScrubbedPayload = !!modifiedKeysToNewValues || // There are modified values | ||
hasTruncated || | ||
/* | ||
* Objects with circular references need to be replaced, | ||
* otherwise we cannot ensure that scrubbed versions are | ||
* being returned. However, if the payload is itself a | ||
* circular reference, if we replace it we will 'unroll' | ||
* one level of the circular dependency because of the | ||
* scrubbed-payload substitution. | ||
*/ | ||
(!!(circularReferences === null || circularReferences === void 0 ? void 0 : circularReferences.length) && !isPayloadACircularReference) || | ||
/* | ||
* Errors are special: to ensure we can payloadStringify them, | ||
* we need to return a new object. | ||
*/ | ||
(0, utils_2.isError)(payload); | ||
let returnedPayload = payload; | ||
if (createNewScrubbedPayload) { | ||
returnedPayload = (isPayloadArray ? [] : {}); | ||
if (isPayloadArray) { | ||
const res = new Array(); | ||
for (let i = 0, l = payload.length; i < l; ++i) { | ||
res[i] = (modifiedKeysToNewValues === null || modifiedKeysToNewValues === void 0 ? void 0 : modifiedKeysToNewValues[i]) || payload[i]; | ||
if (i.toString() == lastProcessedKey) { | ||
/* | ||
* Truncation occurred after this key was set, or we were anyhow at the end | ||
* of the keys | ||
*/ | ||
break; | ||
} | ||
} | ||
returnedPayload = res; | ||
} | ||
else { | ||
returnedPayload = {}; | ||
for (const key in objectToIterateOn) { | ||
returnedPayload[key] = (modifiedKeysToNewValues === null || modifiedKeysToNewValues === void 0 ? void 0 : modifiedKeysToNewValues[key]) || payload[key]; | ||
if (key == lastProcessedKey) { | ||
/* | ||
* Truncation occurred after this key was set, or we were anyhow at the end | ||
* of the keys. | ||
*/ | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
return { | ||
/* | ||
* If we did not modify the payload, just return it. | ||
* This helps reducing overhead with circular references. | ||
* | ||
* Errors are treaded specially by JSON.stringify, so we need | ||
* to return our copy even if we did not scrub. | ||
*/ | ||
scrubbedPayload: returnedPayload, | ||
hasScrubbed, | ||
hasTruncated, | ||
approximatePayloadSize: approximatePayloadSizeAsJSON, | ||
circularReferences, | ||
touchedObjects, | ||
}; | ||
} | ||
} | ||
exports.httpRequestBodiesSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_1.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_BODIES); | ||
exports.httpRequestHeadersSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_1.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_HEADERS); | ||
exports.httpResponseBodiesSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_1.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_BODIES); | ||
exports.httpResponseHeadersSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_1.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_HEADERS); | ||
exports.httpQueryParamsSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_1.LUMIGO_SECRET_MASKING_REGEX_HTTP_QUERY_PARAMS); | ||
exports.processEnvironmentSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_1.LUMIGO_SECRET_MASKING_REGEX_ENVIRONMENT); | ||
exports.defaultSecretScrubber = new EnvironmentVariableBasedSecretScrubber(); | ||
const httpRequestBodiesSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_2.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_BODIES); | ||
const httpRequestHeadersSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_2.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_HEADERS); | ||
const httpResponseBodiesSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_2.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_BODIES); | ||
const httpResponseHeadersSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_2.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_HEADERS); | ||
const httpQueryParamsSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_2.LUMIGO_SECRET_MASKING_REGEX_HTTP_QUERY_PARAMS); | ||
const processEnvironmentSecretScrubber = new EnvironmentVariableBasedSecretScrubber(utils_2.LUMIGO_SECRET_MASKING_REGEX_ENVIRONMENT); | ||
const defaultSecretScrubber = new EnvironmentVariableBasedSecretScrubber(); | ||
const getSecretScrubber = (scrubContext) => { | ||
switch (scrubContext) { | ||
case ScrubContext.HTTP_REQUEST_BODY: | ||
return httpRequestBodiesSecretScrubber; | ||
case ScrubContext.HTTP_REQUEST_HEADERS: | ||
return httpRequestHeadersSecretScrubber; | ||
case ScrubContext.HTTP_REQUEST_QUERY: | ||
return httpQueryParamsSecretScrubber; | ||
case ScrubContext.HTTP_RESPONSE_BODY: | ||
return httpResponseBodiesSecretScrubber; | ||
case ScrubContext.HTTP_RESPONSE_HEADERS: | ||
return httpResponseHeadersSecretScrubber; | ||
case ScrubContext.PROCESS_ENVIRONMENT: | ||
return processEnvironmentSecretScrubber; | ||
default: | ||
return defaultSecretScrubber; | ||
} | ||
}; | ||
const scrub = (payload, scrubContext = ScrubContext.DEFAULT, skipScrubPaths) => { var _a; return (_a = getSecretScrubber(scrubContext).scrub(payload, skipScrubPaths)) === null || _a === void 0 ? void 0 : _a.scrubbedPayload; }; | ||
exports.scrub = scrub; | ||
const scrubWithApproximateMaxPayloadSize = (payload, maxPayloadCharacterCount, scrubContext = ScrubContext.DEFAULT, skipScrubPaths) => getSecretScrubber(scrubContext).scrub(payload, skipScrubPaths, maxPayloadCharacterCount); | ||
exports.scrubWithApproximateMaxPayloadSize = scrubWithApproximateMaxPayloadSize; | ||
//# sourceMappingURL=secrets.js.map |
export * as Logger from './logger'; | ||
export * as CommonUtils from './common'; | ||
export { payloadStringify, scrub, ScrubContext } from './common'; | ||
export * as Types from './types'; | ||
export * as Triggers from './common/triggers'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Triggers = exports.Types = exports.CommonUtils = exports.Logger = void 0; | ||
exports.Triggers = exports.Types = exports.ScrubContext = exports.scrub = exports.payloadStringify = exports.CommonUtils = exports.Logger = void 0; | ||
exports.Logger = require("./logger"); | ||
exports.CommonUtils = require("./common"); | ||
// We consume these functions a lot, expose them as top-level items | ||
var common_1 = require("./common"); | ||
Object.defineProperty(exports, "payloadStringify", { enumerable: true, get: function () { return common_1.payloadStringify; } }); | ||
Object.defineProperty(exports, "scrub", { enumerable: true, get: function () { return common_1.scrub; } }); | ||
Object.defineProperty(exports, "ScrubContext", { enumerable: true, get: function () { return common_1.ScrubContext; } }); | ||
exports.Types = require("./types"); | ||
exports.Triggers = require("./common/triggers"); | ||
//# sourceMappingURL=index.js.map |
@@ -17,3 +17,3 @@ "use strict"; | ||
return (key, value) => { | ||
if (typeof value === 'object' && value !== null) { | ||
if ((0, utils_1.isNonNullObject)(value)) { | ||
// Duplicate reference found, discard key | ||
@@ -20,0 +20,0 @@ if (cache.includes(value)) |
@@ -12,3 +12,10 @@ export declare const LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP = "LUMIGO_BLACKLIST_REGEX"; | ||
export declare const OMITTING_KEYS_REGEXES: string[]; | ||
export declare function isString(x: any): x is string; | ||
export declare const DEFAULT_LUMIGO_MAX_ENTRY_SIZE = 2048; | ||
export declare const isPrimitiveType: (obj: any) => boolean; | ||
export declare const getValueLengthAsJSON: (obj: any, isParentArray?: boolean) => any; | ||
export declare const isError: (x: any) => x is Error; | ||
export declare const isBlankString: (x: any) => x is string; | ||
export declare const isNonNullObject: (x: any) => x is Object; | ||
export declare const isString: (x: any) => x is string; | ||
export declare const isSymbol: (x: any) => x is Symbol; | ||
export declare const isStoreLogs: () => boolean; | ||
@@ -20,5 +27,4 @@ export declare const setStoreLogsOn: () => string; | ||
export declare const isWarm: () => boolean; | ||
export declare const LUMIGO_MAX_ENTRY_SIZE = 2048; | ||
export declare const getEventEntitySize: (hasError?: boolean) => number; | ||
export declare const parseJsonFromEnvVar: (envVar: any, warnClient?: boolean, defaultReturnValue?: any) => any; | ||
export declare const parseJsonFromEnvVar: (envVar: string, warnClient?: boolean, defaultReturnValue?: any) => any; | ||
export declare function safeExecute<T>(callback: Function, message?: string, logLevel?: import("./logger").LogSeverity, defaultReturn?: T): Function; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.safeExecute = exports.parseJsonFromEnvVar = exports.getEventEntitySize = exports.LUMIGO_MAX_ENTRY_SIZE = exports.isWarm = exports.setWarm = exports.setDebug = exports.isDebug = exports.setStoreLogsOn = exports.isStoreLogs = exports.isString = exports.OMITTING_KEYS_REGEXES = exports.LUMIGO_WHITELIST_KEYS_REGEXES = exports.LUMIGO_SECRET_MASKING_ALL_MAGIC = exports.LUMIGO_SECRET_MASKING_REGEX_ENVIRONMENT = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_QUERY_PARAMS = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_HEADERS = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_BODIES = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_HEADERS = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_BODIES = exports.LUMIGO_SECRET_MASKING_REGEX = exports.LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP = void 0; | ||
exports.safeExecute = exports.parseJsonFromEnvVar = exports.getEventEntitySize = exports.isWarm = exports.setWarm = exports.setDebug = exports.isDebug = exports.setStoreLogsOn = exports.isStoreLogs = exports.isSymbol = exports.isString = exports.isNonNullObject = exports.isBlankString = exports.isError = exports.getValueLengthAsJSON = exports.isPrimitiveType = exports.DEFAULT_LUMIGO_MAX_ENTRY_SIZE = exports.OMITTING_KEYS_REGEXES = exports.LUMIGO_WHITELIST_KEYS_REGEXES = exports.LUMIGO_SECRET_MASKING_ALL_MAGIC = exports.LUMIGO_SECRET_MASKING_REGEX_ENVIRONMENT = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_QUERY_PARAMS = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_HEADERS = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_RESPONSE_BODIES = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_HEADERS = exports.LUMIGO_SECRET_MASKING_REGEX_HTTP_REQUEST_BODIES = exports.LUMIGO_SECRET_MASKING_REGEX = exports.LUMIGO_SECRET_MASKING_REGEX_BACKWARD_COMP = void 0; | ||
const logger_1 = require("./logger"); | ||
@@ -31,6 +31,42 @@ const DEBUG_FLAG = 'LUMIGO_DEBUG'; | ||
]; | ||
function isString(x) { | ||
return Object.prototype.toString.call(x) === '[object String]'; | ||
} | ||
exports.DEFAULT_LUMIGO_MAX_ENTRY_SIZE = 2048; | ||
const nativeTypes = ['bigint', 'boolean', 'number', 'null', 'string', 'symbol', 'undefined']; | ||
const isPrimitiveType = (obj) => nativeTypes.includes(typeof obj); | ||
exports.isPrimitiveType = isPrimitiveType; | ||
const getValueLengthAsJSON = (obj, isParentArray = false) => { | ||
/* | ||
* Keep this function ordered by most recurring objects first | ||
*/ | ||
if (obj === null || obj === undefined) { | ||
return 4; // Will be converted to 'null' | ||
} | ||
switch (typeof obj) { | ||
case 'string': | ||
return obj.length + 2; | ||
case 'object': { | ||
return (obj.toJSON ? obj.toJSON() : String(obj)).length; | ||
} | ||
case 'undefined': // undefined is not serialized to 'null' as JSON if in array, and skipped if in object | ||
case 'number': { | ||
if (!Number.isFinite(obj) || Number.isNaN(obj)) { | ||
return 4; // Infinite and NaN are always converted to 'null' | ||
} | ||
return String(obj).length; | ||
} | ||
case 'function': // Functions are not serialized to 'null' as JSON if in array, and skipped if in object | ||
case 'symbol': | ||
return (isParentArray && 4) || 0; // Symbols are not serialized by JSON.stringify | ||
} | ||
}; | ||
exports.getValueLengthAsJSON = getValueLengthAsJSON; | ||
const isError = (x) => x instanceof Error; | ||
exports.isError = isError; | ||
const isBlankString = (x) => (0, exports.isString)(x) && !x.trim(); | ||
exports.isBlankString = isBlankString; | ||
const isNonNullObject = (x) => typeof x === 'object' && x !== null; | ||
exports.isNonNullObject = isNonNullObject; | ||
const isString = (x) => typeof x === 'string'; | ||
exports.isString = isString; | ||
const isSymbol = (x) => typeof x === 'symbol'; | ||
exports.isSymbol = isSymbol; | ||
const isStoreLogs = () => validateEnvVar(STORE_LOGS_FLAG); | ||
@@ -43,3 +79,3 @@ exports.isStoreLogs = isStoreLogs; | ||
exports.isDebug = isDebug; | ||
const setDebug = () => (process.env['LUMIGO_DEBUG'] = 'TRUE'); | ||
const setDebug = () => (process.env[DEBUG_FLAG] = 'TRUE'); | ||
exports.setDebug = setDebug; | ||
@@ -50,7 +86,9 @@ const setWarm = () => (process.env[WARM_FLAG] = 'TRUE'); | ||
exports.isWarm = isWarm; | ||
exports.LUMIGO_MAX_ENTRY_SIZE = 2048; | ||
const getEventEntitySize = (hasError = false) => { | ||
const basicSize = parseInt(process.env['MAX_EVENT_ENTITY_SIZE']) || | ||
parseInt(process.env['LUMIGO_MAX_ENTRY_SIZE']) || | ||
exports.LUMIGO_MAX_ENTRY_SIZE; | ||
let basicSize = parseInt(process.env['MAX_EVENT_ENTITY_SIZE']) || | ||
parseInt(process.env['LUMIGO_MAX_ENTRY_SIZE']); | ||
if (Number.isNaN(basicSize)) { | ||
(0, logger_1.getLogger)().warn('Cannot look up max event size'); | ||
basicSize = exports.DEFAULT_LUMIGO_MAX_ENTRY_SIZE; | ||
} | ||
if (hasError) { | ||
@@ -64,3 +102,6 @@ return basicSize * 2; | ||
try { | ||
return JSON.parse(process.env[envVar]); | ||
const val = process.env[envVar]; | ||
if (val) { | ||
return JSON.parse(val); | ||
} | ||
} | ||
@@ -73,3 +114,3 @@ catch (e) { | ||
exports.parseJsonFromEnvVar = parseJsonFromEnvVar; | ||
function safeExecute(callback, message = 'Error in Lumigo tracer', logLevel = (0, logger_1.getLogger)().LOG_LEVELS.WARNING, defaultReturn = undefined) { | ||
function safeExecute(callback, message = 'Error in Lumigo tracer', logLevel = (0, logger_1.getLogger)().LOG_LEVELS.WARNING, defaultReturn) { | ||
return function (...args) { | ||
@@ -76,0 +117,0 @@ try { |
{ | ||
"name": "@lumigo/node-core", | ||
"version": "1.13.1", | ||
"version": "1.14.0", | ||
"description": "Lumigo core node sdk", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
241989
2290
14