field-redactor 1.0.0 → 1.2.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/README.md +133 -107
- package/dist/{customObjectChecker.d.ts → customObjectManager.d.ts} +3 -3
- package/dist/customObjectManager.d.ts.map +1 -0
- package/dist/{customObjectChecker.js → customObjectManager.js} +7 -20
- package/dist/customObjectManager.js.map +1 -0
- package/dist/errors.d.ts +0 -6
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -11
- package/dist/errors.js.map +1 -1
- package/dist/fieldRedactor.d.ts +6 -3
- package/dist/fieldRedactor.d.ts.map +1 -1
- package/dist/fieldRedactor.js +17 -11
- package/dist/fieldRedactor.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/objectRedactor.d.ts +8 -8
- package/dist/objectRedactor.d.ts.map +1 -1
- package/dist/objectRedactor.js +91 -64
- package/dist/objectRedactor.js.map +1 -1
- package/dist/primitiveRedactor.d.ts.map +1 -1
- package/dist/primitiveRedactor.js +2 -7
- package/dist/primitiveRedactor.js.map +1 -1
- package/dist/secretManager.d.ts +7 -0
- package/dist/secretManager.d.ts.map +1 -1
- package/dist/secretManager.js +13 -1
- package/dist/secretManager.js.map +1 -1
- package/dist/types.d.ts +10 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -5
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/customObjectChecker.d.ts.map +0 -1
- package/dist/customObjectChecker.js.map +0 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ In many instances, redaction of sensitive data from log output is fairly straigh
|
|
|
18
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
19
|
|
|
20
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
|
|
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
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
import { FieldRedactor } from 'field-redactor';
|
|
@@ -27,15 +27,19 @@ const fieldRedactor = new FieldRedactor();
|
|
|
27
27
|
|
|
28
28
|
// return redacted result
|
|
29
29
|
const result = await fieldRedactor.redact(myJsonObject);
|
|
30
|
+
const primitiveResult = await fieldRedactor.redact("foobar");
|
|
30
31
|
console.log(myJsonObject); // { foo: "bar", fizz: null }
|
|
31
32
|
console.log(result); // { foo: "REDACTED", fizz: null }
|
|
33
|
+
console.log(primitiveResult); // "foobar"
|
|
32
34
|
|
|
33
35
|
// redact in place
|
|
34
36
|
await fieldRedactor.redactInPlace(myJsonObject);
|
|
35
37
|
console.log(myJsonObject); // { foo: "REDACTED", fizz: null }
|
|
36
38
|
```
|
|
37
|
-
> **Note:** `null` and `undefined` values are not redacted by default.
|
|
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.
|
|
39
43
|
|
|
40
44
|
|
|
41
45
|
## Customization
|
|
@@ -48,6 +52,7 @@ The true power of this tool comes from its customization. FieldRedactor can be c
|
|
|
48
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. |
|
|
49
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. |
|
|
50
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. |
|
|
51
56
|
| `customObjects` | `CustomObject[]` | `[]` | Specifies custom objects requiring fine-tuned redaction logic, such as referencing sibling keys. See the "Custom Objects" section for details. |
|
|
52
57
|
| `ignoreBooleans` | `boolean` | `false` | If `true`, booleans will not be redacted even if secret. |
|
|
53
58
|
| `ignoreNullOrUndefined` | `boolean` | `true` | If `true`, `null` and `undefined` values will not be redacted. |
|
|
@@ -80,16 +85,14 @@ console.log(result);
|
|
|
80
85
|
```
|
|
81
86
|
|
|
82
87
|
### `secretKeys` Configuration
|
|
83
|
-
|
|
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.
|
|
84
91
|
|
|
85
92
|
#### Details
|
|
86
93
|
- **Type:** `RegExp[]`
|
|
87
|
-
- **Default:** All values considered secret
|
|
88
|
-
|
|
89
|
-
- **Effect:** Matches keys in objects or child objects and redacts their values, if primitive. Arrays are processed recursively, with primitives redacted.
|
|
90
|
-
- If the value is an object it will be assessed using the same logic, regardless of if its key value is a secret.
|
|
91
|
-
- if an array value is an object it will be assessed using the same logic, regardless of if its key value is a secret.
|
|
92
|
-
- Has lowest precedence when compared to `deepSecretKeys`, `fullSecretKeys`, and `customObjects` configurations.
|
|
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.
|
|
93
96
|
|
|
94
97
|
#### Example
|
|
95
98
|
##### Code
|
|
@@ -103,14 +106,11 @@ const myJsonObject = {
|
|
|
103
106
|
firstName: "Foo",
|
|
104
107
|
lastName: "Bar",
|
|
105
108
|
Salutation: "Mr.",
|
|
106
|
-
preference: "email",
|
|
107
|
-
lastUpdated: "2024-12-01T22:07:26.448Z"
|
|
108
109
|
},
|
|
109
110
|
someSecretData: ["fizz", "buzz", { deep: "is not redacted", name: "foobar" }],
|
|
110
|
-
hobbies: ["Basketball", "Baseball", "Tennis"]
|
|
111
111
|
}
|
|
112
112
|
const fieldRedactor = new FieldRedactor({
|
|
113
|
-
secretKeys: [/email/i, /name/i, /
|
|
113
|
+
secretKeys: [/email/i, /name/i, /userid/i, /someSecretData/i],
|
|
114
114
|
});
|
|
115
115
|
const result = await fieldRedactor.redact(myJsonObject);
|
|
116
116
|
console.log(result);
|
|
@@ -120,33 +120,31 @@ console.log(result);
|
|
|
120
120
|
```json
|
|
121
121
|
{
|
|
122
122
|
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
123
|
-
"userId":
|
|
123
|
+
"userId": "REDACTED",
|
|
124
124
|
"contactInfo": {
|
|
125
125
|
"email": "REDACTED",
|
|
126
126
|
"firstName": "REDACTED",
|
|
127
127
|
"lastName": "REDACTED",
|
|
128
128
|
"Salutation": "Mr.",
|
|
129
|
-
"preference": "email",
|
|
130
|
-
"lastUpdated": "2024-12-01T22:07:26.448Z"
|
|
131
129
|
},
|
|
132
|
-
"someSecretData": ["REDACTED", "REDACTED", { "deep": "is not redacted", "name": "REDACTED" }]
|
|
133
|
-
"hobbies": ["Basketball", "Baseball", "Tennis"]
|
|
130
|
+
"someSecretData": ["REDACTED", "REDACTED", { "deep": "is not redacted", "name": "REDACTED" }]
|
|
134
131
|
}
|
|
135
132
|
```
|
|
136
133
|
|
|
137
|
-
> -
|
|
138
|
-
> -
|
|
139
|
-
> -
|
|
140
|
-
> - object in `someSecretData` was evaluated separate from primitives in the same array
|
|
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
|
|
141
137
|
|
|
142
138
|
### `deepSecretKeys` Configuration
|
|
143
|
-
|
|
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.
|
|
144
142
|
|
|
145
143
|
#### Details
|
|
146
144
|
- **Type:** `RegExp[]`
|
|
147
145
|
- **Default:** `[]`
|
|
148
146
|
- **Effect:** Matches keys in objects or child objects and deeply redacts all values, including values in child objects or objects within arrays.
|
|
149
|
-
-
|
|
147
|
+
- _Note: has higher precedence than `secretKeys`._
|
|
150
148
|
|
|
151
149
|
#### Example
|
|
152
150
|
##### Code
|
|
@@ -160,16 +158,11 @@ const myJsonObject = {
|
|
|
160
158
|
firstName: "Foo",
|
|
161
159
|
lastName: "Bar",
|
|
162
160
|
Salutation: "Mr.",
|
|
163
|
-
preference: "email",
|
|
164
|
-
lastUpdated: "2024-12-01T22:07:26.448Z",
|
|
165
161
|
lastUpdatedBy: {
|
|
166
|
-
|
|
167
|
-
lastName: "Doe",
|
|
168
|
-
id: "12345"
|
|
162
|
+
id: 1
|
|
169
163
|
}
|
|
170
164
|
},
|
|
171
|
-
someSecretData: ["fizz", "buzz", { deep: "FOO", name: "BAR" }]
|
|
172
|
-
hobbies: ["Basketball", "Baseball", "Tennis", {contactInfo: "foobar"}]
|
|
165
|
+
someSecretData: ["fizz", "buzz", { deep: "FOO", name: "BAR" }]
|
|
173
166
|
}
|
|
174
167
|
const fieldRedactor = new FieldRedactor({
|
|
175
168
|
deepSecretKeys: [/someSecretData/i, /contactInfo/i]
|
|
@@ -188,28 +181,24 @@ console.log(result);
|
|
|
188
181
|
"firstName": "REDACTED",
|
|
189
182
|
"lastName": "REDACTED",
|
|
190
183
|
"Salutation": "REDACTED",
|
|
191
|
-
"preference": "REDACTED",
|
|
192
|
-
"lastUpdated": "REDACTED",
|
|
193
184
|
"lastUpdatedBy": {
|
|
194
|
-
"firstName": "REDACTED",
|
|
195
|
-
"lastName": "REDACTED",
|
|
196
185
|
"id": "REDACTED"
|
|
197
186
|
}
|
|
198
187
|
},
|
|
199
|
-
"someSecretData": ["REDACTED", "REDACTED", { "deep": "REDACTED", "name": "REDACTED" }]
|
|
200
|
-
"hobbies": ["Basketball", "Baseball", "Tennis", { "contactInfo": "REDACTED" }]
|
|
188
|
+
"someSecretData": ["REDACTED", "REDACTED", { "deep": "REDACTED", "name": "REDACTED" }]
|
|
201
189
|
}
|
|
202
190
|
```
|
|
203
|
-
> - All values in `contactInfo` were redacted
|
|
204
|
-
> - All values in `someSecretData` were redacted
|
|
191
|
+
> - All values in `contactInfo` were redacted
|
|
192
|
+
> - All values in `someSecretData` were redacted
|
|
205
193
|
|
|
206
194
|
### `fullSecretKeys` Configuration
|
|
207
|
-
Specifies values which should be stringified and
|
|
195
|
+
* Specifies values which should be stringified and redacted
|
|
196
|
+
* _Note: has higher precedence than `secretKeys` and `deepSecretKeys`_
|
|
208
197
|
|
|
209
198
|
#### Details
|
|
210
199
|
- **Type:** `RegExp[]`
|
|
211
200
|
- **Default:** `[]`
|
|
212
|
-
- **Effect:** Matches keys
|
|
201
|
+
- **Effect:** Matches keys and stringifies + redacts their values.
|
|
213
202
|
- Has higher precedence than `secretKeys` and `deepSecretKeys` but lower precedence than `customObjects`.
|
|
214
203
|
|
|
215
204
|
#### Example
|
|
@@ -227,12 +216,10 @@ const myJsonObject = {
|
|
|
227
216
|
Salutation: "Mr.",
|
|
228
217
|
preference: "email",
|
|
229
218
|
lastUpdated: "2024-12-01T22:07:26.448Z"
|
|
230
|
-
}
|
|
231
|
-
someSecretData: ["fizz", "buzz", { deep: "foo", name: "bar" }],
|
|
232
|
-
hobbies: ["Basketball", "Baseball", "Tennis"]
|
|
219
|
+
}
|
|
233
220
|
}
|
|
234
221
|
const fieldRedactor = new FieldRedactor({
|
|
235
|
-
fullSecretKeys: [/someSecretData/i
|
|
222
|
+
fullSecretKeys: [/someSecretData/i],
|
|
236
223
|
});
|
|
237
224
|
const result = await fieldRedactor.redact(myJsonObject);
|
|
238
225
|
console.log(result);
|
|
@@ -243,26 +230,58 @@ console.log(result);
|
|
|
243
230
|
{
|
|
244
231
|
"timestamp": "2024-12-01T22:07:26.448Z",
|
|
245
232
|
"userId": 271,
|
|
246
|
-
"contactInfo": "REDACTED"
|
|
247
|
-
"someSecretData": "REDACTED",
|
|
248
|
-
"hobbies": ["Basketball", "Baseball", "Tennis"]
|
|
233
|
+
"contactInfo": "REDACTED"
|
|
249
234
|
}
|
|
250
235
|
```
|
|
251
236
|
> - Entirity of `contactInfo` was redacted.
|
|
252
|
-
|
|
237
|
+
|
|
238
|
+
### `deleteSecretKeys` Configuration
|
|
239
|
+
* Specifies values which should be completely deleted.
|
|
240
|
+
|
|
241
|
+
#### Details
|
|
242
|
+
- **Type:** `RegExp[]`
|
|
243
|
+
- **Default:** `[]`
|
|
244
|
+
- **Effect:** Matches keys and deletes them from output.
|
|
245
|
+
- Has lower precedence than `customObjects`
|
|
246
|
+
|
|
247
|
+
#### Example
|
|
248
|
+
##### Code
|
|
249
|
+
```typescript
|
|
250
|
+
import { FieldRedactor } from 'field-redactor';
|
|
251
|
+
|
|
252
|
+
const myJsonObject = {
|
|
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
|
|
253
272
|
|
|
254
273
|
### `customObjects` Configuration
|
|
255
|
-
**One of the most powerful features of this library and why it was written in the first place.**
|
|
274
|
+
* **One of the most powerful features of this library and why it was written in the first place.**
|
|
275
|
+
* Combining CustomObjects with secrets yields a powerful and highly customizable redaction tool capable of conditionally redacting a broad variety of input JSON objects correctly according to a user-specified schema.
|
|
256
276
|
|
|
257
277
|
#### Details
|
|
258
278
|
- **Type:** `CustomObject` (See `CustomObject` Schema Section)
|
|
259
279
|
- **Default:** `[]`
|
|
260
|
-
- **Effect:** Any object that matches the schema will be
|
|
261
|
-
-
|
|
262
|
-
- If a
|
|
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_
|
|
263
283
|
|
|
264
284
|
#### `CustomObject` Schema
|
|
265
|
-
A custom object takes the following format:
|
|
266
285
|
```typescript
|
|
267
286
|
{
|
|
268
287
|
[key]: CustomObjectMatchType | string
|
|
@@ -271,91 +290,98 @@ A custom object takes the following format:
|
|
|
271
290
|
|
|
272
291
|
- `key`
|
|
273
292
|
- **Type:** `string`
|
|
274
|
-
- **Effect:** Specifies the key
|
|
293
|
+
- **Effect:** Specifies the key to match on.
|
|
275
294
|
- `value`:
|
|
276
295
|
- **Type:** `CustomObjectMatchType | string`
|
|
277
296
|
- **Effect:** Specifies how the value should be redacted
|
|
278
|
-
- `string` - checks if
|
|
279
|
-
- `CustomObjectMatchType` - Redacts according to the match type.
|
|
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.
|
|
280
299
|
|
|
281
300
|
|
|
282
301
|
#### `CustomObjectMatchType` Enum
|
|
302
|
+
Specifies how a value should be redacted in a CustomObject if not using a `string` sibling specifier.
|
|
303
|
+
|
|
283
304
|
| Key | Description |
|
|
284
305
|
| --- | ----------- |
|
|
285
|
-
| `
|
|
286
|
-
| `
|
|
287
|
-
| `
|
|
288
|
-
| `
|
|
289
|
-
| `
|
|
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. |
|
|
290
312
|
|
|
291
313
|
#### Example
|
|
292
314
|
```typescript
|
|
293
|
-
import { FieldRedactor } from 'field-redactor';
|
|
315
|
+
import { FieldRedactor, CustomObjectMatchType } from 'field-redactor';
|
|
294
316
|
|
|
295
|
-
const
|
|
296
|
-
name: CustomObjectMatchType.Ignore,
|
|
297
|
-
type: CustomObjectMatchType.Ignore,
|
|
298
|
-
significance: CustomObjectMatchType.Ignore,
|
|
299
|
-
shallowValue: "name",
|
|
300
|
-
deepValue: "type",
|
|
301
|
-
fullValue: "significance"
|
|
317
|
+
const myCustomObject1 = {
|
|
302
318
|
shallow: CustomObjectMatchType.Shallow,
|
|
303
319
|
deep: CustomObjectMatchType.Deep,
|
|
304
320
|
full: CustomObjectMatchType.Full,
|
|
321
|
+
delete: CustomObjectMatchType.Delete
|
|
305
322
|
pass: CustomObjectMatchType.Pass,
|
|
306
323
|
ignore: CustomObjectMatchType.Ignore
|
|
307
324
|
};
|
|
308
325
|
|
|
326
|
+
const myCustomObject2 = {
|
|
327
|
+
name: CustomObjectMatchType.Ignore,
|
|
328
|
+
type: CustomObjectMatchType.Ignore,
|
|
329
|
+
shallowValue: "name",
|
|
330
|
+
deepValue: "type",
|
|
331
|
+
}
|
|
332
|
+
|
|
309
333
|
const myJsonObject = {
|
|
310
334
|
timestamp: "2024-12-01T22:07:26.448Z",
|
|
311
335
|
userId: 271,
|
|
312
336
|
data: [
|
|
313
337
|
{
|
|
314
|
-
name: "email",
|
|
315
|
-
type: "Secure",
|
|
316
|
-
significance: "meta"
|
|
317
|
-
shallowValue: "foo.bar@example.com",
|
|
318
|
-
deepValue: "foobar",
|
|
319
|
-
fullValue: "hello",
|
|
320
338
|
shallow: "hello",
|
|
321
339
|
deep: "hello",
|
|
322
340
|
full: "hello",
|
|
341
|
+
delete: "hello",
|
|
323
342
|
pass: "hello",
|
|
324
343
|
ignore: "hello"
|
|
325
344
|
},
|
|
326
345
|
{
|
|
327
346
|
name: "email",
|
|
328
347
|
type: "Secure",
|
|
329
|
-
|
|
330
|
-
|
|
348
|
+
shallowValue: "foo.bar@example.com",
|
|
349
|
+
deepValue: "foobar",
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
shallow: {
|
|
331
353
|
hello: "world",
|
|
332
354
|
email: "foobar"
|
|
333
355
|
},
|
|
334
|
-
|
|
356
|
+
deep: {
|
|
335
357
|
hello: "world",
|
|
336
358
|
email: "foobar"
|
|
337
359
|
},
|
|
338
|
-
|
|
360
|
+
full: {
|
|
339
361
|
hello: "world",
|
|
340
362
|
email: "foobar"
|
|
341
363
|
},
|
|
342
|
-
|
|
364
|
+
delete: {
|
|
343
365
|
hello: "world",
|
|
344
366
|
email: "foobar"
|
|
345
367
|
},
|
|
346
|
-
|
|
368
|
+
pass: {
|
|
347
369
|
hello: "world",
|
|
348
370
|
email: "foobar"
|
|
349
371
|
},
|
|
350
|
-
|
|
372
|
+
ignore: {
|
|
351
373
|
hello: "world",
|
|
352
374
|
email: "foobar"
|
|
353
|
-
}
|
|
354
|
-
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
{
|
|
378
|
+
name: "email",
|
|
379
|
+
type: "Secure",
|
|
380
|
+
shallowValue: {
|
|
355
381
|
hello: "world",
|
|
356
382
|
email: "foobar"
|
|
357
383
|
},
|
|
358
|
-
|
|
384
|
+
deepValue: {
|
|
359
385
|
hello: "world",
|
|
360
386
|
email: "foobar"
|
|
361
387
|
}
|
|
@@ -366,7 +392,7 @@ const fieldRedactor = new FieldRedactor({
|
|
|
366
392
|
secretKeys: [/email/],
|
|
367
393
|
deepSecretKeys: [/secure/i],
|
|
368
394
|
fullSecretKeys: [/meta/i],
|
|
369
|
-
customObjects: [
|
|
395
|
+
customObjects: [myCustomObject1, myCustomObject2]
|
|
370
396
|
});
|
|
371
397
|
const result = await fieldRedactor.redact(myJsonObject);
|
|
372
398
|
console.log(result);
|
|
@@ -379,11 +405,6 @@ console.log(result);
|
|
|
379
405
|
"userId": 271,
|
|
380
406
|
"data": [
|
|
381
407
|
{
|
|
382
|
-
"name": "email",
|
|
383
|
-
"type": "Secure",
|
|
384
|
-
"shallowValue": "REDACTED",
|
|
385
|
-
"deepValue": "REDACTED",
|
|
386
|
-
"fullValue": "REDACTED",
|
|
387
408
|
"shallow": "REDACTED",
|
|
388
409
|
"deep": "REDACTED",
|
|
389
410
|
"full": "REDACTED",
|
|
@@ -393,15 +414,10 @@ console.log(result);
|
|
|
393
414
|
{
|
|
394
415
|
"name": "email",
|
|
395
416
|
"type": "Secure",
|
|
396
|
-
"shallowValue":
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
"deepValue": {
|
|
401
|
-
"hello": "REDACTED",
|
|
402
|
-
"email": "REDACTED"
|
|
403
|
-
},
|
|
404
|
-
"fullValue": "REDACTED",
|
|
417
|
+
"shallowValue": "REDACTED",
|
|
418
|
+
"deepValue": "REDACTED"
|
|
419
|
+
},
|
|
420
|
+
{
|
|
405
421
|
"shallow": {
|
|
406
422
|
"hello": "world",
|
|
407
423
|
"email": "REDACTED"
|
|
@@ -420,14 +436,22 @@ console.log(result);
|
|
|
420
436
|
"email": "foobar"
|
|
421
437
|
}
|
|
422
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
|
+
}
|
|
423
451
|
]
|
|
424
|
-
}
|
|
452
|
+
}
|
|
425
453
|
```
|
|
426
|
-
>
|
|
427
|
-
> - The first object contains only primitives whereas the second contains objects to highlight the differences
|
|
428
|
-
> - `name` and `type` field were never redacted in either object because `CustomObjectMatchType` was `Ignore`
|
|
429
|
-
> - `shallowValue`, `deepValue`, and `fullValue` had string key specifiers which matched a `shallowKey`, `deepSecretKey`, and `fullSecretKey`, respectively, and were redacted according to those rules.
|
|
430
|
-
> - `shallow`, `deep`, `full`, `pass`, and `ignore` fields were redacted according to their `CustomObjectMatchType` value specified in the schema.
|
|
454
|
+
> - Example shows both primitives and objects to highlight differences
|
|
431
455
|
|
|
432
456
|
### `ignoreBooleans` Configuration
|
|
433
457
|
- **Type:** `boolean`
|
|
@@ -517,6 +541,7 @@ const fieldRedactor: FieldRedactor = new FieldRedactor({
|
|
|
517
541
|
redactor: myRedactor,
|
|
518
542
|
secretKeys: [/email/, /name/i, /someSecretData/, /children/],
|
|
519
543
|
deepSecretKeys: [/accountInfo/i, /someDeepSecretData/i, /privateInfo/i],
|
|
544
|
+
deleteSecretKeys: [/authKey/i],
|
|
520
545
|
customObjects: [metadataCustomObject, actionsCustomObject],
|
|
521
546
|
ignoreNullOrUndefined: false
|
|
522
547
|
});
|
|
@@ -524,6 +549,7 @@ const fieldRedactor: FieldRedactor = new FieldRedactor({
|
|
|
524
549
|
const myJsonObjectToRedact = {
|
|
525
550
|
timestamp: "2024-12-01T22:07:26.448Z",
|
|
526
551
|
userId: 271,
|
|
552
|
+
authKey: 12345,
|
|
527
553
|
contactInfo: {
|
|
528
554
|
email: "foo.bar@example.com",
|
|
529
555
|
salutation: "Mr.",
|
|
@@ -2,7 +2,7 @@ import { CustomObject } from './types';
|
|
|
2
2
|
/**
|
|
3
3
|
* Utility for determining if a given object matches a CustomObject schema.
|
|
4
4
|
*/
|
|
5
|
-
export declare class
|
|
5
|
+
export declare class CustomObjectManager {
|
|
6
6
|
private customObjects;
|
|
7
7
|
/**
|
|
8
8
|
* Creates a CustomObjectChecker with the specified CustomObjects.
|
|
@@ -16,7 +16,7 @@ export declare class CustomObjectChecker {
|
|
|
16
16
|
*/
|
|
17
17
|
getMatchingCustomObject(value: any): CustomObject | undefined;
|
|
18
18
|
private isCustomObject;
|
|
19
|
-
private
|
|
19
|
+
private objectHasExtraKeys;
|
|
20
20
|
private validateCustomObjects;
|
|
21
21
|
}
|
|
22
|
-
//# sourceMappingURL=
|
|
22
|
+
//# sourceMappingURL=customObjectManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"customObjectManager.d.ts","sourceRoot":"","sources":["../src/customObjectManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAAsB;IAE3C;;;OAGG;gBACS,aAAa,CAAC,EAAE,YAAY,EAAE;IAK1C;;;;OAIG;IACI,uBAAuB,CAAC,KAAK,EAAE,GAAG,GAAG,YAAY,GAAG,SAAS;IASpE,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;CAoB9B"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CustomObjectManager = void 0;
|
|
4
4
|
const errors_1 = require("./errors");
|
|
5
5
|
/**
|
|
6
6
|
* Utility for determining if a given object matches a CustomObject schema.
|
|
7
7
|
*/
|
|
8
|
-
class
|
|
8
|
+
class CustomObjectManager {
|
|
9
9
|
/**
|
|
10
10
|
* Creates a CustomObjectChecker with the specified CustomObjects.
|
|
11
11
|
* @param customObjects The CustomObjects to check against.
|
|
@@ -32,23 +32,10 @@ class CustomObjectChecker {
|
|
|
32
32
|
if (typeof value !== 'object' || !value || Array.isArray(value)) {
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
for (const key of Object.keys(value)) {
|
|
39
|
-
if (!customObject.hasOwnProperty(key)) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return true;
|
|
35
|
+
return !this.objectHasExtraKeys(customObject, value) && !this.objectHasExtraKeys(value, customObject);
|
|
44
36
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (!value.hasOwnProperty(key)) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return true;
|
|
37
|
+
objectHasExtraKeys(object, objectToCompareTo) {
|
|
38
|
+
return Object.keys(object).some((key) => !objectToCompareTo.hasOwnProperty(key));
|
|
52
39
|
}
|
|
53
40
|
validateCustomObjects(customObjects) {
|
|
54
41
|
if (!customObjects || customObjects.length <= 1) {
|
|
@@ -68,5 +55,5 @@ class CustomObjectChecker {
|
|
|
68
55
|
}
|
|
69
56
|
}
|
|
70
57
|
}
|
|
71
|
-
exports.
|
|
72
|
-
//# sourceMappingURL=
|
|
58
|
+
exports.CustomObjectManager = CustomObjectManager;
|
|
59
|
+
//# sourceMappingURL=customObjectManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"customObjectManager.js","sourceRoot":"","sources":["../src/customObjectManager.ts"],"names":[],"mappings":";;;AAAA,qCAA2D;AAG3D;;GAEG;AACH,MAAa,mBAAmB;IAG9B;;;OAGG;IACH,YAAY,aAA8B;QANlC,kBAAa,GAAmB,EAAE,CAAC;QAOzC,IAAI,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,CAAC;IAED;;;;OAIG;IACI,uBAAuB,CAAC,KAAU;QACvC,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC;gBAC7C,OAAO,YAAY,CAAC;YACtB,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,cAAc,CAAC,KAAU,EAAE,YAA0B;QAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACxG,CAAC;IAEO,kBAAkB,CAAC,MAAW,EAAE,iBAAsB;QAC5D,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;IACnF,CAAC;IAEO,qBAAqB,CAAC,aAA8B;QAC1D,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO;QACT,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,OAAO,GAAiB,aAAa,CAAC,CAAC,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClD,MAAM,KAAK,GAAiB,aAAa,CAAC,CAAC,CAAC,CAAC;gBAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjE,IAAI,UAAU,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;oBAChF,MAAM,IAAI,wCAA+B,CACvC,6BAA6B,CAAC,QAAQ,CAAC,gCAAgC,UAAU,EAAE,CACpF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA1DD,kDA0DC"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -11,10 +11,4 @@ export declare class FieldRedactorError extends Error {
|
|
|
11
11
|
export declare class FieldRedactorConfigurationError extends FieldRedactorError {
|
|
12
12
|
constructor(message: string);
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Error thrown when the input value to the FieldRedactor fails validation, such as not being a JSON object.
|
|
16
|
-
*/
|
|
17
|
-
export declare class FieldRedactorValidationError extends FieldRedactorError {
|
|
18
|
-
constructor(message: string);
|
|
19
|
-
}
|
|
20
14
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,qBAAa,+BAAgC,SAAQ,kBAAkB;gBACzD,OAAO,EAAE,MAAM;CAI5B
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,qBAAa,+BAAgC,SAAQ,kBAAkB;gBACzD,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.FieldRedactorConfigurationError = exports.FieldRedactorError = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Top-Level Field Redactor error thrown when there is an error redacting a JSON object.
|
|
6
6
|
*/
|
|
@@ -22,14 +22,4 @@ class FieldRedactorConfigurationError extends FieldRedactorError {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
exports.FieldRedactorConfigurationError = FieldRedactorConfigurationError;
|
|
25
|
-
/**
|
|
26
|
-
* Error thrown when the input value to the FieldRedactor fails validation, such as not being a JSON object.
|
|
27
|
-
*/
|
|
28
|
-
class FieldRedactorValidationError extends FieldRedactorError {
|
|
29
|
-
constructor(message) {
|
|
30
|
-
super(message);
|
|
31
|
-
this.name = 'FieldRedactorValidationError';
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
exports.FieldRedactorValidationError = FieldRedactorValidationError;
|
|
35
25
|
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED;;;GAGG;AACH,MAAa,+BAAgC,SAAQ,kBAAkB;IACrE,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;IAChD,CAAC;CACF;AALD,0EAKC
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED;;;GAGG;AACH,MAAa,+BAAgC,SAAQ,kBAAkB;IACrE,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;IAChD,CAAC;CACF;AALD,0EAKC"}
|
package/dist/fieldRedactor.d.ts
CHANGED
|
@@ -11,15 +11,18 @@ export declare class FieldRedactor {
|
|
|
11
11
|
/**
|
|
12
12
|
* Conditionally redacts fields in the JSON object based on the configuration provided in the constructor and returns the
|
|
13
13
|
* redacted result.
|
|
14
|
-
*
|
|
14
|
+
* If the value is a primitive, undefined, or date, returns the value as-is.
|
|
15
|
+
* @param value The JSON value to redact. If primitive it will be resolved as-is.
|
|
15
16
|
* @returns The redacted JSON object.
|
|
16
17
|
*/
|
|
17
18
|
redact(value: any): Promise<any>;
|
|
18
19
|
/**
|
|
19
20
|
* Conditionally redacts fields in the JSON object in place based on the configuration provided in the constructor.
|
|
20
|
-
*
|
|
21
|
+
* If the value is a primitive, undefined, or date, returns the value as-is.
|
|
22
|
+
* @param value The JSON value to redact in place. If primitive it will be resolved as-is.
|
|
23
|
+
* @returns The redacted JSON object.
|
|
21
24
|
*/
|
|
22
25
|
redactInPlace(value: any): Promise<void>;
|
|
23
|
-
private
|
|
26
|
+
private isPrimitiveOrUndefined;
|
|
24
27
|
}
|
|
25
28
|
//# sourceMappingURL=fieldRedactor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fieldRedactor.d.ts","sourceRoot":"","sources":["../src/fieldRedactor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAO9C;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;gBACpC,MAAM,CAAC,EAAE,mBAAmB;
|
|
1
|
+
{"version":3,"file":"fieldRedactor.d.ts","sourceRoot":"","sources":["../src/fieldRedactor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAO9C;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;gBACpC,MAAM,CAAC,EAAE,mBAAmB;IAyBxC;;;;;;OAMG;IACU,MAAM,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAK7C;;;;;OAKG;IACU,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrD,OAAO,CAAC,sBAAsB;CAG/B"}
|