2020-03-26 14:37:35 +00:00
|
|
|
'use strict'
|
|
|
|
|
|
|
|
const rx = require('./rx')
|
|
|
|
|
|
|
|
module.exports = redactor
|
|
|
|
|
2020-11-12 15:37:43 +00:00
|
|
|
function redactor ({ secret, serialize, wcLen, strict, isCensorFct, censorFctTakesPath }, state) {
|
2020-03-26 14:37:35 +00:00
|
|
|
/* eslint-disable-next-line */
|
|
|
|
const redact = Function('o', `
|
|
|
|
if (typeof o !== 'object' || o == null) {
|
|
|
|
${strictImpl(strict, serialize)}
|
|
|
|
}
|
|
|
|
const { censor, secret } = this
|
2020-11-12 15:37:43 +00:00
|
|
|
${redactTmpl(secret, isCensorFct, censorFctTakesPath)}
|
2020-03-26 14:37:35 +00:00
|
|
|
this.compileRestore()
|
2020-11-12 15:37:43 +00:00
|
|
|
${dynamicRedactTmpl(wcLen > 0, isCensorFct, censorFctTakesPath)}
|
2020-03-26 14:37:35 +00:00
|
|
|
${resultTmpl(serialize)}
|
|
|
|
`).bind(state)
|
|
|
|
|
|
|
|
if (serialize === false) {
|
|
|
|
redact.restore = (o) => state.restore(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
return redact
|
|
|
|
}
|
|
|
|
|
2020-11-12 15:37:43 +00:00
|
|
|
function redactTmpl (secret, isCensorFct, censorFctTakesPath) {
|
2020-03-26 14:37:35 +00:00
|
|
|
return Object.keys(secret).map((path) => {
|
2020-11-12 15:37:43 +00:00
|
|
|
const { escPath, leadingBracket, path: arrPath } = secret[path]
|
2020-03-26 14:37:35 +00:00
|
|
|
const skip = leadingBracket ? 1 : 0
|
|
|
|
const delim = leadingBracket ? '' : '.'
|
|
|
|
const hops = []
|
|
|
|
var match
|
|
|
|
while ((match = rx.exec(path)) !== null) {
|
|
|
|
const [ , ix ] = match
|
|
|
|
const { index, input } = match
|
|
|
|
if (index > skip) hops.push(input.substring(0, index - (ix ? 0 : 1)))
|
|
|
|
}
|
|
|
|
var existence = hops.map((p) => `o${delim}${p}`).join(' && ')
|
|
|
|
if (existence.length === 0) existence += `o${delim}${path} != null`
|
|
|
|
else existence += ` && o${delim}${path} != null`
|
|
|
|
|
|
|
|
const circularDetection = `
|
|
|
|
switch (true) {
|
|
|
|
${hops.reverse().map((p) => `
|
|
|
|
case o${delim}${p} === censor:
|
|
|
|
secret[${escPath}].circle = ${JSON.stringify(p)}
|
|
|
|
break
|
|
|
|
`).join('\n')}
|
|
|
|
}
|
|
|
|
`
|
2020-11-12 15:37:43 +00:00
|
|
|
|
|
|
|
const censorArgs = censorFctTakesPath
|
|
|
|
? `val, ${JSON.stringify(arrPath)}`
|
|
|
|
: `val`
|
|
|
|
|
2020-03-26 14:37:35 +00:00
|
|
|
return `
|
|
|
|
if (${existence}) {
|
|
|
|
const val = o${delim}${path}
|
|
|
|
if (val === censor) {
|
|
|
|
secret[${escPath}].precensored = true
|
|
|
|
} else {
|
|
|
|
secret[${escPath}].val = val
|
2020-11-12 15:37:43 +00:00
|
|
|
o${delim}${path} = ${isCensorFct ? `censor(${censorArgs})` : 'censor'}
|
2020-03-26 14:37:35 +00:00
|
|
|
${circularDetection}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|
|
|
|
}).join('\n')
|
|
|
|
}
|
|
|
|
|
2020-11-12 15:37:43 +00:00
|
|
|
function dynamicRedactTmpl (hasWildcards, isCensorFct, censorFctTakesPath) {
|
2020-03-26 14:37:35 +00:00
|
|
|
return hasWildcards === true ? `
|
|
|
|
{
|
|
|
|
const { wildcards, wcLen, groupRedact, nestedRedact } = this
|
|
|
|
for (var i = 0; i < wcLen; i++) {
|
|
|
|
const { before, beforeStr, after, nested } = wildcards[i]
|
|
|
|
if (nested === true) {
|
|
|
|
secret[beforeStr] = secret[beforeStr] || []
|
2020-11-12 15:37:43 +00:00
|
|
|
nestedRedact(secret[beforeStr], o, before, after, censor, ${isCensorFct}, ${censorFctTakesPath})
|
|
|
|
} else secret[beforeStr] = groupRedact(o, before, censor, ${isCensorFct}, ${censorFctTakesPath})
|
2020-03-26 14:37:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
` : ''
|
|
|
|
}
|
|
|
|
|
|
|
|
function resultTmpl (serialize) {
|
|
|
|
return serialize === false ? `return o` : `
|
|
|
|
var s = this.serialize(o)
|
|
|
|
this.restore(o)
|
|
|
|
return s
|
|
|
|
`
|
|
|
|
}
|
|
|
|
|
|
|
|
function strictImpl (strict, serialize) {
|
|
|
|
return strict === true
|
|
|
|
? `throw Error('fast-redact: primitives cannot be redacted')`
|
|
|
|
: serialize === false ? `return o` : `return this.serialize(o)`
|
|
|
|
}
|