Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fast-redact

Package Overview
Dependencies
Maintainers
2
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-redact - npm Package Compare versions

Comparing version 2.0.0 to 2.1.0

111

benchmark/index.js
'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 })

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc