@uniglot/wont-let-you-see 0.2.0 → 0.3.1
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 +106 -40
- package/dist/index.js +113 -92
- package/package.json +1 -1
- package/patterns/aws.json +28 -0
- package/patterns/common.json +18 -0
- package/patterns/kubernetes.json +8 -0
- package/src/__tests__/masker.test.ts +64 -0
- package/src/__tests__/patterns.test.ts +135 -61
- package/src/masker.ts +62 -58
- package/src/patterns.ts +108 -45
|
@@ -1,21 +1,31 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import {
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { loadPatterns, resetPatternCache, getPatternByName } from "../patterns";
|
|
3
|
+
|
|
4
|
+
function getPattern(name: string) {
|
|
5
|
+
const p = getPatternByName(name);
|
|
6
|
+
if (!p) throw new Error(`Pattern '${name}' not found`);
|
|
7
|
+
return p.pattern;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe("AWS Patterns", () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
resetPatternCache();
|
|
13
|
+
});
|
|
3
14
|
|
|
4
|
-
describe("AWS_PATTERNS", () => {
|
|
5
15
|
describe("ARN", () => {
|
|
6
16
|
it("should match aws partition", () => {
|
|
7
17
|
expect(
|
|
8
|
-
|
|
18
|
+
getPattern("arn").test("arn:aws:iam::123456789012:user/admin"),
|
|
9
19
|
).toBe(true);
|
|
10
20
|
});
|
|
11
21
|
|
|
12
22
|
it("should match aws-cn partition", () => {
|
|
13
|
-
expect(
|
|
23
|
+
expect(getPattern("arn").test("arn:aws-cn:s3:::my-bucket")).toBe(true);
|
|
14
24
|
});
|
|
15
25
|
|
|
16
26
|
it("should match aws-us-gov partition", () => {
|
|
17
27
|
expect(
|
|
18
|
-
|
|
28
|
+
getPattern("arn").test(
|
|
19
29
|
"arn:aws-us-gov:ec2:us-gov-west-1:123456789012:instance/i-123",
|
|
20
30
|
),
|
|
21
31
|
).toBe(true);
|
|
@@ -24,80 +34,86 @@ describe("AWS_PATTERNS", () => {
|
|
|
24
34
|
|
|
25
35
|
describe("VPC resources", () => {
|
|
26
36
|
it("should match vpc", () => {
|
|
27
|
-
expect(
|
|
37
|
+
expect(getPattern("vpc").test("vpc-0123456789abcdef0")).toBe(true);
|
|
28
38
|
});
|
|
29
39
|
|
|
30
40
|
it("should match subnet", () => {
|
|
31
|
-
expect(
|
|
41
|
+
expect(getPattern("subnet").test("subnet-0123456789abcdef0")).toBe(true);
|
|
32
42
|
});
|
|
33
43
|
|
|
34
44
|
it("should match security group", () => {
|
|
35
|
-
expect(
|
|
45
|
+
expect(getPattern("security-group").test("sg-0123456789abcdef0")).toBe(
|
|
36
46
|
true,
|
|
37
47
|
);
|
|
38
48
|
});
|
|
39
49
|
|
|
40
50
|
it("should match nat gateway", () => {
|
|
41
|
-
expect(
|
|
51
|
+
expect(getPattern("nat-gateway").test("nat-0123456789abcdef0")).toBe(
|
|
52
|
+
true,
|
|
53
|
+
);
|
|
42
54
|
});
|
|
43
55
|
|
|
44
56
|
it("should match network acl", () => {
|
|
45
|
-
expect(
|
|
57
|
+
expect(getPattern("network-acl").test("acl-0123456789abcdef0")).toBe(
|
|
58
|
+
true,
|
|
59
|
+
);
|
|
46
60
|
});
|
|
47
61
|
|
|
48
62
|
it("should match eni", () => {
|
|
49
|
-
expect(
|
|
63
|
+
expect(getPattern("eni").test("eni-0123456789abcdef0")).toBe(true);
|
|
50
64
|
});
|
|
51
65
|
});
|
|
52
66
|
|
|
53
67
|
describe("EC2 resources", () => {
|
|
54
68
|
it("should match ebs volume", () => {
|
|
55
|
-
expect(
|
|
69
|
+
expect(getPattern("ebs").test("vol-0123456789abcdef0")).toBe(true);
|
|
56
70
|
});
|
|
57
71
|
|
|
58
72
|
it("should match snapshot", () => {
|
|
59
|
-
expect(
|
|
73
|
+
expect(getPattern("snapshot").test("snap-0123456789abcdef0")).toBe(true);
|
|
60
74
|
});
|
|
61
75
|
});
|
|
62
76
|
|
|
63
77
|
describe("VPC networking resources", () => {
|
|
64
78
|
it("should match vpc endpoint", () => {
|
|
65
|
-
expect(
|
|
79
|
+
expect(getPattern("vpc-endpoint").test("vpce-0123456789abcdef0")).toBe(
|
|
66
80
|
true,
|
|
67
81
|
);
|
|
68
82
|
});
|
|
69
83
|
|
|
70
84
|
it("should match transit gateway", () => {
|
|
71
|
-
expect(
|
|
85
|
+
expect(getPattern("transit-gateway").test("tgw-0123456789abcdef0")).toBe(
|
|
72
86
|
true,
|
|
73
87
|
);
|
|
74
88
|
});
|
|
75
89
|
|
|
76
90
|
it("should match customer gateway", () => {
|
|
77
|
-
expect(
|
|
91
|
+
expect(getPattern("customer-gateway").test("cgw-0123456789abcdef0")).toBe(
|
|
78
92
|
true,
|
|
79
93
|
);
|
|
80
94
|
});
|
|
81
95
|
|
|
82
96
|
it("should match vpn gateway", () => {
|
|
83
|
-
expect(
|
|
97
|
+
expect(getPattern("vpn-gateway").test("vgw-0123456789abcdef0")).toBe(
|
|
98
|
+
true,
|
|
99
|
+
);
|
|
84
100
|
});
|
|
85
101
|
|
|
86
102
|
it("should match vpn connection", () => {
|
|
87
|
-
expect(
|
|
103
|
+
expect(getPattern("vpn-connection").test("vpn-0123456789abcdef0")).toBe(
|
|
88
104
|
true,
|
|
89
105
|
);
|
|
90
106
|
});
|
|
91
107
|
|
|
92
108
|
it("should NOT match invalid vpc endpoint", () => {
|
|
93
|
-
expect(
|
|
109
|
+
expect(getPattern("vpc-endpoint").test("vpce-invalid")).toBe(false);
|
|
94
110
|
});
|
|
95
111
|
});
|
|
96
112
|
|
|
97
113
|
describe("ECR resources", () => {
|
|
98
114
|
it("should match ECR repo URI", () => {
|
|
99
115
|
expect(
|
|
100
|
-
|
|
116
|
+
getPattern("ecr-repo").test(
|
|
101
117
|
"123456789012.dkr.ecr.us-west-2.amazonaws.com/my-repo",
|
|
102
118
|
),
|
|
103
119
|
).toBe(true);
|
|
@@ -105,7 +121,7 @@ describe("AWS_PATTERNS", () => {
|
|
|
105
121
|
|
|
106
122
|
it("should match ECR repo URI with nested path", () => {
|
|
107
123
|
expect(
|
|
108
|
-
|
|
124
|
+
getPattern("ecr-repo").test(
|
|
109
125
|
"123456789012.dkr.ecr.eu-central-1.amazonaws.com/org/app/service",
|
|
110
126
|
),
|
|
111
127
|
).toBe(true);
|
|
@@ -113,7 +129,7 @@ describe("AWS_PATTERNS", () => {
|
|
|
113
129
|
|
|
114
130
|
it("should match ECR repo URI with dots and underscores", () => {
|
|
115
131
|
expect(
|
|
116
|
-
|
|
132
|
+
getPattern("ecr-repo").test(
|
|
117
133
|
"123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my_repo.name",
|
|
118
134
|
),
|
|
119
135
|
).toBe(true);
|
|
@@ -121,21 +137,21 @@ describe("AWS_PATTERNS", () => {
|
|
|
121
137
|
|
|
122
138
|
it("should NOT match invalid ECR URI (wrong account ID length)", () => {
|
|
123
139
|
expect(
|
|
124
|
-
|
|
140
|
+
getPattern("ecr-repo").test(
|
|
125
141
|
"12345.dkr.ecr.us-west-2.amazonaws.com/my-repo",
|
|
126
142
|
),
|
|
127
143
|
).toBe(false);
|
|
128
144
|
});
|
|
129
145
|
|
|
130
146
|
it("should NOT match non-ECR docker registry", () => {
|
|
131
|
-
expect(
|
|
147
|
+
expect(getPattern("ecr-repo").test("docker.io/library/nginx")).toBe(
|
|
132
148
|
false,
|
|
133
149
|
);
|
|
134
150
|
});
|
|
135
151
|
|
|
136
152
|
it("should match ECR repo URI with masked account ID", () => {
|
|
137
153
|
expect(
|
|
138
|
-
|
|
154
|
+
getPattern("ecr-repo").test(
|
|
139
155
|
"#(custom-1).dkr.ecr.us-west-2.amazonaws.com/my-repo",
|
|
140
156
|
),
|
|
141
157
|
).toBe(true);
|
|
@@ -143,7 +159,7 @@ describe("AWS_PATTERNS", () => {
|
|
|
143
159
|
|
|
144
160
|
it("should match ECR repo URI with masked account ID (higher number)", () => {
|
|
145
161
|
expect(
|
|
146
|
-
|
|
162
|
+
getPattern("ecr-repo").test(
|
|
147
163
|
"#(custom-123).dkr.ecr.us-east-1.amazonaws.com/app/service",
|
|
148
164
|
),
|
|
149
165
|
).toBe(true);
|
|
@@ -152,56 +168,60 @@ describe("AWS_PATTERNS", () => {
|
|
|
152
168
|
|
|
153
169
|
describe("Account ID (contextual)", () => {
|
|
154
170
|
it("should match OwnerId field", () => {
|
|
155
|
-
expect(
|
|
171
|
+
expect(getPattern("account-id").test('"OwnerId": "123456789012"')).toBe(
|
|
156
172
|
true,
|
|
157
173
|
);
|
|
158
174
|
});
|
|
159
175
|
|
|
160
176
|
it("should match account_id field (terraform style)", () => {
|
|
161
|
-
expect(
|
|
162
|
-
|
|
163
|
-
);
|
|
177
|
+
expect(
|
|
178
|
+
getPattern("account-id").test('"account_id": "123456789012"'),
|
|
179
|
+
).toBe(true);
|
|
164
180
|
});
|
|
165
181
|
|
|
166
182
|
it("should NOT match bare number", () => {
|
|
167
|
-
expect(
|
|
183
|
+
expect(getPattern("account-id").test("123456789012")).toBe(false);
|
|
168
184
|
});
|
|
169
185
|
});
|
|
170
186
|
|
|
171
187
|
describe("Access Key ID", () => {
|
|
172
188
|
it("should match AKIA prefix", () => {
|
|
173
|
-
expect(
|
|
189
|
+
expect(getPattern("access-key-id").test(" AKIAIOSFODNN7EXAMPLE ")).toBe(
|
|
174
190
|
true,
|
|
175
191
|
);
|
|
176
192
|
});
|
|
177
193
|
|
|
178
194
|
it("should match ASIA prefix (temporary)", () => {
|
|
179
|
-
expect(
|
|
195
|
+
expect(getPattern("access-key-id").test(" ASIAISAMPLEKEYID1234 ")).toBe(
|
|
180
196
|
true,
|
|
181
197
|
);
|
|
182
198
|
});
|
|
183
199
|
|
|
184
200
|
it("should NOT match random string", () => {
|
|
185
|
-
expect(
|
|
201
|
+
expect(getPattern("access-key-id").test("RANDOMSTRING12345678")).toBe(
|
|
202
|
+
false,
|
|
203
|
+
);
|
|
186
204
|
});
|
|
187
205
|
});
|
|
188
206
|
});
|
|
189
207
|
|
|
190
|
-
describe("
|
|
208
|
+
describe("Kubernetes Patterns", () => {
|
|
209
|
+
beforeEach(() => {
|
|
210
|
+
resetPatternCache();
|
|
211
|
+
});
|
|
212
|
+
|
|
191
213
|
describe("Service Account Token", () => {
|
|
192
214
|
it("should match JWT format", () => {
|
|
193
215
|
const jwt =
|
|
194
216
|
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tYWJjZGUiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjEyMzQ1Njc4LTEyMzQtMTIzNC0xMjM0LTEyMzQ1Njc4OTAxMiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.signature";
|
|
195
|
-
expect(
|
|
217
|
+
expect(getPattern("k8s-token").test(jwt)).toBe(true);
|
|
196
218
|
});
|
|
197
219
|
});
|
|
198
220
|
|
|
199
221
|
describe("Node Names", () => {
|
|
200
222
|
it("should match AWS node name", () => {
|
|
201
223
|
expect(
|
|
202
|
-
|
|
203
|
-
"ip-10-0-1-123.us-west-2.compute.internal",
|
|
204
|
-
),
|
|
224
|
+
getPattern("k8s-node").test("ip-10-0-1-123.us-west-2.compute.internal"),
|
|
205
225
|
).toBe(true);
|
|
206
226
|
});
|
|
207
227
|
});
|
|
@@ -209,7 +229,7 @@ describe("K8S_PATTERNS", () => {
|
|
|
209
229
|
describe("Cluster Endpoints", () => {
|
|
210
230
|
it("should match EKS endpoint", () => {
|
|
211
231
|
expect(
|
|
212
|
-
|
|
232
|
+
getPattern("k8s-endpoint").test(
|
|
213
233
|
"https://ABCDEF1234567890ABCD.us-west-2.eks.amazonaws.com",
|
|
214
234
|
),
|
|
215
235
|
).toBe(true);
|
|
@@ -217,14 +237,18 @@ describe("K8S_PATTERNS", () => {
|
|
|
217
237
|
});
|
|
218
238
|
});
|
|
219
239
|
|
|
220
|
-
describe("
|
|
240
|
+
describe("Common Patterns", () => {
|
|
241
|
+
beforeEach(() => {
|
|
242
|
+
resetPatternCache();
|
|
243
|
+
});
|
|
244
|
+
|
|
221
245
|
describe("IPv4", () => {
|
|
222
246
|
it("should match IPv4", () => {
|
|
223
|
-
expect(
|
|
247
|
+
expect(getPattern("ipv4").test("192.168.1.1")).toBe(true);
|
|
224
248
|
});
|
|
225
249
|
|
|
226
250
|
it("should not match CIDR notation", () => {
|
|
227
|
-
expect(
|
|
251
|
+
expect(getPattern("ipv4").test("10.0.0.0/8")).toBe(false);
|
|
228
252
|
});
|
|
229
253
|
});
|
|
230
254
|
|
|
@@ -238,16 +262,16 @@ MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC
|
|
|
238
262
|
-----END PRIVATE KEY-----`;
|
|
239
263
|
|
|
240
264
|
it("should match entire RSA private key block", () => {
|
|
241
|
-
expect(
|
|
265
|
+
expect(getPattern("private-key").test(rsaKey)).toBe(true);
|
|
242
266
|
});
|
|
243
267
|
|
|
244
268
|
it("should match entire generic private key block", () => {
|
|
245
|
-
expect(
|
|
269
|
+
expect(getPattern("private-key").test(genericKey)).toBe(true);
|
|
246
270
|
});
|
|
247
271
|
|
|
248
272
|
it("should not match header only", () => {
|
|
249
273
|
expect(
|
|
250
|
-
|
|
274
|
+
getPattern("private-key").test("-----BEGIN RSA PRIVATE KEY-----"),
|
|
251
275
|
).toBe(false);
|
|
252
276
|
});
|
|
253
277
|
});
|
|
@@ -255,39 +279,89 @@ MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC
|
|
|
255
279
|
describe("API Key Field (contextual)", () => {
|
|
256
280
|
it("should match api_key field", () => {
|
|
257
281
|
expect(
|
|
258
|
-
|
|
282
|
+
getPattern("api-key").test('"api_key": "sk-1234567890abcdef"'),
|
|
259
283
|
).toBe(true);
|
|
260
284
|
});
|
|
261
285
|
|
|
262
286
|
it("should match password field", () => {
|
|
263
|
-
expect(
|
|
264
|
-
|
|
265
|
-
)
|
|
287
|
+
expect(getPattern("api-key").test('"password": "supersecret123"')).toBe(
|
|
288
|
+
true,
|
|
289
|
+
);
|
|
266
290
|
});
|
|
267
291
|
|
|
268
292
|
it("should match token field", () => {
|
|
269
|
-
expect(
|
|
270
|
-
|
|
271
|
-
)
|
|
293
|
+
expect(getPattern("api-key").test('"token": "ghp_xxxxxxxxxxxx"')).toBe(
|
|
294
|
+
true,
|
|
295
|
+
);
|
|
272
296
|
});
|
|
273
297
|
});
|
|
274
298
|
});
|
|
275
299
|
|
|
276
300
|
describe("ReDoS safety", () => {
|
|
301
|
+
beforeEach(() => {
|
|
302
|
+
resetPatternCache();
|
|
303
|
+
});
|
|
304
|
+
|
|
277
305
|
it("should handle pathological input quickly", () => {
|
|
278
306
|
const pathological = "a".repeat(1000) + "b";
|
|
279
307
|
const start = performance.now();
|
|
280
308
|
|
|
281
|
-
const allPatterns =
|
|
282
|
-
|
|
283
|
-
...Object.values(K8S_PATTERNS),
|
|
284
|
-
...Object.values(COMMON_PATTERNS),
|
|
285
|
-
];
|
|
286
|
-
|
|
287
|
-
for (const pattern of allPatterns) {
|
|
309
|
+
const allPatterns = loadPatterns();
|
|
310
|
+
for (const { pattern } of allPatterns) {
|
|
288
311
|
pattern.test(pathological);
|
|
289
312
|
}
|
|
290
313
|
|
|
291
314
|
expect(performance.now() - start).toBeLessThan(100);
|
|
292
315
|
});
|
|
293
316
|
});
|
|
317
|
+
|
|
318
|
+
describe("loadPatterns", () => {
|
|
319
|
+
beforeEach(() => {
|
|
320
|
+
resetPatternCache();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("should load patterns from JSON files", () => {
|
|
324
|
+
const patterns = loadPatterns();
|
|
325
|
+
expect(patterns.length).toBeGreaterThan(0);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("should load AWS patterns", () => {
|
|
329
|
+
const patterns = loadPatterns();
|
|
330
|
+
const vpcPattern = patterns.find((p) => p.name === "vpc");
|
|
331
|
+
expect(vpcPattern).toBeDefined();
|
|
332
|
+
expect(vpcPattern!.pattern.test("vpc-1234567890abcdef0")).toBe(true);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("should load Kubernetes patterns", () => {
|
|
336
|
+
const patterns = loadPatterns();
|
|
337
|
+
const k8sTokenPattern = patterns.find((p) => p.name === "k8s-token");
|
|
338
|
+
expect(k8sTokenPattern).toBeDefined();
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("should load common patterns", () => {
|
|
342
|
+
const patterns = loadPatterns();
|
|
343
|
+
const ipv4Pattern = patterns.find((p) => p.name === "ipv4");
|
|
344
|
+
expect(ipv4Pattern).toBeDefined();
|
|
345
|
+
expect(ipv4Pattern!.pattern.test("192.168.1.1")).toBe(true);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it("should mark contextual patterns correctly", () => {
|
|
349
|
+
const patterns = loadPatterns();
|
|
350
|
+
const accountIdPattern = patterns.find((p) => p.name === "account-id");
|
|
351
|
+
expect(accountIdPattern).toBeDefined();
|
|
352
|
+
expect(accountIdPattern!.isContextual).toBe(true);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it("should cache patterns after first load", () => {
|
|
356
|
+
const patterns1 = loadPatterns();
|
|
357
|
+
const patterns2 = loadPatterns();
|
|
358
|
+
expect(patterns1).toBe(patterns2);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it("should reset cache on resetPatternCache()", () => {
|
|
362
|
+
const patterns1 = loadPatterns();
|
|
363
|
+
resetPatternCache();
|
|
364
|
+
const patterns2 = loadPatterns();
|
|
365
|
+
expect(patterns1).not.toBe(patterns2);
|
|
366
|
+
});
|
|
367
|
+
});
|
package/src/masker.ts
CHANGED
|
@@ -1,47 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadPatterns, type LoadedPattern } from "./patterns";
|
|
2
2
|
import { addEntry, getOriginal } from "./mapping";
|
|
3
3
|
import { getConfig, isPatternEnabled } from "./config";
|
|
4
4
|
|
|
5
|
-
interface PatternConfig {
|
|
6
|
-
pattern: RegExp;
|
|
7
|
-
type: string;
|
|
8
|
-
isContextual?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const PATTERN_ORDER: PatternConfig[] = [
|
|
12
|
-
{ pattern: AWS_PATTERNS.eksCluster, type: "eks-cluster" },
|
|
13
|
-
{ pattern: AWS_PATTERNS.arn, type: "arn" },
|
|
14
|
-
{ pattern: AWS_PATTERNS.accountId, type: "account-id", isContextual: true },
|
|
15
|
-
{ pattern: AWS_PATTERNS.accessKeyId, type: "access-key-id" },
|
|
16
|
-
{ pattern: AWS_PATTERNS.vpc, type: "vpc" },
|
|
17
|
-
{ pattern: AWS_PATTERNS.subnet, type: "subnet" },
|
|
18
|
-
{ pattern: AWS_PATTERNS.securityGroup, type: "security-group" },
|
|
19
|
-
{ pattern: AWS_PATTERNS.internetGateway, type: "internet-gateway" },
|
|
20
|
-
{ pattern: AWS_PATTERNS.routeTable, type: "route-table" },
|
|
21
|
-
{ pattern: AWS_PATTERNS.natGateway, type: "nat-gateway" },
|
|
22
|
-
{ pattern: AWS_PATTERNS.networkAcl, type: "network-acl" },
|
|
23
|
-
{ pattern: AWS_PATTERNS.eni, type: "eni" },
|
|
24
|
-
{ pattern: AWS_PATTERNS.vpcEndpoint, type: "vpc-endpoint" },
|
|
25
|
-
{ pattern: AWS_PATTERNS.transitGateway, type: "transit-gateway" },
|
|
26
|
-
{ pattern: AWS_PATTERNS.customerGateway, type: "customer-gateway" },
|
|
27
|
-
{ pattern: AWS_PATTERNS.vpnGateway, type: "vpn-gateway" },
|
|
28
|
-
{ pattern: AWS_PATTERNS.vpnConnection, type: "vpn-connection" },
|
|
29
|
-
{ pattern: AWS_PATTERNS.ecrRepoUri, type: "ecr-repo" },
|
|
30
|
-
{ pattern: AWS_PATTERNS.ami, type: "ami" },
|
|
31
|
-
{ pattern: AWS_PATTERNS.ec2Instance, type: "ec2-instance" },
|
|
32
|
-
{ pattern: AWS_PATTERNS.ebs, type: "ebs" },
|
|
33
|
-
{ pattern: AWS_PATTERNS.snapshot, type: "snapshot" },
|
|
34
|
-
|
|
35
|
-
{ pattern: K8S_PATTERNS.serviceAccountToken, type: "k8s-token" },
|
|
36
|
-
{ pattern: K8S_PATTERNS.clusterEndpoint, type: "k8s-endpoint" },
|
|
37
|
-
{ pattern: K8S_PATTERNS.kubeconfigServer, type: "k8s-endpoint" },
|
|
38
|
-
{ pattern: K8S_PATTERNS.nodeNameAws, type: "k8s-node" },
|
|
39
|
-
|
|
40
|
-
{ pattern: COMMON_PATTERNS.privateKey, type: "private-key" },
|
|
41
|
-
{ pattern: COMMON_PATTERNS.apiKeyField, type: "api-key", isContextual: true },
|
|
42
|
-
{ pattern: COMMON_PATTERNS.ipv4, type: "ipv4" },
|
|
43
|
-
];
|
|
44
|
-
|
|
45
5
|
function removeAnchors(source: string): string {
|
|
46
6
|
let result = source.replace(/^\^/, "").replace(/\$$/, "");
|
|
47
7
|
if (!result.endsWith("\\b")) {
|
|
@@ -50,34 +10,58 @@ function removeAnchors(source: string): string {
|
|
|
50
10
|
return result;
|
|
51
11
|
}
|
|
52
12
|
|
|
53
|
-
|
|
54
|
-
if (!text || typeof text !== "string") {
|
|
55
|
-
return text;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const config = getConfig();
|
|
59
|
-
if (!config.enabled) {
|
|
60
|
-
return text;
|
|
61
|
-
}
|
|
13
|
+
const REGEX_PREFIX = "regex:";
|
|
62
14
|
|
|
15
|
+
function applyCustomPatterns(
|
|
16
|
+
sessionId: string,
|
|
17
|
+
text: string,
|
|
18
|
+
customPatterns: string[],
|
|
19
|
+
): string {
|
|
63
20
|
let result = text;
|
|
64
21
|
|
|
65
|
-
for (const customPattern of
|
|
66
|
-
if (
|
|
67
|
-
const
|
|
68
|
-
|
|
22
|
+
for (const customPattern of customPatterns) {
|
|
23
|
+
if (customPattern.startsWith(REGEX_PREFIX)) {
|
|
24
|
+
const regexStr = customPattern.slice(REGEX_PREFIX.length);
|
|
25
|
+
const regex = new RegExp(removeAnchors(regexStr), "g");
|
|
26
|
+
const matches = new Set<string>();
|
|
27
|
+
let match;
|
|
28
|
+
while ((match = regex.exec(result)) !== null) {
|
|
29
|
+
matches.add(match[0]);
|
|
30
|
+
}
|
|
31
|
+
for (const value of matches) {
|
|
32
|
+
const token = addEntry(sessionId, "custom", value);
|
|
33
|
+
result = result.split(value).join(token);
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
const escaped = customPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
37
|
+
const literalRegex = new RegExp(escaped + "(?![\\w])", "g");
|
|
38
|
+
if (literalRegex.test(result)) {
|
|
39
|
+
const token = addEntry(sessionId, "custom", customPattern);
|
|
40
|
+
result = result.replace(literalRegex, token);
|
|
41
|
+
}
|
|
69
42
|
}
|
|
70
43
|
}
|
|
71
44
|
|
|
72
|
-
|
|
73
|
-
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function applyLoadedPatterns(
|
|
49
|
+
sessionId: string,
|
|
50
|
+
text: string,
|
|
51
|
+
patterns: LoadedPattern[],
|
|
52
|
+
): string {
|
|
53
|
+
let result = text;
|
|
54
|
+
|
|
55
|
+
for (const { name, pattern, isContextual } of patterns) {
|
|
56
|
+
if (!isPatternEnabled(name)) {
|
|
74
57
|
continue;
|
|
75
58
|
}
|
|
59
|
+
|
|
76
60
|
if (isContextual) {
|
|
77
61
|
result = result.replace(
|
|
78
62
|
new RegExp(pattern.source, "g"),
|
|
79
63
|
(match, capturedValue) => {
|
|
80
|
-
const token = addEntry(sessionId,
|
|
64
|
+
const token = addEntry(sessionId, name, capturedValue);
|
|
81
65
|
return match.replace(capturedValue, token);
|
|
82
66
|
},
|
|
83
67
|
);
|
|
@@ -91,7 +75,7 @@ export function mask(sessionId: string, text: string): string {
|
|
|
91
75
|
}
|
|
92
76
|
|
|
93
77
|
for (const value of matches) {
|
|
94
|
-
const token = addEntry(sessionId,
|
|
78
|
+
const token = addEntry(sessionId, name, value);
|
|
95
79
|
result = result.split(value).join(token);
|
|
96
80
|
}
|
|
97
81
|
}
|
|
@@ -100,6 +84,26 @@ export function mask(sessionId: string, text: string): string {
|
|
|
100
84
|
return result;
|
|
101
85
|
}
|
|
102
86
|
|
|
87
|
+
export function mask(sessionId: string, text: string): string {
|
|
88
|
+
if (!text || typeof text !== "string") {
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const config = getConfig();
|
|
93
|
+
if (!config.enabled) {
|
|
94
|
+
return text;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let result = text;
|
|
98
|
+
|
|
99
|
+
result = applyCustomPatterns(sessionId, result, config.customPatterns);
|
|
100
|
+
|
|
101
|
+
const patterns = loadPatterns();
|
|
102
|
+
result = applyLoadedPatterns(sessionId, result, patterns);
|
|
103
|
+
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
103
107
|
export function unmask(sessionId: string, text: string): string {
|
|
104
108
|
if (!text || typeof text !== "string") {
|
|
105
109
|
return text;
|