-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreplacer.ts
123 lines (101 loc) · 2.77 KB
/
replacer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import qs from "qs";
import { redact } from ".";
import { canBeRedacted } from "./can-be-redacted";
import { isPlainObject } from "./is-plain-object";
import { safelyConvertToObject } from "./safely-convert-to-object";
import { safelyParseRelaxedJson } from "./safely-parse-relaxed-json";
import { safelyParseUrl } from "./safely-parse-url";
import type { Data, RedactOptions } from "./types";
export const replacer =
(options: RedactOptions) => (_key: string, data: Data) => {
const { list = [], redactString = "[REDACTED]" } = options;
/**
* If the data has already been redacted we don't want to
* try and convert it to an array by mistake i.e [REDACTED]
*/
if (typeof data === "string" && data === redactString) {
return data;
}
/**
* If the string can be converted to a number we return it back as a string
* so json parse doesn't get a hold of it and convert it to a number
*/
if (typeof data === "string" && !Number.isNaN(Number.parseInt(data))) {
return data;
}
/**
* Return Arrays
*/
if (Array.isArray(data)) {
return data;
}
/**
* Convert Map to object or Set to Array
*/
if (data instanceof Map || data instanceof Set) {
return redact(
data instanceof Set ? Array.from(data) : Object.fromEntries(data),
options,
);
}
/**
* Handle Strings, HTML, JSON, YML, URLs etc
*/
if (typeof data === "string") {
// IS RELAXED JSON?
const obj = safelyParseRelaxedJson(data);
if (obj) {
return redact(obj, options);
}
// IS URL?
const result = safelyParseUrl(data);
if (typeof result !== "string") {
if (result.parsedUrl) {
const clone = { ...result.parsedUrl };
clone.query = redact(result.parsedUrl.query, options);
const u = new URL(clone.url);
u.search = qs.stringify(clone.query, { encode: false });
return u.href;
}
if (result.parsedQuery) {
const clone = redact(result.parsedQuery, options);
return qs.stringify(clone, { encode: false });
}
}
return data;
}
/**
* Handle Plain Object
*/
if (isPlainObject(data)) {
for (const key in data) {
// the key could be blacklisted but the data[key] could be json
if (typeof data[key] === "string" && data[key] !== redactString) {
data[key] = redact(data[key], options);
}
data[key] = canBeRedacted({ key, value: data[key], list })
? redactString
: data[key];
}
return data;
}
// TODO:
// Handle WeakMaps
// Handle WeakSets
// Handle Symbols
// Handle Number & BigInt
// Handle Functions
/**
* handle other object types
*
* Date, RegExp, class
*/
if (typeof data === "object") {
const obj = safelyConvertToObject(data);
if (!obj) {
return data;
}
return redact(obj, options);
}
return data;
};