fast-redact
Advanced tools
Comparing version 2.0.0 to 2.1.0
'use strict' | ||
const bench = require('fastbench') | ||
const noir = require('pino-noir')(['a.b.c']) | ||
const fastRedact = require('..') | ||
const redactNoSerialize = fastRedact({ paths: ['a.b.c'], serialize: false }) | ||
const redactWildNoSerialize = fastRedact({ paths: ['a.b.*'], serialize: false }) | ||
const redactIntermediateWildNoSerialize = fastRedact({ paths: ['a.*.c'], serialize: false }) | ||
const redact = fastRedact({ paths: ['a.b.c'] }) | ||
const noirWild = require('pino-noir')(['a.b.*']) | ||
const redactWild = fastRedact({ paths: ['a.b.*'] }) | ||
const redactIntermediateWild = fastRedact({ paths: ['a.*.c'] }) | ||
const redactIntermediateWildMatchWildOutcome = fastRedact({ paths: ['a.*.c', 'a.*.b', 'a.*.a'] }) | ||
const redactStaticMatchWildOutcome = fastRedact({ paths: ['a.b.c', 'a.d.a', 'a.d.b', 'a.d.c'] }) | ||
const noirCensorFunction = require('pino-noir')(['a.b.*'], (v) => v + '.') | ||
const redactCensorFunction = fastRedact({ paths: ['a.b.*'], censor: (v) => v + '.', serialize: false }) | ||
const obj = { | ||
a: { | ||
const censorFn = (v) => v + '.' | ||
const censorFnWithPath = (v, p) => v + '.' + p | ||
const noir = require('pino-noir')(['aa.b.c']) | ||
const redactNoSerialize = fastRedact({ paths: ['ab.b.c'], serialize: false }) | ||
const redactNoSerializeRestore = fastRedact({ paths: ['ac.b.c'], serialize: false }) | ||
const noirWild = require('pino-noir')(['ad.b.*']) | ||
const redactWildNoSerialize = fastRedact({ paths: ['ae.b.*'], serialize: false }) | ||
const redactWildNoSerializeRestore = fastRedact({ paths: ['af.b.*'], serialize: false }) | ||
const redactIntermediateWildNoSerialize = fastRedact({ paths: ['ag.*.c'], serialize: false }) | ||
const redactIntermediateWildNoSerializeRestore = fastRedact({ paths: ['ah.*.c'], serialize: false }) | ||
const noirJSONSerialize = require('pino-noir')(['aj.b.c']) // `ai` used in pure JSON test. | ||
const redact = fastRedact({ paths: ['ak.b.c'] }) | ||
const noirWildJSONSerialize = require('pino-noir')(['al.b.c']) | ||
const redactWild = fastRedact({ paths: ['am.b.*'] }) | ||
const redactIntermediateWild = fastRedact({ paths: ['an.*.c'] }) | ||
const redactIntermediateWildMatchWildOutcome = fastRedact({ paths: ['ao.*.c', 'ao.*.b', 'ao.*.a'] }) | ||
const redactStaticMatchWildOutcome = fastRedact({ paths: ['ap.b.c', 'ap.d.a', 'ap.d.b', 'ap.d.c'] }) | ||
const noirCensorFunction = require('pino-noir')(['aq.b.*'], censorFn) | ||
const redactCensorFunction = fastRedact({ paths: ['ar.b.*'], censor: censorFn, serialize: false }) | ||
const redactIntermediateWildCensorFunction = fastRedact({ paths: ['as.*.c'], censor: censorFn, serialize: false }) | ||
const redactCensorFunctionWithPath = fastRedact({ paths: ['at.d.b'], censor: censorFn, serialize: false }) | ||
const redactWildCensorFunctionWithPath = fastRedact({ paths: ['au.d.*'], censor: censorFnWithPath, serialize: false }) | ||
const redactIntermediateWildCensorFunctionWithPath = fastRedact({ paths: ['av.*.c'], censorFnWithPath, serialize: false }) | ||
const getObj = (outerKey) => ({ | ||
[outerKey]: { | ||
b: { | ||
@@ -28,3 +41,3 @@ c: 's' | ||
} | ||
} | ||
}) | ||
@@ -35,4 +48,5 @@ const max = 500 | ||
function benchNoirV2 (cb) { | ||
const obj = getObj('aa') | ||
for (var i = 0; i < max; i++) { | ||
noir.a(obj.a) | ||
noir.aa(obj.aa) | ||
} | ||
@@ -42,2 +56,3 @@ setImmediate(cb) | ||
function benchFastRedact (cb) { | ||
const obj = getObj('ab') | ||
for (var i = 0; i < max; i++) { | ||
@@ -49,5 +64,6 @@ redactNoSerialize(obj) | ||
function benchFastRedactRestore (cb) { | ||
const obj = getObj('ac') | ||
for (var i = 0; i < max; i++) { | ||
redactNoSerialize(obj) | ||
redactNoSerialize.restore(obj) | ||
redactNoSerializeRestore(obj) | ||
redactNoSerializeRestore.restore(obj) | ||
} | ||
@@ -57,4 +73,5 @@ setImmediate(cb) | ||
function benchNoirV2Wild (cb) { | ||
const obj = getObj('ad') | ||
for (var i = 0; i < max; i++) { | ||
noirWild.a(obj.a) | ||
noirWild.ad(obj.ad) | ||
} | ||
@@ -64,2 +81,3 @@ setImmediate(cb) | ||
function benchFastRedactWild (cb) { | ||
const obj = getObj('ae') | ||
for (var i = 0; i < max; i++) { | ||
@@ -71,5 +89,6 @@ redactWildNoSerialize(obj) | ||
function benchFastRedactWildRestore (cb) { | ||
const obj = getObj('af') | ||
for (var i = 0; i < max; i++) { | ||
redactWildNoSerialize(obj) | ||
redactWildNoSerialize.restore(obj) | ||
redactWildNoSerializeRestore(obj) | ||
redactWildNoSerializeRestore.restore(obj) | ||
} | ||
@@ -79,2 +98,3 @@ setImmediate(cb) | ||
function benchFastRedactIntermediateWild (cb) { | ||
const obj = getObj('ag') | ||
for (var i = 0; i < max; i++) { | ||
@@ -86,5 +106,6 @@ redactIntermediateWildNoSerialize(obj) | ||
function benchFastRedactIntermediateWildRestore (cb) { | ||
const obj = getObj('ah') | ||
for (var i = 0; i < max; i++) { | ||
redactIntermediateWildNoSerialize(obj) | ||
redactIntermediateWildNoSerialize.restore(obj) | ||
redactIntermediateWildNoSerializeRestore(obj) | ||
redactIntermediateWildNoSerializeRestore.restore(obj) | ||
} | ||
@@ -94,2 +115,3 @@ setImmediate(cb) | ||
function benchJSONStringify (cb) { | ||
const obj = getObj('ai') | ||
for (var i = 0; i < max; i++) { | ||
@@ -101,4 +123,5 @@ JSON.stringify(obj) | ||
function benchNoirV2Serialize (cb) { | ||
const obj = getObj('aj') | ||
for (var i = 0; i < max; i++) { | ||
noir.a(obj.a) | ||
noirJSONSerialize.aj(obj.aj) | ||
JSON.stringify(obj) | ||
@@ -109,2 +132,3 @@ } | ||
function benchFastRedactSerialize (cb) { | ||
const obj = getObj('ak') | ||
for (var i = 0; i < max; i++) { | ||
@@ -116,4 +140,5 @@ redact(obj) | ||
function benchNoirV2WildSerialize (cb) { | ||
const obj = getObj('al') | ||
for (var i = 0; i < max; i++) { | ||
noirWild.a(obj.a) | ||
noirWildJSONSerialize.al(obj.al) | ||
JSON.stringify(obj) | ||
@@ -124,2 +149,3 @@ } | ||
function benchFastRedactWildSerialize (cb) { | ||
const obj = getObj('am') | ||
for (var i = 0; i < max; i++) { | ||
@@ -131,2 +157,3 @@ redactWild(obj) | ||
function benchFastRedactIntermediateWildSerialize (cb) { | ||
const obj = getObj('an') | ||
for (var i = 0; i < max; i++) { | ||
@@ -138,2 +165,3 @@ redactIntermediateWild(obj) | ||
function benchFastRedactIntermediateWildMatchWildOutcomeSerialize (cb) { | ||
const obj = getObj('ao') | ||
for (var i = 0; i < max; i++) { | ||
@@ -145,2 +173,3 @@ redactIntermediateWildMatchWildOutcome(obj) | ||
function benchFastRedactStaticMatchWildOutcomeSerialize (cb) { | ||
const obj = getObj('ap') | ||
for (var i = 0; i < max; i++) { | ||
@@ -152,4 +181,5 @@ redactStaticMatchWildOutcome(obj) | ||
function benchNoirV2CensorFunction (cb) { | ||
const obj = getObj('aq') | ||
for (var i = 0; i < max; i++) { | ||
noirCensorFunction.a(obj.a) | ||
noirCensorFunction.aq(obj.aq) | ||
} | ||
@@ -159,2 +189,3 @@ setImmediate(cb) | ||
function benchFastRedactCensorFunction (cb) { | ||
const obj = getObj('ar') | ||
for (var i = 0; i < max; i++) { | ||
@@ -164,2 +195,30 @@ redactCensorFunction(obj) | ||
setImmediate(cb) | ||
}, | ||
function benchFastRedactCensorFunctionIntermediateWild (cb) { | ||
const obj = getObj('as') | ||
for (var i = 0; i < max; i++) { | ||
redactIntermediateWildCensorFunction(obj) | ||
} | ||
setImmediate(cb) | ||
}, | ||
function benchFastRedactCensorFunctionWithPath (cb) { | ||
const obj = getObj('at') | ||
for (var i = 0; i < max; i++) { | ||
redactCensorFunctionWithPath(obj) | ||
} | ||
setImmediate(cb) | ||
}, | ||
function benchFastRedactWildCensorFunctionWithPath (cb) { | ||
const obj = getObj('au') | ||
for (var i = 0; i < max; i++) { | ||
redactWildCensorFunctionWithPath(obj) | ||
} | ||
setImmediate(cb) | ||
}, | ||
function benchFastRedactIntermediateWildCensorFunctionWithPath (cb) { | ||
const obj = getObj('av') | ||
for (var i = 0; i < max; i++) { | ||
redactIntermediateWildCensorFunctionWithPath(obj) | ||
} | ||
setImmediate(cb) | ||
} | ||
@@ -166,0 +225,0 @@ ], 500) |
@@ -35,2 +35,3 @@ 'use strict' | ||
const isCensorFct = typeof censor === 'function' | ||
const censorFctTakesPath = isCensorFct && censor.length > 1 | ||
@@ -46,3 +47,3 @@ if (paths.length === 0) return serialize || noop | ||
return redactor({ secret, wcLen, serialize, strict, isCensorFct }, state({ | ||
return redactor({ secret, wcLen, serialize, strict, isCensorFct, censorFctTakesPath }, state({ | ||
secret, | ||
@@ -49,0 +50,0 @@ censor, |
@@ -19,12 +19,23 @@ 'use strict' | ||
function groupRedact (o, path, censor, isCensorFct) { | ||
function groupRedact (o, path, censor, isCensorFct, censorFctTakesPath) { | ||
const target = get(o, path) | ||
if (target == null) return { keys: null, values: null, target: null, flat: true } | ||
const keys = Object.keys(target) | ||
const length = keys.length | ||
const values = new Array(length) | ||
for (var i = 0; i < length; i++) { | ||
const k = keys[i] | ||
values[i] = target[k] | ||
target[k] = isCensorFct ? censor(target[k]) : censor | ||
const keysLength = keys.length | ||
const pathLength = path.length | ||
const pathWithKey = censorFctTakesPath ? [...path] : undefined | ||
const values = new Array(keysLength) | ||
for (var i = 0; i < keysLength; i++) { | ||
const key = keys[i] | ||
values[i] = target[key] | ||
if (censorFctTakesPath) { | ||
pathWithKey[pathLength] = key | ||
target[key] = censor(target[key], pathWithKey) | ||
} else if (isCensorFct) { | ||
target[key] = censor(target[key]) | ||
} else { | ||
target[key] = censor | ||
} | ||
} | ||
@@ -42,10 +53,11 @@ return { keys, values, target, flat: true } | ||
function nestedRedact (store, o, path, ns, censor, isCensorFct) { | ||
function nestedRedact (store, o, path, ns, censor, isCensorFct, censorFctTakesPath) { | ||
const target = get(o, path) | ||
if (target == null) return | ||
const keys = Object.keys(target) | ||
const length = keys.length | ||
for (var i = 0; i < length; i++) { | ||
const keysLength = keys.length | ||
for (var i = 0; i < keysLength; i++) { | ||
const key = keys[i] | ||
const { value, parent, exists } = specialSet(target, key, ns, censor, isCensorFct) | ||
const { value, parent, exists } = | ||
specialSet(target, key, path, ns, censor, isCensorFct, censorFctTakesPath) | ||
@@ -63,6 +75,7 @@ if (exists === true && parent !== null) { | ||
function specialSet (o, k, p, v, f) { | ||
function specialSet (o, k, path, afterPath, censor, isCensorFct, censorFctTakesPath) { | ||
const afterPathLen = afterPath.length | ||
const lastPathIndex = afterPathLen - 1 | ||
const originalKey = k | ||
var i = -1 | ||
var l = p.length | ||
var li = l - 1 | ||
var n | ||
@@ -75,4 +88,4 @@ var nv | ||
if (typeof n !== 'object') return { value: null, parent: null, exists } | ||
while (n != null && ++i < l) { | ||
k = p[i] | ||
while (n != null && ++i < afterPathLen) { | ||
k = afterPath[i] | ||
oov = ov | ||
@@ -84,5 +97,8 @@ if (!(k in n)) { | ||
ov = n[k] | ||
nv = f ? v(ov) : v | ||
nv = (i !== li) ? ov : nv | ||
n[k] = (has(n, k) && nv === ov) || (nv === undefined && v !== undefined) ? n[k] : nv | ||
nv = (i !== lastPathIndex) | ||
? ov | ||
: (isCensorFct | ||
? (censorFctTakesPath ? censor(ov, [...path, originalKey, ...afterPath]) : censor(ov)) | ||
: censor) | ||
n[k] = (has(n, k) && nv === ov) || (nv === undefined && censor !== undefined) ? n[k] : nv | ||
n = n[k] | ||
@@ -93,2 +109,3 @@ if (typeof n !== 'object') break | ||
} | ||
function get (o, p) { | ||
@@ -95,0 +112,0 @@ var i = -1 |
@@ -7,3 +7,3 @@ 'use strict' | ||
function redactor ({ secret, serialize, wcLen, strict, isCensorFct }, state) { | ||
function redactor ({ secret, serialize, wcLen, strict, isCensorFct, censorFctTakesPath }, state) { | ||
/* eslint-disable-next-line */ | ||
@@ -15,5 +15,5 @@ const redact = Function('o', ` | ||
const { censor, secret } = this | ||
${redactTmpl(secret, isCensorFct)} | ||
${redactTmpl(secret, isCensorFct, censorFctTakesPath)} | ||
this.compileRestore() | ||
${dynamicRedactTmpl(wcLen > 0, isCensorFct)} | ||
${dynamicRedactTmpl(wcLen > 0, isCensorFct, censorFctTakesPath)} | ||
${resultTmpl(serialize)} | ||
@@ -29,5 +29,5 @@ `).bind(state) | ||
function redactTmpl (secret, isCensorFct) { | ||
function redactTmpl (secret, isCensorFct, censorFctTakesPath) { | ||
return Object.keys(secret).map((path) => { | ||
const { escPath, leadingBracket } = secret[path] | ||
const { escPath, leadingBracket, path: arrPath } = secret[path] | ||
const skip = leadingBracket ? 1 : 0 | ||
@@ -55,2 +55,7 @@ const delim = leadingBracket ? '' : '.' | ||
` | ||
const censorArgs = censorFctTakesPath | ||
? `val, ${JSON.stringify(arrPath)}` | ||
: `val` | ||
return ` | ||
@@ -63,3 +68,3 @@ if (${existence}) { | ||
secret[${escPath}].val = val | ||
o${delim}${path} = ${isCensorFct ? 'censor(val)' : 'censor'} | ||
o${delim}${path} = ${isCensorFct ? `censor(${censorArgs})` : 'censor'} | ||
${circularDetection} | ||
@@ -72,3 +77,3 @@ } | ||
function dynamicRedactTmpl (hasWildcards, isCensorFct) { | ||
function dynamicRedactTmpl (hasWildcards, isCensorFct, censorFctTakesPath) { | ||
return hasWildcards === true ? ` | ||
@@ -81,4 +86,4 @@ { | ||
secret[beforeStr] = secret[beforeStr] || [] | ||
nestedRedact(secret[beforeStr], o, before, after, censor, ${isCensorFct}) | ||
} else secret[beforeStr] = groupRedact(o, before, censor, ${isCensorFct}) | ||
nestedRedact(secret[beforeStr], o, before, after, censor, ${isCensorFct}, ${censorFctTakesPath}) | ||
} else secret[beforeStr] = groupRedact(o, before, censor, ${isCensorFct}, ${censorFctTakesPath}) | ||
} | ||
@@ -85,0 +90,0 @@ } |
'use strict' | ||
module.exports = /[^.[\]]+|\[((?:.)*?)\]/g | ||
/* | ||
Regular expression explanation: | ||
Alt 1: /[^.[\]]+/ - Match one or more characters that are *not* a dot (.) | ||
opening square bracket ([) or closing square bracket (]) | ||
Alt 2: /\[((?:.)*?)\]/ - If the char IS dot or square bracket, then create a capture | ||
group (which will be capture group $1) that matches anything | ||
within square brackets. Expansion is lazy so it will | ||
stop matching as soon as the first closing bracket is met `]` | ||
(rather than continuing to match until the final closing bracket). | ||
*/ |
@@ -9,3 +9,2 @@ 'use strict' | ||
censor, | ||
isCensorFct, | ||
compileRestore, | ||
@@ -18,4 +17,3 @@ serialize, | ||
} = o | ||
const builder = [{ secret, censor, isCensorFct, compileRestore }] | ||
builder.push({ secret }) | ||
const builder = [{ secret, censor, compileRestore }] | ||
if (serialize !== false) builder.push({ serialize }) | ||
@@ -22,0 +20,0 @@ if (wcLen > 0) builder.push({ groupRedact, nestedRedact, wildcards, wcLen }) |
@@ -9,3 +9,3 @@ 'use strict' | ||
const { | ||
ERR_PATHS_MUST_BE_STRINGS = () => 'fast-redact - Paths must be strings', | ||
ERR_PATHS_MUST_BE_STRINGS = () => 'fast-redact - Paths must be (non-empty) strings', | ||
ERR_INVALID_PATH = (s) => `fast-redact – Invalid path (${s})` | ||
@@ -12,0 +12,0 @@ } = opts |
{ | ||
"name": "fast-redact", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "very fast object redaction", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -118,3 +118,3 @@ # fast-redact | ||
The `serialize` option may be a function of a boolean. If a function is supplied, this | ||
The `serialize` option may either be a function or a boolean. If a function is supplied, this | ||
will be used to `serialize` the redacted object. It's important to understand that for | ||
@@ -121,0 +121,0 @@ performance reasons `fast-redact` *mutates* the original object, then serializes, then |
@@ -8,2 +8,3 @@ 'use strict' | ||
const censorFct = value => !value ? value : 'xxx' + value.substr(-2) | ||
const censorWithPath = (v, p) => p.join('.') + ' ' + censorFct(v) | ||
@@ -92,19 +93,23 @@ test('returns no-op when passed no paths [serialize: false]', ({ end, doesNotThrow }) => { | ||
test('throws if a path is not a string', ({ end, is, throws }) => { | ||
test('throws if a path is not a string', ({ end, throws }) => { | ||
const invalidTypeMsg = 'fast-redact - Paths must be (non-empty) strings' | ||
throws((e) => { | ||
fastRedact({ paths: [1] }) | ||
}, Error('fast-redact - Paths must be strings')) | ||
}, Error(invalidTypeMsg)) | ||
throws((e) => { | ||
fastRedact({ paths: [null] }) | ||
}, Error('fast-redact - Paths must be strings')) | ||
}, Error(invalidTypeMsg)) | ||
throws((e) => { | ||
fastRedact({ paths: [undefined] }) | ||
}, Error('fast-redact - Paths must be strings')) | ||
}, Error(invalidTypeMsg)) | ||
throws((e) => { | ||
fastRedact({ paths: [{}] }) | ||
}, Error('fast-redact - Paths must be strings')) | ||
}, Error(invalidTypeMsg)) | ||
throws((e) => { | ||
fastRedact({ paths: [[null]] }) | ||
}, Error(invalidTypeMsg)) | ||
end() | ||
}) | ||
test('throws when passed illegal paths', ({ end, is, throws }) => { | ||
test('throws when passed illegal paths', ({ end, throws }) => { | ||
const err = (s) => Error(`fast-redact – Invalid path (${s})`) | ||
@@ -198,2 +203,8 @@ throws((e) => { | ||
}, err('a\r')) | ||
throws((e) => { | ||
fastRedact({ paths: [''] }) | ||
}, err('')) | ||
throws((e) => { | ||
fastRedact({ paths: ['[""""]'] }) | ||
}, err('[""""]')) | ||
end() | ||
@@ -223,2 +234,38 @@ }) | ||
test('supports path segments that aren\'t identifiers if bracketed', ({ end, strictSame }) => { | ||
const redactSerializeFalse = fastRedact({ | ||
paths: ['a[""]', 'a["x-y"]', 'a[\'"y"\']', "a['\\'x\\'']"], | ||
serialize: false, | ||
censor: 'X' | ||
}) | ||
const res = redactSerializeFalse({ a: { '': 'Hi!', 'x-y': 'Hi!', '"y"': 'Hi!', "'x'": 'Hi!' } }) | ||
strictSame(res, { a: { '': 'X', 'x-y': 'X', '"y"': 'X', "'x'": 'X' } }) | ||
end() | ||
}) | ||
test('supports consecutive bracketed path segments', ({ end, strictSame }) => { | ||
const redactSerializeFalse = fastRedact({ | ||
paths: ['a[""]["y"]'], | ||
serialize: false, | ||
censor: 'X' | ||
}) | ||
const res = redactSerializeFalse({ a: { '': { 'y': 'Hi!' } } }) | ||
strictSame(res, { a: { '': { 'y': 'X' } } }) | ||
end() | ||
}) | ||
test('supports leading bracketed widcard', ({ end, strictSame }) => { | ||
const redactSerializeFalse = fastRedact({ | ||
paths: ['[*]["y"]'], | ||
serialize: false, | ||
censor: 'X' | ||
}) | ||
const res = redactSerializeFalse({ 'x': { 'y': 'Hi!' } }) | ||
strictSame(res, { 'x': { 'y': 'X' } }) | ||
end() | ||
}) | ||
test('masks according to supplied censor', ({ end, is }) => { | ||
@@ -269,2 +316,22 @@ const censor = 'test' | ||
test('masks according to supplied censor-with-path function', ({ end, is }) => { | ||
const redact = fastRedact({ paths: ['a'], censor: censorWithPath, serialize: false }) | ||
is(redact({ a: '0123456' }).a, 'a xxx56') | ||
end() | ||
}) | ||
test('masks according to supplied censor-with-path function with wildcards', ({ end, is }) => { | ||
const redact = fastRedact({ paths: '*', censor: censorWithPath, serialize: false }) | ||
is(redact({ a: '0123456' }).a, 'a xxx56') | ||
end() | ||
}) | ||
test('masks according to supplied censor-with-path function with nested wildcards', ({ end, is }) => { | ||
const redact = fastRedact({ paths: ['*.b'], censor: censorWithPath, serialize: false }) | ||
is(redact({ a: { b: '0123456' } }).a.b, 'a.b xxx56') | ||
is(redact({ c: { b: '0123456', d: 'pristine' } }).c.b, 'c.b xxx56') | ||
is(redact({ c: { b: '0123456', d: 'pristine' } }).c.d, 'pristine') | ||
end() | ||
}) | ||
test('redact.restore function places original values back in place with censor function', ({ end, is }) => { | ||
@@ -271,0 +338,0 @@ const redact = fastRedact({ paths: ['a'], censor: censorFct, serialize: false }) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
70597
1567