field-redactor 1.2.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +38 -0
- package/CHANGELOG.md +179 -0
- package/CONTRIBUTING.md +64 -0
- package/README.md +67 -670
- package/dist/api/fieldRedactor.d.ts +53 -0
- package/dist/api/fieldRedactor.d.ts.map +1 -0
- package/dist/api/fieldRedactor.js +169 -0
- package/dist/api/fieldRedactor.js.map +1 -0
- package/dist/api/fieldRedactorConfigBuilder.d.ts +57 -0
- package/dist/api/fieldRedactorConfigBuilder.d.ts.map +1 -0
- package/dist/api/fieldRedactorConfigBuilder.js +115 -0
- package/dist/api/fieldRedactorConfigBuilder.js.map +1 -0
- package/dist/api/fieldRedactorDeps.d.ts +19 -0
- package/dist/api/fieldRedactorDeps.d.ts.map +1 -0
- package/dist/api/fieldRedactorDeps.js +45 -0
- package/dist/api/fieldRedactorDeps.js.map +1 -0
- package/dist/arrayRedaction.d.ts +12 -0
- package/dist/arrayRedaction.d.ts.map +1 -0
- package/dist/arrayRedaction.js +70 -0
- package/dist/arrayRedaction.js.map +1 -0
- package/dist/config/configValidator.d.ts +9 -0
- package/dist/config/configValidator.d.ts.map +1 -0
- package/dist/config/configValidator.js +77 -0
- package/dist/config/configValidator.js.map +1 -0
- package/dist/config/customObjectSchemas.d.ts +7 -0
- package/dist/config/customObjectSchemas.d.ts.map +1 -0
- package/dist/config/customObjectSchemas.js +35 -0
- package/dist/config/customObjectSchemas.js.map +1 -0
- package/dist/config/presets.d.ts +22 -0
- package/dist/config/presets.d.ts.map +1 -0
- package/dist/config/presets.js +50 -0
- package/dist/config/presets.js.map +1 -0
- package/dist/config/redactionRules.d.ts +25 -0
- package/dist/config/redactionRules.d.ts.map +1 -0
- package/dist/config/redactionRules.js +108 -0
- package/dist/config/redactionRules.js.map +1 -0
- package/dist/configValidator.d.ts +9 -0
- package/dist/configValidator.d.ts.map +1 -0
- package/dist/configValidator.js +77 -0
- package/dist/configValidator.js.map +1 -0
- package/dist/copyOnWriteHelpers.d.ts +20 -0
- package/dist/copyOnWriteHelpers.d.ts.map +1 -0
- package/dist/copyOnWriteHelpers.js +58 -0
- package/dist/copyOnWriteHelpers.js.map +1 -0
- package/dist/customObjectFieldHandler.d.ts +21 -0
- package/dist/customObjectFieldHandler.d.ts.map +1 -0
- package/dist/customObjectFieldHandler.js +159 -0
- package/dist/customObjectFieldHandler.js.map +1 -0
- package/dist/customObjectManager.d.ts +14 -8
- package/dist/customObjectManager.d.ts.map +1 -1
- package/dist/customObjectManager.js +31 -30
- package/dist/customObjectManager.js.map +1 -1
- package/dist/customObjectSchemas.d.ts +7 -0
- package/dist/customObjectSchemas.d.ts.map +1 -0
- package/dist/customObjectSchemas.js +35 -0
- package/dist/customObjectSchemas.js.map +1 -0
- package/dist/dryRun.d.ts +9 -0
- package/dist/dryRun.d.ts.map +1 -0
- package/dist/dryRun.js +75 -0
- package/dist/dryRun.js.map +1 -0
- package/dist/dryRunAttribution.d.ts +10 -0
- package/dist/dryRunAttribution.d.ts.map +1 -0
- package/dist/dryRunAttribution.js +14 -0
- package/dist/dryRunAttribution.js.map +1 -0
- package/dist/dryrun/dryRun.d.ts +9 -0
- package/dist/dryrun/dryRun.d.ts.map +1 -0
- package/dist/dryrun/dryRun.js +75 -0
- package/dist/dryrun/dryRun.js.map +1 -0
- package/dist/dryrun/dryRunAttribution.d.ts +10 -0
- package/dist/dryrun/dryRunAttribution.d.ts.map +1 -0
- package/dist/dryrun/dryRunAttribution.js +14 -0
- package/dist/dryrun/dryRunAttribution.js.map +1 -0
- package/dist/engine/arrayRedaction.d.ts +12 -0
- package/dist/engine/arrayRedaction.d.ts.map +1 -0
- package/dist/engine/arrayRedaction.js +70 -0
- package/dist/engine/arrayRedaction.js.map +1 -0
- package/dist/engine/customObjectFieldHandler.d.ts +35 -0
- package/dist/engine/customObjectFieldHandler.d.ts.map +1 -0
- package/dist/engine/customObjectFieldHandler.js +167 -0
- package/dist/engine/customObjectFieldHandler.js.map +1 -0
- package/dist/engine/objectRedactor.d.ts +18 -0
- package/dist/engine/objectRedactor.d.ts.map +1 -0
- package/dist/engine/objectRedactor.js +38 -0
- package/dist/engine/objectRedactor.js.map +1 -0
- package/dist/engine/objectRedactorCustomObject.d.ts +27 -0
- package/dist/engine/objectRedactorCustomObject.d.ts.map +1 -0
- package/dist/engine/objectRedactorCustomObject.js +54 -0
- package/dist/engine/objectRedactorCustomObject.js.map +1 -0
- package/dist/engine/objectRedactorHelpers.d.ts +9 -0
- package/dist/engine/objectRedactorHelpers.d.ts.map +1 -0
- package/dist/engine/objectRedactorHelpers.js +61 -0
- package/dist/engine/objectRedactorHelpers.js.map +1 -0
- package/dist/engine/objectRedactorMutation.d.ts +10 -0
- package/dist/engine/objectRedactorMutation.d.ts.map +1 -0
- package/dist/engine/objectRedactorMutation.js +89 -0
- package/dist/engine/objectRedactorMutation.js.map +1 -0
- package/dist/engine/objectRedactorSync.d.ts +2 -0
- package/dist/engine/objectRedactorSync.d.ts.map +1 -0
- package/dist/engine/objectRedactorSync.js +7 -0
- package/dist/engine/objectRedactorSync.js.map +1 -0
- package/dist/engine/objectRedactorTraversal.d.ts +41 -0
- package/dist/engine/objectRedactorTraversal.d.ts.map +1 -0
- package/dist/engine/objectRedactorTraversal.js +201 -0
- package/dist/engine/objectRedactorTraversal.js.map +1 -0
- package/dist/engine/primitiveRedactor.d.ts +33 -0
- package/dist/engine/primitiveRedactor.d.ts.map +1 -0
- package/dist/engine/primitiveRedactor.js +75 -0
- package/dist/engine/primitiveRedactor.js.map +1 -0
- package/dist/engine/traversalServices.d.ts +21 -0
- package/dist/engine/traversalServices.d.ts.map +1 -0
- package/dist/engine/traversalServices.js +3 -0
- package/dist/engine/traversalServices.js.map +1 -0
- package/dist/fieldDisposition.d.ts +3 -0
- package/dist/fieldDisposition.d.ts.map +1 -0
- package/dist/fieldDisposition.js +6 -0
- package/dist/fieldDisposition.js.map +1 -0
- package/dist/fieldRedactor.d.ts +34 -11
- package/dist/fieldRedactor.d.ts.map +1 -1
- package/dist/fieldRedactor.js +116 -35
- package/dist/fieldRedactor.js.map +1 -1
- package/dist/fieldRedactorConfigBuilder.d.ts +55 -0
- package/dist/fieldRedactorConfigBuilder.d.ts.map +1 -0
- package/dist/fieldRedactorConfigBuilder.js +111 -0
- package/dist/fieldRedactorConfigBuilder.js.map +1 -0
- package/dist/fieldRedactorDeps.d.ts +19 -0
- package/dist/fieldRedactorDeps.d.ts.map +1 -0
- package/dist/fieldRedactorDeps.js +43 -0
- package/dist/fieldRedactorDeps.js.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/jsonWalk.d.ts +11 -0
- package/dist/jsonWalk.d.ts.map +1 -0
- package/dist/jsonWalk.js +55 -0
- package/dist/jsonWalk.js.map +1 -0
- package/dist/maybeAsync.d.ts +7 -0
- package/dist/maybeAsync.d.ts.map +1 -0
- package/dist/maybeAsync.js +56 -0
- package/dist/maybeAsync.js.map +1 -0
- package/dist/objectRedactor.d.ts +10 -34
- package/dist/objectRedactor.d.ts.map +1 -1
- package/dist/objectRedactor.js +11 -298
- package/dist/objectRedactor.js.map +1 -1
- package/dist/objectRedactorCow.d.ts +35 -0
- package/dist/objectRedactorCow.d.ts.map +1 -0
- package/dist/objectRedactorCow.js +300 -0
- package/dist/objectRedactorCow.js.map +1 -0
- package/dist/objectRedactorCustomObject.d.ts +28 -0
- package/dist/objectRedactorCustomObject.d.ts.map +1 -0
- package/dist/objectRedactorCustomObject.js +57 -0
- package/dist/objectRedactorCustomObject.js.map +1 -0
- package/dist/objectRedactorHelpers.d.ts +9 -0
- package/dist/objectRedactorHelpers.d.ts.map +1 -0
- package/dist/objectRedactorHelpers.js +61 -0
- package/dist/objectRedactorHelpers.js.map +1 -0
- package/dist/objectRedactorMutation.d.ts +10 -0
- package/dist/objectRedactorMutation.d.ts.map +1 -0
- package/dist/objectRedactorMutation.js +89 -0
- package/dist/objectRedactorMutation.js.map +1 -0
- package/dist/objectRedactorSync.d.ts +2 -0
- package/dist/objectRedactorSync.d.ts.map +1 -0
- package/dist/objectRedactorSync.js +7 -0
- package/dist/objectRedactorSync.js.map +1 -0
- package/dist/objectRedactorTraversal.d.ts +41 -0
- package/dist/objectRedactorTraversal.d.ts.map +1 -0
- package/dist/objectRedactorTraversal.js +201 -0
- package/dist/objectRedactorTraversal.js.map +1 -0
- package/dist/pathParsing.d.ts +11 -0
- package/dist/pathParsing.d.ts.map +1 -0
- package/dist/pathParsing.js +53 -0
- package/dist/pathParsing.js.map +1 -0
- package/dist/pathRuleMatcher.d.ts +19 -0
- package/dist/pathRuleMatcher.d.ts.map +1 -0
- package/dist/pathRuleMatcher.js +42 -0
- package/dist/pathRuleMatcher.js.map +1 -0
- package/dist/presets.d.ts +22 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +50 -0
- package/dist/presets.js.map +1 -0
- package/dist/primitiveRedactor.d.ts +13 -8
- package/dist/primitiveRedactor.d.ts.map +1 -1
- package/dist/primitiveRedactor.js +32 -27
- package/dist/primitiveRedactor.js.map +1 -1
- package/dist/redactionRules.d.ts +22 -0
- package/dist/redactionRules.d.ts.map +1 -0
- package/dist/redactionRules.js +74 -0
- package/dist/redactionRules.js.map +1 -0
- package/dist/regexUtils.d.ts +3 -0
- package/dist/regexUtils.d.ts.map +1 -0
- package/dist/regexUtils.js +8 -0
- package/dist/regexUtils.js.map +1 -0
- package/dist/ruleResolver.d.ts +65 -0
- package/dist/ruleResolver.d.ts.map +1 -0
- package/dist/ruleResolver.js +193 -0
- package/dist/ruleResolver.js.map +1 -0
- package/dist/rules/customObjectManager.d.ts +28 -0
- package/dist/rules/customObjectManager.d.ts.map +1 -0
- package/dist/rules/customObjectManager.js +60 -0
- package/dist/rules/customObjectManager.js.map +1 -0
- package/dist/rules/fieldDisposition.d.ts +3 -0
- package/dist/rules/fieldDisposition.d.ts.map +1 -0
- package/dist/rules/fieldDisposition.js +6 -0
- package/dist/rules/fieldDisposition.js.map +1 -0
- package/dist/rules/pathRuleMatcher.d.ts +19 -0
- package/dist/rules/pathRuleMatcher.d.ts.map +1 -0
- package/dist/rules/pathRuleMatcher.js +40 -0
- package/dist/rules/pathRuleMatcher.js.map +1 -0
- package/dist/rules/ruleResolver.d.ts +65 -0
- package/dist/rules/ruleResolver.d.ts.map +1 -0
- package/dist/rules/ruleResolver.js +194 -0
- package/dist/rules/ruleResolver.js.map +1 -0
- package/dist/rules/secretManager.d.ts +32 -0
- package/dist/rules/secretManager.d.ts.map +1 -0
- package/dist/rules/secretManager.js +85 -0
- package/dist/rules/secretManager.js.map +1 -0
- package/dist/rules/valuePatternMatcher.d.ts +15 -0
- package/dist/rules/valuePatternMatcher.d.ts.map +1 -0
- package/dist/rules/valuePatternMatcher.js +30 -0
- package/dist/rules/valuePatternMatcher.js.map +1 -0
- package/dist/secretManager.d.ts +17 -24
- package/dist/secretManager.d.ts.map +1 -1
- package/dist/secretManager.js +47 -32
- package/dist/secretManager.js.map +1 -1
- package/dist/traversalServices.d.ts +21 -0
- package/dist/traversalServices.d.ts.map +1 -0
- package/dist/traversalServices.js +3 -0
- package/dist/traversalServices.js.map +1 -0
- package/dist/types.d.ts +139 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +14 -1
- package/dist/types.js.map +1 -1
- package/dist/util/jsonWalk.d.ts +10 -0
- package/dist/util/jsonWalk.d.ts.map +1 -0
- package/dist/util/jsonWalk.js +53 -0
- package/dist/util/jsonWalk.js.map +1 -0
- package/dist/util/maybeAsync.d.ts +7 -0
- package/dist/util/maybeAsync.d.ts.map +1 -0
- package/dist/util/maybeAsync.js +56 -0
- package/dist/util/maybeAsync.js.map +1 -0
- package/dist/util/pathParsing.d.ts +11 -0
- package/dist/util/pathParsing.d.ts.map +1 -0
- package/dist/util/pathParsing.js +53 -0
- package/dist/util/pathParsing.js.map +1 -0
- package/dist/util/regexUtils.d.ts +3 -0
- package/dist/util/regexUtils.d.ts.map +1 -0
- package/dist/util/regexUtils.js +8 -0
- package/dist/util/regexUtils.js.map +1 -0
- package/dist/valuePatternMatcher.d.ts +15 -0
- package/dist/valuePatternMatcher.d.ts.map +1 -0
- package/dist/valuePatternMatcher.js +30 -0
- package/dist/valuePatternMatcher.js.map +1 -0
- package/docs/guides/anti-patterns.md +107 -0
- package/docs/guides/metadata-redaction.md +112 -0
- package/docs/guides/migration-1.2-to-1.5.md +106 -0
- package/docs/guides/migration-1.5-to-1.6.md +56 -0
- package/docs/guides/path-rules.md +47 -0
- package/docs/guides/secret-key-modes.md +108 -0
- package/docs/guides/value-pattern-redaction.md +58 -0
- package/docs/reference/config.md +139 -0
- package/docs/release-notes/2.0.0.md +19 -0
- package/docs/release-notes/2.1.0.md +17 -0
- package/docs/release-notes/2.2.0.md +16 -0
- package/docs/release-notes/2.3.0.md +17 -0
- package/docs/release-notes/2.3.1.md +17 -0
- package/docs/release-notes/2.4.0.md +30 -0
- package/docs/release-notes/2.5.0.md +33 -0
- package/docs/release-notes/2.5.1.md +17 -0
- package/docs/release-notes/README.md +32 -0
- package/docs/release-notes/v1.0.0.md +17 -0
- package/docs/release-notes/v1.1.0.md +18 -0
- package/docs/release-notes/v1.2.0.md +18 -0
- package/docs/release-notes/v1.2.1.md +16 -0
- package/docs/release-notes/v1.2.2.md +19 -0
- package/docs/release-notes/v1.3.0.md +112 -0
- package/docs/release-notes/v1.5.0.md +88 -0
- package/docs/release-notes/v1.6.0.md +59 -0
- package/jest.config.js +6 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,703 +1,100 @@
|
|
|
1
1
|
# FieldRedactor
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A TypeScript library for redacting PII from nested JSON using regex key rules, object **schemas** (sibling-key patterns), and configurable redaction modes.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
|
-
# History
|
|
8
|
-
In many instances, redaction of sensitive data from log output is fairly straightforward and can be accomplished through existing redaction libraries. However, I often encountered scenarios where such simplistic approaches were not sufficient. Take, for example, the following object:
|
|
9
|
-
|
|
10
|
-
```json
|
|
11
|
-
{
|
|
12
|
-
"name": "email",
|
|
13
|
-
"type": "String",
|
|
14
|
-
"value": "foo.bar@example.com"
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
If this object is placed in a data set with many others, and only some of these objects contain PII, redaction becomes quite troublesome. One could redact all `value` fields from these objects - but this merely renders the log output useless for debugging or tracing, as all values are now redacted. The value of the `name` field determines whether or not the `value` field should be redacted. I often found myself writing custom logic to make this determination, which led to brittle code that was difficult to maintain. In the end I decided to write a new, highly configurable plug-and-play solution that could redact sensitive data in various manners while requiring only minor configuration tweaks. Enter FieldRedactor!
|
|
19
|
-
|
|
20
|
-
## Basic Usage
|
|
21
|
-
Basic usage of the FieldRedactor is straightforward but not recommended. Object redaction can be performed either in-place or return the redacted object. If redactor is given a string, primitive, Date, function, or null/undefined value then it returns the value without modification.
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import { FieldRedactor } from 'field-redactor';
|
|
25
|
-
const myJsonObject = { foo: "bar", fizz: null };
|
|
26
|
-
const fieldRedactor = new FieldRedactor();
|
|
27
|
-
|
|
28
|
-
// return redacted result
|
|
29
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
30
|
-
const primitiveResult = await fieldRedactor.redact("foobar");
|
|
31
|
-
console.log(myJsonObject); // { foo: "bar", fizz: null }
|
|
32
|
-
console.log(result); // { foo: "REDACTED", fizz: null }
|
|
33
|
-
console.log(primitiveResult); // "foobar"
|
|
34
|
-
|
|
35
|
-
// redact in place
|
|
36
|
-
await fieldRedactor.redactInPlace(myJsonObject);
|
|
37
|
-
console.log(myJsonObject); // { foo: "REDACTED", fizz: null }
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
> **Note:** `null`, `undefined`, `string`, `Date`, `Function`, and primitive value inputs are completely ignored.
|
|
41
|
-
>
|
|
42
|
-
> **Note:** `null` and `undefined` values are not redacted by default.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
## Customization
|
|
46
|
-
The true power of this tool comes from its customization. FieldRedactor can be customized to redact only primtive values for certain keys, deeply redact others, while stringifying and fully redacting other keys. The redactor itself can be configured, and "Custom Objects" can be specified to handle certain object shapes in a highly specific and configurable way.
|
|
47
|
-
|
|
48
|
-
### Overview
|
|
49
|
-
| Config Field | Type | Default | Effect |
|
|
50
|
-
|-----------------------|---------------------------------|--------------------------------|-----------------------------------------------------------------------|
|
|
51
|
-
| `redactor` | `(val: any) => Promise<string>` | `(val) => Promise.resolve("REDACTED")` | The function to use when redacting values. |
|
|
52
|
-
| `secretKeys` | `RegExp[]` | `null` | Specifies which values at any level of the JSON object should be redacted. Objects are not deeply redacted, but primitive values in arrays are. If not specified, all values are considered secret. |
|
|
53
|
-
| `deepSecretKeys` | `RegExp[]` | `[]` | Specifies keys at any level of the JSON object to be deeply redacted. All values within matching objects are fully redacted unless matching a custom object. |
|
|
54
|
-
| `fullSecretKeys` | `RegExp[]` | `[]` | Specifies keys at any level of the JSON object to be stringified and fully redacted. Primarily used for objects and arrays. |
|
|
55
|
-
| `deleteSecretKeys` | `RegExp[]` | `[]` | Specifies keys at any level of the JSON object to be completely deleted. |
|
|
56
|
-
| `customObjects` | `CustomObject[]` | `[]` | Specifies custom objects requiring fine-tuned redaction logic, such as referencing sibling keys. See the "Custom Objects" section for details. |
|
|
57
|
-
| `ignoreBooleans` | `boolean` | `false` | If `true`, booleans will not be redacted even if secret. |
|
|
58
|
-
| `ignoreNullOrUndefined` | `boolean` | `true` | If `true`, `null` and `undefined` values will not be redacted. |
|
|
59
|
-
|
|
60
|
-
### `redactor` Configuration
|
|
61
|
-
Configures the redactor function used when a secret is encountered. Users should typically provide this configuration.
|
|
62
|
-
|
|
63
|
-
#### Details
|
|
64
|
-
- **Type:** `(val: any) => Promise<string>`
|
|
65
|
-
- **Effect:** The function used to redact values.
|
|
66
|
-
- Value can only be null or undefined if `ignoreNullOrUndefined` is set to false.
|
|
67
|
-
- Defaults to `() => Promise.resolve('REDACTED')`.
|
|
68
|
-
|
|
69
|
-
#### Example
|
|
70
|
-
##### Code
|
|
71
|
-
```typescript
|
|
72
|
-
import { FieldRedactor } from 'field-redactor';
|
|
73
|
-
import * as crypto from 'crypto';
|
|
74
|
-
const redactor: Redactor = (val: any) => Promise.resolve(crypto.createHash('sha256').update(val.toString()).digest('hex'));
|
|
75
|
-
const fieldRedactor = new FieldRedactor({
|
|
76
|
-
redactor
|
|
77
|
-
});
|
|
78
|
-
const result = await redactor.redact({foo: "bar"});
|
|
79
|
-
console.log(result);
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
##### Output
|
|
83
7
|
```bash
|
|
84
|
-
|
|
8
|
+
npm install field-redactor
|
|
9
|
+
# or
|
|
10
|
+
yarn add field-redactor
|
|
85
11
|
```
|
|
86
12
|
|
|
87
|
-
|
|
88
|
-
* Specifies values which should be redacted.
|
|
89
|
-
* __All values are considered secret if no secrets of any type are specified.__
|
|
90
|
-
* has lowest precedence of all secret specifiers.
|
|
91
|
-
|
|
92
|
-
#### Details
|
|
93
|
-
- **Type:** `RegExp[]`
|
|
94
|
-
- **Default:** All values considered secret unless a secret field is specified.
|
|
95
|
-
- **Effect:** Matches keys in objects, child objects, or array value primitives. Assessed recursively.
|
|
13
|
+
## Quick start
|
|
96
14
|
|
|
97
|
-
#### Example
|
|
98
|
-
##### Code
|
|
99
15
|
```typescript
|
|
100
|
-
import { FieldRedactor } from 'field-redactor';
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
16
|
+
import { CustomObjectMatchType, FieldRedactor, FieldRedactorConfigBuilder } from 'field-redactor';
|
|
17
|
+
|
|
18
|
+
// Recommended: explicit rules via createSafe or the builder
|
|
19
|
+
const redactor = FieldRedactorConfigBuilder.create()
|
|
20
|
+
.shallow(/email/i, /password/i)
|
|
21
|
+
.remove(/authKey/i)
|
|
22
|
+
.schema(
|
|
23
|
+
{ name: CustomObjectMatchType.Ignore, type: CustomObjectMatchType.Ignore, value: 'name' },
|
|
24
|
+
{ name: 'metadata-entry' }
|
|
25
|
+
)
|
|
26
|
+
.buildSafeRedactor();
|
|
27
|
+
|
|
28
|
+
const result = redactor.redactSync({
|
|
29
|
+
email: 'alice@example.com',
|
|
30
|
+
authKey: 'secret',
|
|
31
|
+
metadata: [{ name: 'email', type: 'String', value: 'alice@example.com' }]
|
|
114
32
|
});
|
|
115
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
116
|
-
console.log(result);
|
|
117
33
|
```
|
|
118
34
|
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
{
|
|
122
|
-
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
123
|
-
"userId": "REDACTED",
|
|
124
|
-
"contactInfo": {
|
|
125
|
-
"email": "REDACTED",
|
|
126
|
-
"firstName": "REDACTED",
|
|
127
|
-
"lastName": "REDACTED",
|
|
128
|
-
"Salutation": "Mr.",
|
|
129
|
-
},
|
|
130
|
-
"someSecretData": ["REDACTED", "REDACTED", { "deep": "is not redacted", "name": "REDACTED" }]
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
> - `email` and `name` fields were all redacted
|
|
135
|
-
> - primitives in `someSecretData` array were redacted
|
|
136
|
-
> - object values in `someSecretData` was evaluated and redacted if applicable
|
|
137
|
-
|
|
138
|
-
### `deepSecretKeys` Configuration
|
|
139
|
-
* Specifies values which should be deeply redacted
|
|
140
|
-
* Has higher precedence than `secretKeys`
|
|
141
|
-
* All children of the key will have their values redacted unless `fullSecretKey` or `customObject` has precedence.
|
|
35
|
+
`redact()` / `redactSync()` leave the input untouched by default (copy-on-write). Primitives, `Date`, and `null`/`undefined` at the root are returned unchanged.
|
|
142
36
|
|
|
143
|
-
|
|
144
|
-
- **Type:** `RegExp[]`
|
|
145
|
-
- **Default:** `[]`
|
|
146
|
-
- **Effect:** Matches keys in objects or child objects and deeply redacts all values, including values in child objects or objects within arrays.
|
|
147
|
-
- _Note: has higher precedence than `secretKeys`._
|
|
37
|
+
### Preview changes with `dryRun`
|
|
148
38
|
|
|
149
|
-
#### Example
|
|
150
|
-
##### Code
|
|
151
39
|
```typescript
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
timestamp: "2024-12-01T22:07:26.448Z",
|
|
155
|
-
userId: 271,
|
|
156
|
-
contactInfo: {
|
|
157
|
-
email: "foo.bar@example.com",
|
|
158
|
-
firstName: "Foo",
|
|
159
|
-
lastName: "Bar",
|
|
160
|
-
Salutation: "Mr.",
|
|
161
|
-
lastUpdatedBy: {
|
|
162
|
-
id: 1
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
someSecretData: ["fizz", "buzz", { deep: "FOO", name: "BAR" }]
|
|
166
|
-
}
|
|
167
|
-
const fieldRedactor = new FieldRedactor({
|
|
168
|
-
deepSecretKeys: [/someSecretData/i, /contactInfo/i]
|
|
169
|
-
});
|
|
170
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
171
|
-
console.log(result);
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
##### Output
|
|
175
|
-
```json
|
|
176
|
-
{
|
|
177
|
-
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
178
|
-
"userId": 271,
|
|
179
|
-
"contactInfo": {
|
|
180
|
-
"email": "REDACTED",
|
|
181
|
-
"firstName": "REDACTED",
|
|
182
|
-
"lastName": "REDACTED",
|
|
183
|
-
"Salutation": "REDACTED",
|
|
184
|
-
"lastUpdatedBy": {
|
|
185
|
-
"id": "REDACTED"
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
"someSecretData": ["REDACTED", "REDACTED", { "deep": "REDACTED", "name": "REDACTED" }]
|
|
189
|
-
}
|
|
40
|
+
const { result, report } = redactor.dryRunSync(payload);
|
|
41
|
+
// report.redactedPaths, report.deletedPaths, report.matchedSchemas, report.pathRules
|
|
190
42
|
```
|
|
191
|
-
> - All values in `contactInfo` were redacted
|
|
192
|
-
> - All values in `someSecretData` were redacted
|
|
193
|
-
|
|
194
|
-
### `fullSecretKeys` Configuration
|
|
195
|
-
* Specifies values which should be stringified and redacted
|
|
196
|
-
* _Note: has higher precedence than `secretKeys` and `deepSecretKeys`_
|
|
197
43
|
|
|
198
|
-
|
|
199
|
-
- **Type:** `RegExp[]`
|
|
200
|
-
- **Default:** `[]`
|
|
201
|
-
- **Effect:** Matches keys and stringifies + redacts their values.
|
|
202
|
-
- Has higher precedence than `secretKeys` and `deepSecretKeys` but lower precedence than `customObjects`.
|
|
44
|
+
## Start here
|
|
203
45
|
|
|
204
|
-
#### Example
|
|
205
|
-
##### Code
|
|
206
|
-
```typescript
|
|
207
|
-
import { FieldRedactor } from 'field-redactor';
|
|
208
|
-
|
|
209
|
-
const myJsonObject = {
|
|
210
|
-
timestamp: "2024-12-01T22:07:26.448Z",
|
|
211
|
-
userId: 271,
|
|
212
|
-
contactInfo: {
|
|
213
|
-
email: "foo.bar@example.com",
|
|
214
|
-
firstName: "Foo",
|
|
215
|
-
lastName: "Bar",
|
|
216
|
-
Salutation: "Mr.",
|
|
217
|
-
preference: "email",
|
|
218
|
-
lastUpdated: "2024-12-01T22:07:26.448Z"
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
const fieldRedactor = new FieldRedactor({
|
|
222
|
-
fullSecretKeys: [/someSecretData/i],
|
|
223
|
-
});
|
|
224
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
225
|
-
console.log(result);
|
|
226
46
|
```
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
{
|
|
231
|
-
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
232
|
-
"userId": 271,
|
|
233
|
-
"contactInfo": "REDACTED"
|
|
234
|
-
}
|
|
47
|
+
Do you know which JSON keys are always sensitive?
|
|
48
|
+
├─ yes → Shallow / Deep / Opaque / Remove (see secret key modes guide)
|
|
49
|
+
└─ only sometimes → shaped objects like { name, value }? → Schema rules (see metadata guide)
|
|
235
50
|
```
|
|
236
|
-
> - Entirity of `contactInfo` was redacted.
|
|
237
51
|
|
|
238
|
-
|
|
239
|
-
* Specifies values which should be completely deleted.
|
|
52
|
+
**Precedence:** Schema → Opaque → Deep → Remove → Shallow → Value-pattern
|
|
240
53
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
54
|
+
| Concept | Config field |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| Shallow | `secretKeys` |
|
|
57
|
+
| Deep | `deepSecretKeys` |
|
|
58
|
+
| Opaque | `fullSecretKeys` |
|
|
59
|
+
| Remove | `deleteSecretKeys` |
|
|
60
|
+
| Schema | `customObjects` |
|
|
246
61
|
|
|
247
|
-
|
|
248
|
-
##### Code
|
|
249
|
-
```typescript
|
|
250
|
-
import { FieldRedactor } from 'field-redactor';
|
|
62
|
+
Use `FieldRedactor.createSafe({ ... })` or `FieldRedactorConfigBuilder` so you never accidentally redact every field. `new FieldRedactor()` without rules still redacts all values (legacy default).
|
|
251
63
|
|
|
252
|
-
|
|
253
|
-
timestamp: "2024-12-01T22:07:26.448Z",
|
|
254
|
-
userId: 271,
|
|
255
|
-
appAuthKey: "12345-67890"
|
|
256
|
-
}
|
|
257
|
-
const fieldRedactor = new FieldRedactor({
|
|
258
|
-
deleteSecretKeys: [/authKey/i],
|
|
259
|
-
});
|
|
260
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
261
|
-
console.log(result);
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
##### Output
|
|
265
|
-
```json
|
|
266
|
-
{
|
|
267
|
-
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
268
|
-
"userId": 271
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
> - `appAuthKey` was deleted
|
|
64
|
+
## Documentation
|
|
272
65
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
66
|
+
| Guide | Description |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| [Secret key modes](docs/guides/secret-key-modes.md) | Shallow, Deep, Opaque, Remove with examples |
|
|
69
|
+
| [Metadata redaction](docs/guides/metadata-redaction.md) | `{ name, value }` schemas and sibling-key rules |
|
|
70
|
+
| [Anti-patterns](docs/guides/anti-patterns.md) | Common config mistakes and fixes |
|
|
71
|
+
| [Value-pattern redaction](docs/guides/value-pattern-redaction.md) | Detect PII in free-text field values |
|
|
72
|
+
| [Path rules & allowlists](docs/guides/path-rules.md) | Target stable JSON paths; exempt keys under deep redaction |
|
|
73
|
+
| [Configuration reference](docs/reference/config.md) | Full option table, API, presets, validation |
|
|
74
|
+
| [Migration 1.5 → 1.6](docs/guides/migration-1.5-to-1.6.md) | Upgrade from 1.5.x (path rules, naming, exports) |
|
|
75
|
+
| [Migration 1.2 → 1.5](docs/guides/migration-1.2-to-1.5.md) | Upgrade from the previous npm line |
|
|
76
|
+
| [Release notes](docs/release-notes/README.md) | Per-version notes for every published tag |
|
|
77
|
+
| [Contributing](CONTRIBUTING.md) | Layout, precedence, naming, and local workflow |
|
|
276
78
|
|
|
277
|
-
|
|
278
|
-
- **Type:** `CustomObject` (See `CustomObject` Schema Section)
|
|
279
|
-
- **Default:** `[]`
|
|
280
|
-
- **Effect:** Any object that matches the schema will be redacted based on its schema.
|
|
281
|
-
- _Note: has highest precedence_
|
|
282
|
-
- -_Note: If a custom object is nested inside another, the child takes precedence_
|
|
79
|
+
## API surface
|
|
283
80
|
|
|
284
|
-
#### `CustomObject` Schema
|
|
285
81
|
```typescript
|
|
286
|
-
{
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
- `value`:
|
|
295
|
-
- **Type:** `CustomObjectMatchType | string`
|
|
296
|
-
- **Effect:** Specifies how the value should be redacted
|
|
297
|
-
- `string` - checks if a sibling key with this name exists and contains a secret value. If so, redacts according to the secret specifier.
|
|
298
|
-
- `CustomObjectMatchType` - Redacts according to the match type.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
#### `CustomObjectMatchType` Enum
|
|
302
|
-
Specifies how a value should be redacted in a CustomObject if not using a `string` sibling specifier.
|
|
303
|
-
|
|
304
|
-
| Key | Description |
|
|
305
|
-
| --- | ----------- |
|
|
306
|
-
| `Delete` | Delete the value from the result. |
|
|
307
|
-
| `Full` | Stringify value and redact. |
|
|
308
|
-
| `Deep` | Redact if primitive and deeply redact if object or array. |
|
|
309
|
-
| `Shallow` | Redact if primitive or array of primitives and revert to normal rules otherwise, including objects in arrays. |
|
|
310
|
-
| `Pass` | Do not redact, but revert to normal rules for child objects or objects in arrays. |
|
|
311
|
-
| `Ignore` | Skip evaluation entirely. |
|
|
312
|
-
|
|
313
|
-
#### Example
|
|
314
|
-
```typescript
|
|
315
|
-
import { FieldRedactor, CustomObjectMatchType } from 'field-redactor';
|
|
316
|
-
|
|
317
|
-
const myCustomObject1 = {
|
|
318
|
-
shallow: CustomObjectMatchType.Shallow,
|
|
319
|
-
deep: CustomObjectMatchType.Deep,
|
|
320
|
-
full: CustomObjectMatchType.Full,
|
|
321
|
-
delete: CustomObjectMatchType.Delete
|
|
322
|
-
pass: CustomObjectMatchType.Pass,
|
|
323
|
-
ignore: CustomObjectMatchType.Ignore
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
const myCustomObject2 = {
|
|
327
|
-
name: CustomObjectMatchType.Ignore,
|
|
328
|
-
type: CustomObjectMatchType.Ignore,
|
|
329
|
-
shallowValue: "name",
|
|
330
|
-
deepValue: "type",
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const myJsonObject = {
|
|
334
|
-
timestamp: "2024-12-01T22:07:26.448Z",
|
|
335
|
-
userId: 271,
|
|
336
|
-
data: [
|
|
337
|
-
{
|
|
338
|
-
shallow: "hello",
|
|
339
|
-
deep: "hello",
|
|
340
|
-
full: "hello",
|
|
341
|
-
delete: "hello",
|
|
342
|
-
pass: "hello",
|
|
343
|
-
ignore: "hello"
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
name: "email",
|
|
347
|
-
type: "Secure",
|
|
348
|
-
shallowValue: "foo.bar@example.com",
|
|
349
|
-
deepValue: "foobar",
|
|
350
|
-
},
|
|
351
|
-
{
|
|
352
|
-
shallow: {
|
|
353
|
-
hello: "world",
|
|
354
|
-
email: "foobar"
|
|
355
|
-
},
|
|
356
|
-
deep: {
|
|
357
|
-
hello: "world",
|
|
358
|
-
email: "foobar"
|
|
359
|
-
},
|
|
360
|
-
full: {
|
|
361
|
-
hello: "world",
|
|
362
|
-
email: "foobar"
|
|
363
|
-
},
|
|
364
|
-
delete: {
|
|
365
|
-
hello: "world",
|
|
366
|
-
email: "foobar"
|
|
367
|
-
},
|
|
368
|
-
pass: {
|
|
369
|
-
hello: "world",
|
|
370
|
-
email: "foobar"
|
|
371
|
-
},
|
|
372
|
-
ignore: {
|
|
373
|
-
hello: "world",
|
|
374
|
-
email: "foobar"
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
{
|
|
378
|
-
name: "email",
|
|
379
|
-
type: "Secure",
|
|
380
|
-
shallowValue: {
|
|
381
|
-
hello: "world",
|
|
382
|
-
email: "foobar"
|
|
383
|
-
},
|
|
384
|
-
deepValue: {
|
|
385
|
-
hello: "world",
|
|
386
|
-
email: "foobar"
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
]
|
|
390
|
-
};
|
|
391
|
-
const fieldRedactor = new FieldRedactor({
|
|
392
|
-
secretKeys: [/email/],
|
|
393
|
-
deepSecretKeys: [/secure/i],
|
|
394
|
-
fullSecretKeys: [/meta/i],
|
|
395
|
-
customObjects: [myCustomObject1, myCustomObject2]
|
|
396
|
-
});
|
|
397
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
398
|
-
console.log(result);
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
##### Output
|
|
402
|
-
```json
|
|
403
|
-
{
|
|
404
|
-
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
405
|
-
"userId": 271,
|
|
406
|
-
"data": [
|
|
407
|
-
{
|
|
408
|
-
"shallow": "REDACTED",
|
|
409
|
-
"deep": "REDACTED",
|
|
410
|
-
"full": "REDACTED",
|
|
411
|
-
"pass": "hello",
|
|
412
|
-
"ignore": "hello"
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
"name": "email",
|
|
416
|
-
"type": "Secure",
|
|
417
|
-
"shallowValue": "REDACTED",
|
|
418
|
-
"deepValue": "REDACTED"
|
|
419
|
-
},
|
|
420
|
-
{
|
|
421
|
-
"shallow": {
|
|
422
|
-
"hello": "world",
|
|
423
|
-
"email": "REDACTED"
|
|
424
|
-
},
|
|
425
|
-
"deep": {
|
|
426
|
-
"hello": "REDACTED",
|
|
427
|
-
"email": "REDACTED"
|
|
428
|
-
},
|
|
429
|
-
"full": "REDACTED",
|
|
430
|
-
"pass": {
|
|
431
|
-
"hello": "world",
|
|
432
|
-
"email": "REDACTED"
|
|
433
|
-
},
|
|
434
|
-
"ignore": {
|
|
435
|
-
"hello": "world",
|
|
436
|
-
"email": "foobar"
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
{
|
|
440
|
-
"name": "email",
|
|
441
|
-
"type": "Secure",
|
|
442
|
-
"shallowValue": {
|
|
443
|
-
"hello": "world",
|
|
444
|
-
"email": "REDACTED"
|
|
445
|
-
},
|
|
446
|
-
"deepValue": {
|
|
447
|
-
"hello": "REDACTED",
|
|
448
|
-
"email": "REDACTED"
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
]
|
|
452
|
-
}
|
|
453
|
-
```
|
|
454
|
-
> - Example shows both primitives and objects to highlight differences
|
|
455
|
-
|
|
456
|
-
### `ignoreBooleans` Configuration
|
|
457
|
-
- **Type:** `boolean`
|
|
458
|
-
- **Default:** `false`
|
|
459
|
-
- **Effect:** Specifies if boolean values should be redacted.
|
|
460
|
-
|
|
461
|
-
### Example
|
|
462
|
-
#### Code
|
|
463
|
-
```typescript
|
|
464
|
-
import { FieldRedactor } from 'field-redactor';
|
|
465
|
-
|
|
466
|
-
const myJsonObject = {
|
|
467
|
-
foo: "bar",
|
|
468
|
-
fizz: false,
|
|
469
|
-
buzz: true
|
|
470
|
-
};
|
|
471
|
-
const fieldRedactor = new FieldRedactor({
|
|
472
|
-
ignoreBooleans: true,
|
|
473
|
-
secretKeys: [/foo/, /fizz/, /buzz/]
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
477
|
-
console.log(result);
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
#### Output
|
|
481
|
-
```json
|
|
482
|
-
{
|
|
483
|
-
"foo": "REDACTED",
|
|
484
|
-
"fizz": false,
|
|
485
|
-
"buzz": true
|
|
486
|
-
}
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
### `ignoreNullOrUndefined` Configuration
|
|
490
|
-
- **Type:** `boolean`
|
|
491
|
-
- **Default:** `true`
|
|
492
|
-
- **Effect:** Specifies if null or undefined values shold be redacted.
|
|
493
|
-
- *Note: Ensure custom redaction function can appropriately handle null or undefined if set to false.*
|
|
494
|
-
|
|
495
|
-
### Example
|
|
496
|
-
#### Code
|
|
497
|
-
```typescript
|
|
498
|
-
const myJsonObject = {
|
|
499
|
-
foo: "bar",
|
|
500
|
-
fizz: null,
|
|
501
|
-
buzz: undefined
|
|
502
|
-
};
|
|
503
|
-
const fieldRedactor = new FieldRedactor({
|
|
504
|
-
ignoreNullOrUndefined: false
|
|
505
|
-
});
|
|
82
|
+
import {
|
|
83
|
+
FieldRedactor,
|
|
84
|
+
FieldRedactorConfigBuilder,
|
|
85
|
+
FieldRedactorConfigurationError,
|
|
86
|
+
FieldRedactorError,
|
|
87
|
+
presets,
|
|
88
|
+
validateFieldRedactorConfig
|
|
89
|
+
} from 'field-redactor';
|
|
506
90
|
|
|
507
|
-
|
|
508
|
-
console.log(result);
|
|
91
|
+
import type { DryRunPathRule, RedactionRuleLabel, MatchedSchemaReport } from 'field-redactor';
|
|
509
92
|
```
|
|
510
|
-
#### Output
|
|
511
|
-
```json
|
|
512
|
-
{
|
|
513
|
-
"foo": "REDACTED",
|
|
514
|
-
"fizz": "REDACTED",
|
|
515
|
-
"buzz": "REDACTED"
|
|
516
|
-
}
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
## Full Example
|
|
520
|
-
The following example illustrates the power and utility of this library when conditionally redacting JSON output for logging or other purposes. It allows users to specify the manner of redaction, which fields should be redacted and how, and specify custom object schemas with highly configurable redaction logic based on sibling keys or set rules. I find it a quite useful tool!
|
|
521
93
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const myRedactor = (text: string) => Promise.resolve("REDACTED");
|
|
526
|
-
const metadataCustomObject: CustomObject = {
|
|
527
|
-
name: CustomObjectMatchTypes.Pass,
|
|
528
|
-
type: CustomObjectMatchTypes.Pass,
|
|
529
|
-
id: CustomObjectMatchTypes.Shallow,
|
|
530
|
-
value: "name"
|
|
531
|
-
};
|
|
94
|
+
- **Sync:** `redactSync()`, `redactInPlaceSync()`, `dryRunSync()`
|
|
95
|
+
- **Async:** `redact()`, `redactInPlace()`, `dryRun()` (sync path when no async-only `redactor`)
|
|
96
|
+
- **Presets:** `presets.loggingMetadata()`, `presets.applicationLogging()`, `presets.keyValueEntries()`
|
|
532
97
|
|
|
533
|
-
|
|
534
|
-
userId: CustomObjectMatchTypes.Pass,
|
|
535
|
-
field: CustomObjectMatchTypes.Pass,
|
|
536
|
-
action: CustomObjectMatchTypes.Pass,
|
|
537
|
-
value: "field"
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const fieldRedactor: FieldRedactor = new FieldRedactor({
|
|
541
|
-
redactor: myRedactor,
|
|
542
|
-
secretKeys: [/email/, /name/i, /someSecretData/, /children/],
|
|
543
|
-
deepSecretKeys: [/accountInfo/i, /someDeepSecretData/i, /privateInfo/i],
|
|
544
|
-
deleteSecretKeys: [/authKey/i],
|
|
545
|
-
customObjects: [metadataCustomObject, actionsCustomObject],
|
|
546
|
-
ignoreNullOrUndefined: false
|
|
547
|
-
});
|
|
98
|
+
## Why this library exists
|
|
548
99
|
|
|
549
|
-
|
|
550
|
-
timestamp: "2024-12-01T22:07:26.448Z",
|
|
551
|
-
userId: 271,
|
|
552
|
-
authKey: 12345,
|
|
553
|
-
contactInfo: {
|
|
554
|
-
email: "foo.bar@example.com",
|
|
555
|
-
salutation: "Mr.",
|
|
556
|
-
firstName: "Foo",
|
|
557
|
-
lastName: "Bar",
|
|
558
|
-
dob: "1980-01-01",
|
|
559
|
-
backupEmail: undefined,
|
|
560
|
-
preference: "email",
|
|
561
|
-
lastUpdated: "2024-12-01T22:07:26.448Z"
|
|
562
|
-
},
|
|
563
|
-
someSecretData: ["fizz", "buzz", { deep: "is not redacted", name: "foobar" }],
|
|
564
|
-
accountInfo: {
|
|
565
|
-
balance: 123.45,
|
|
566
|
-
institution: "FizzBuz International"
|
|
567
|
-
information: {
|
|
568
|
-
routingNumber: 11111111,
|
|
569
|
-
acctNumber: 222222
|
|
570
|
-
}
|
|
571
|
-
},
|
|
572
|
-
actions: [
|
|
573
|
-
{
|
|
574
|
-
userId: 271,
|
|
575
|
-
field: "email",
|
|
576
|
-
action: "CREATE",
|
|
577
|
-
value: "foo.bar@example.com"
|
|
578
|
-
},
|
|
579
|
-
{
|
|
580
|
-
userId: 271,
|
|
581
|
-
field: "preference",
|
|
582
|
-
action: "UPDATE",
|
|
583
|
-
value: "email"
|
|
584
|
-
}
|
|
585
|
-
],
|
|
586
|
-
metadata: [
|
|
587
|
-
{
|
|
588
|
-
name: "mdn",
|
|
589
|
-
type: "Number",
|
|
590
|
-
id: 12,
|
|
591
|
-
value: 16151112222
|
|
592
|
-
},
|
|
593
|
-
{
|
|
594
|
-
name: "children",
|
|
595
|
-
type: "Array",
|
|
596
|
-
id: 20,
|
|
597
|
-
value: ["John", "Paul","Ringo", "George"]
|
|
598
|
-
},
|
|
599
|
-
{
|
|
600
|
-
name: "traceId",
|
|
601
|
-
type: "String",
|
|
602
|
-
id: 10,
|
|
603
|
-
value: "1234-6587"
|
|
604
|
-
},
|
|
605
|
-
{
|
|
606
|
-
name: "privateInfo",
|
|
607
|
-
type: "Object",
|
|
608
|
-
id: 20,
|
|
609
|
-
value: {
|
|
610
|
-
mySecretThings: {
|
|
611
|
-
a: "foo",
|
|
612
|
-
b: "bar"
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
],
|
|
617
|
-
hobbies: ["Basketball", "Baseball", "Tennis"],
|
|
618
|
-
someDeepSecretData: ["fizz", "buzz", { deep: "is redacted", name: "foobar" }],
|
|
619
|
-
someFullSecretData: {
|
|
620
|
-
foo: "bar"
|
|
621
|
-
},
|
|
622
|
-
someFullSecretData2: ["a", 1, "12"]
|
|
623
|
-
};
|
|
624
|
-
|
|
625
|
-
const result = await fieldRedactor.redact(myJsonObject);
|
|
626
|
-
console.log(result);
|
|
627
|
-
```
|
|
628
|
-
|
|
629
|
-
##### Output
|
|
630
|
-
```json
|
|
631
|
-
{
|
|
632
|
-
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
633
|
-
"userId": 271,
|
|
634
|
-
"contactInfo": {
|
|
635
|
-
"email": "REDACTED",
|
|
636
|
-
"salutation": "Mr.",
|
|
637
|
-
"firstName": "REDACTED",
|
|
638
|
-
"lastName": "REDACTED",
|
|
639
|
-
"dob": "REDACTED",
|
|
640
|
-
"backupEmail": "REDACTED",
|
|
641
|
-
"preference": "email",
|
|
642
|
-
"lastUpdated": "2024-12-01T22:07:26.448Z",
|
|
643
|
-
},
|
|
644
|
-
"someSecretData": ["REDACTED", "REDACTED", { "deep": "is not redacted", "name": "REDACTED" }],
|
|
645
|
-
"accountInfo": {
|
|
646
|
-
"balance": "REDACTED",
|
|
647
|
-
"institution": "REDACTED",
|
|
648
|
-
"information": {
|
|
649
|
-
"routingNumber": "REDACTED",
|
|
650
|
-
"acctNumber": "REDACTED"
|
|
651
|
-
}
|
|
652
|
-
},
|
|
653
|
-
"actions": [
|
|
654
|
-
{
|
|
655
|
-
"userId": 271,
|
|
656
|
-
"field": "email",
|
|
657
|
-
"action": "CREATE",
|
|
658
|
-
"value": "REDACTED"
|
|
659
|
-
},
|
|
660
|
-
{
|
|
661
|
-
"userId": 271,
|
|
662
|
-
"field": "preference",
|
|
663
|
-
"action": "UPDATE",
|
|
664
|
-
"value": "email"
|
|
665
|
-
}
|
|
666
|
-
],
|
|
667
|
-
"metadata": [
|
|
668
|
-
{
|
|
669
|
-
"name": "mdn",
|
|
670
|
-
"type": "Number",
|
|
671
|
-
"id": "REDACTED",
|
|
672
|
-
"value": "REDACTED"
|
|
673
|
-
},
|
|
674
|
-
{
|
|
675
|
-
"name": "children",
|
|
676
|
-
"type": "Array",
|
|
677
|
-
"id": "REDACTED",
|
|
678
|
-
"value": ["REDACTED", "REDACTED", "REDACTED", "REDACTED"]
|
|
679
|
-
},
|
|
680
|
-
{
|
|
681
|
-
"name": "traceId",
|
|
682
|
-
"type": "String",
|
|
683
|
-
"id": 10,
|
|
684
|
-
"value": "1234-6587"
|
|
685
|
-
},
|
|
686
|
-
{
|
|
687
|
-
"name": "privateInfo",
|
|
688
|
-
"type": "Object",
|
|
689
|
-
"id": "REDACTED",
|
|
690
|
-
"value": {
|
|
691
|
-
"mySecretThings": {
|
|
692
|
-
"a": "REDACTED",
|
|
693
|
-
"b": "REDACTED"
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
],
|
|
698
|
-
"hobbies": ["Basketball", "Baseball", "Tennis"],
|
|
699
|
-
"someDeepSecretData": ["REDACTED", "REDACTED", { "deep": "REDACTED", "name": "REDACTED" }],
|
|
700
|
-
"someFullSecretData": "REDACTED",
|
|
701
|
-
"someFullSecretData2": "REDACTED"
|
|
702
|
-
}
|
|
703
|
-
```
|
|
100
|
+
Many log payloads encode sensitivity in sibling fields rather than key names — for example `{ name: "email", value: "user@example.com" }`. FieldRedactor matches object **schemas** and applies rules based on a sibling's value. See [Metadata redaction](docs/guides/metadata-redaction.md) for the full pattern.
|