Skip to content

Commit 1702d6c

Browse files
author
Ilias Tsangaris
authored
feat(node): send a redacted string rather than omitting values for deny/allowlist (#259)
1 parent 8c92c67 commit 1702d6c

File tree

3 files changed

+147
-160
lines changed

3 files changed

+147
-160
lines changed

packages/node/__tests__/lib/construct-payload.test.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ describe('constructPayload()', () => {
6464
expect(isValidUUIDV4(body._id)).toBe(true);
6565
expect(typeof body.request.log.entries[0].request).toBe('object');
6666
expect(typeof body.request.log.entries[0].response).toBe('object');
67-
expect(body.request.log.entries[0].request.postData).toStrictEqual({});
67+
expect(body.request.log.entries[0].request.postData).toStrictEqual({
68+
mimeType: 'application/json',
69+
text: '{"password":"[REDACTED 6]"}',
70+
});
6871
});
6972
});
7073

packages/node/__tests__/lib/process-request.test.js

+84-153
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ describe('processRequest()', () => {
3232

3333
return request(app)
3434
.post('/')
35-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
35+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
3636
.expect(({ body }) => {
37-
expect(body.postData.text).toBe('{"another":"Hello world"}');
37+
expect(body.postData.text).toBe(
38+
'{"password":"[REDACTED 6]","apiKey":"[REDACTED 3]","another":"Hello world"}'
39+
);
3840
});
3941
});
4042

@@ -43,9 +45,9 @@ describe('processRequest()', () => {
4345

4446
return request(app)
4547
.post('/')
46-
.send({ a: { b: { c: 1 } } })
48+
.send({ a: { b: { c: {} } } })
4749
.expect(({ body }) => {
48-
expect(body.postData.text).toBe('{"a":{"b":{}}}');
50+
expect(body.postData.text).toBe('{"a":{"b":{"c":"[REDACTED]"}}}');
4951
});
5052
});
5153

@@ -54,9 +56,9 @@ describe('processRequest()', () => {
5456

5557
return request(app)
5658
.post('/')
57-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
59+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
5860
.expect(({ body }) => {
59-
expect(body.postData.text).toBe('{"password":"123456","apiKey":"abcdef"}');
61+
expect(body.postData.text).toBe('{"password":"123456","apiKey":"abc","another":"[REDACTED 11]"}');
6062
});
6163
});
6264

@@ -67,7 +69,7 @@ describe('processRequest()', () => {
6769
.post('/')
6870
.send({ a: { b: { c: 1 } }, d: 2 })
6971
.expect(({ body }) => {
70-
expect(body.postData.text).toBe('{"a":{"b":{"c":1}}}');
72+
expect(body.postData.text).toBe('{"a":{"b":{"c":1}},"d":"[REDACTED]"}');
7173
});
7274
});
7375

@@ -76,9 +78,11 @@ describe('processRequest()', () => {
7678

7779
return request(app)
7880
.post('/')
79-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
81+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
8082
.expect(({ body }) => {
81-
expect(body.postData.text).toBe('{"another":"Hello world"}');
83+
expect(body.postData.text).toBe(
84+
'{"password":"[REDACTED 6]","apiKey":"[REDACTED 3]","another":"Hello world"}'
85+
);
8286
});
8387
});
8488
});
@@ -91,10 +95,15 @@ describe('processRequest()', () => {
9195
.post('/')
9296
.set('a', '1')
9397
.expect(({ body }) => {
94-
expect(body.headers).toStrictEqual([
95-
{ name: 'a', value: '1' },
96-
{ name: 'content-length', value: '0' },
97-
]);
98+
expect(body.headers).toStrictEqual(
99+
expect.arrayContaining([
100+
{ name: 'host', value: '[REDACTED 15]' },
101+
{ name: 'accept-encoding', value: '[REDACTED 13]' },
102+
{ name: 'a', value: '1' },
103+
{ name: 'connection', value: '[REDACTED 5]' },
104+
{ name: 'content-length', value: '0' },
105+
])
106+
);
98107
});
99108
});
100109

@@ -105,7 +114,15 @@ describe('processRequest()', () => {
105114
.post('/')
106115
.set('a', '1')
107116
.expect(({ body }) => {
108-
expect(body.headers).toStrictEqual([{ name: 'a', value: '1' }]);
117+
expect(body.headers).toStrictEqual(
118+
expect.arrayContaining([
119+
{ name: 'host', value: '[REDACTED 15]' },
120+
{ name: 'accept-encoding', value: '[REDACTED 13]' },
121+
{ name: 'a', value: '1' },
122+
{ name: 'connection', value: '[REDACTED 5]' },
123+
{ name: 'content-length', value: '[REDACTED 1]' },
124+
])
125+
);
109126
});
110127
});
111128
});
@@ -118,14 +135,22 @@ describe('processRequest()', () => {
118135

119136
return request(app)
120137
.post('/')
121-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
138+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
122139
.set('a', '1')
123140
.expect(({ body }) => {
124-
expect(body.headers).toStrictEqual([
125-
{ name: 'content-type', value: 'application/json' },
126-
{ name: 'a', value: '1' },
127-
]);
128-
expect(body.postData.text).toBe('{"another":"Hello world"}');
141+
expect(body.headers).toStrictEqual(
142+
expect.arrayContaining([
143+
{ name: 'host', value: '[REDACTED 15]' },
144+
{ name: 'accept-encoding', value: '[REDACTED 13]' },
145+
{ name: 'content-type', value: 'application/json' },
146+
{ name: 'a', value: '1' },
147+
{ name: 'content-length', value: '[REDACTED 2]' },
148+
{ name: 'connection', value: '[REDACTED 5]' },
149+
])
150+
);
151+
expect(body.postData.text).toBe(
152+
'{"password":"[REDACTED 6]","apiKey":"[REDACTED 3]","another":"Hello world"}'
153+
);
129154
});
130155
});
131156

@@ -136,14 +161,22 @@ describe('processRequest()', () => {
136161

137162
return request(app)
138163
.post('/')
139-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
164+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
140165
.set('a', '1')
141166
.expect(({ body }) => {
142-
expect(body.headers).toStrictEqual([
143-
{ name: 'a', value: '1' },
144-
{ name: 'content-type', value: 'application/json' },
145-
]);
146-
expect(body.postData.text).toBe('{"another":"Hello world"}');
167+
expect(body.headers).toStrictEqual(
168+
expect.arrayContaining([
169+
{ name: 'host', value: '[REDACTED 15]' },
170+
{ name: 'accept-encoding', value: '[REDACTED 13]' },
171+
{ name: 'content-type', value: 'application/json' },
172+
{ name: 'a', value: '1' },
173+
{ name: 'content-length', value: '[REDACTED 2]' },
174+
{ name: 'connection', value: '[REDACTED 5]' },
175+
])
176+
);
177+
expect(body.postData.text).toBe(
178+
'{"password":"[REDACTED 6]","apiKey":"[REDACTED 3]","another":"Hello world"}'
179+
);
147180
});
148181
});
149182

@@ -155,38 +188,42 @@ describe('processRequest()', () => {
155188

156189
return request(app)
157190
.post('/')
158-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
191+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
159192
.set('a', '1')
160193
.expect(({ body }) => {
161-
expect(body.headers).toStrictEqual([
162-
{ name: 'content-type', value: 'application/json' },
163-
{ name: 'a', value: '1' },
164-
]);
165-
expect(body.postData.text).toBe('{"another":"Hello world"}');
194+
expect(body.headers).toStrictEqual(
195+
expect.arrayContaining([
196+
{ name: 'host', value: '[REDACTED 15]' },
197+
{ name: 'accept-encoding', value: '[REDACTED 13]' },
198+
{ name: 'content-type', value: 'application/json' },
199+
{ name: 'a', value: '1' },
200+
{ name: 'content-length', value: '[REDACTED 2]' },
201+
{ name: 'connection', value: '[REDACTED 5]' },
202+
])
203+
);
204+
expect(body.postData.text).toBe(
205+
'{"password":"[REDACTED 6]","apiKey":"[REDACTED 3]","another":"Hello world"}'
206+
);
166207
});
167208
});
168209
});
169210

211+
/*
212+
* These tests are for the legacy blacklist/whitelist properties that mirrors allowlist/denylist behavior.
213+
* Rather than reimplementing each test again here, it should be appropriate to just test the base case as
214+
* The behavior here is assumed to use the same code paths as those used by the new properties.
215+
*/
170216
describe('deprecated blacklist/whitelist', () => {
171217
it('should strip blacklisted properties', () => {
172218
const app = createApp({ blacklist: ['password', 'apiKey'] });
173219

174220
return request(app)
175221
.post('/')
176-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
177-
.expect(({ body }) => {
178-
expect(body.postData.text).toBe('{"another":"Hello world"}');
179-
});
180-
});
181-
182-
it('should strip blacklisted nested properties', () => {
183-
const app = createApp({ blacklist: ['a.b.c'] });
184-
185-
return request(app)
186-
.post('/')
187-
.send({ a: { b: { c: 1 } } })
222+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
188223
.expect(({ body }) => {
189-
expect(body.postData.text).toBe('{"a":{"b":{}}}');
224+
expect(body.postData.text).toBe(
225+
'{"password":"[REDACTED 6]","apiKey":"[REDACTED 3]","another":"Hello world"}'
226+
);
190227
});
191228
});
192229

@@ -195,115 +232,9 @@ describe('processRequest()', () => {
195232

196233
return request(app)
197234
.post('/')
198-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
199-
.expect(({ body }) => {
200-
expect(body.postData.text).toBe('{"password":"123456","apiKey":"abcdef"}');
201-
});
202-
});
203-
204-
it('should only send whitelisted nested properties', () => {
205-
const app = createApp({ whitelist: ['a.b.c'] });
206-
207-
return request(app)
208-
.post('/')
209-
.send({ a: { b: { c: 1 } }, d: 2 })
210-
.expect(({ body }) => {
211-
expect(body.postData.text).toBe('{"a":{"b":{"c":1}}}');
212-
});
213-
});
214-
215-
it('should ignore whitelist if blacklist is present', () => {
216-
const app = createApp({ blacklist: ['password', 'apiKey'], whitelist: ['password', 'apiKey'] });
217-
218-
return request(app)
219-
.post('/')
220-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
221-
.expect(({ body }) => {
222-
expect(body.postData.text).toBe('{"another":"Hello world"}');
223-
});
224-
});
225-
});
226-
227-
describe('blacklist/whitelist in headers', () => {
228-
it('should strip blacklisted properties', () => {
229-
const app = createApp({ blacklist: ['host', 'accept-encoding', 'user-agent', 'connection'] });
230-
231-
return request(app)
232-
.post('/')
233-
.set('a', '1')
234-
.expect(({ body }) => {
235-
expect(body.headers).toStrictEqual([
236-
{ name: 'a', value: '1' },
237-
{ name: 'content-length', value: '0' },
238-
]);
239-
});
240-
});
241-
242-
it('should only send whitelisted properties', () => {
243-
const app = createApp({ whitelist: ['a'] });
244-
245-
return request(app)
246-
.post('/')
247-
.set('a', '1')
248-
.expect(({ body }) => {
249-
expect(body.headers).toStrictEqual([{ name: 'a', value: '1' }]);
250-
});
251-
});
252-
});
253-
254-
describe('blacklist/whitelist in body and headers', () => {
255-
it('should strip blacklisted properties in body and headers', () => {
256-
const app = createApp({
257-
blacklist: ['host', 'accept-encoding', 'user-agent', 'connection', 'content-length', 'password', 'apiKey'],
258-
});
259-
260-
return request(app)
261-
.post('/')
262-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
263-
.set('a', '1')
264-
.expect(({ body }) => {
265-
expect(body.headers).toStrictEqual([
266-
{ name: 'content-type', value: 'application/json' },
267-
{ name: 'a', value: '1' },
268-
]);
269-
expect(body.postData.text).toBe('{"another":"Hello world"}');
270-
});
271-
});
272-
273-
it('should only send whitelisted nested properties in body and headers', () => {
274-
const app = createApp({
275-
whitelist: ['a', 'another', 'content-type'],
276-
});
277-
278-
return request(app)
279-
.post('/')
280-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
281-
.set('a', '1')
282-
.expect(({ body }) => {
283-
expect(body.headers).toStrictEqual([
284-
{ name: 'a', value: '1' },
285-
{ name: 'content-type', value: 'application/json' },
286-
]);
287-
expect(body.postData.text).toBe('{"another":"Hello world"}');
288-
});
289-
});
290-
291-
it('should ignore whitelist if there are blacklisted properties in headers and body', () => {
292-
const app = createApp({
293-
blacklist: ['host', 'accept-encoding', 'user-agent', 'connection', 'content-length', 'password', 'apiKey'],
294-
whitelist: ['host', 'accept-encoding', 'user-agent', 'connection', 'content-length', 'password', 'apiKey'],
295-
});
296-
297-
return request(app)
298-
.post('/')
299-
.send({ password: '123456', apiKey: 'abcdef', another: 'Hello world' })
300-
.set('a', '1')
235+
.send({ password: '123456', apiKey: 'abc', another: 'Hello world' })
301236
.expect(({ body }) => {
302-
expect(body.headers).toStrictEqual([
303-
{ name: 'content-type', value: 'application/json' },
304-
{ name: 'a', value: '1' },
305-
]);
306-
expect(body.postData.text).toBe('{"another":"Hello world"}');
237+
expect(body.postData.text).toBe('{"password":"123456","apiKey":"abc","another":"[REDACTED 11]"}');
307238
});
308239
});
309240
});

0 commit comments

Comments
 (0)