Skip to content

Commit 6a21b8e

Browse files
box-sdk-buildbox-sdk-build
andauthored
fix: compute webhook signature with and without escaping the body (box/box-codegen#737) (#627)
Co-authored-by: box-sdk-build <[email protected]>
1 parent 72e5cd7 commit 6a21b8e

File tree

6 files changed

+61
-33
lines changed

6 files changed

+61
-33
lines changed

.codegen.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{ "engineHash": "c17f683", "specHash": "630fc85", "version": "1.15.1" }
1+
{ "engineHash": "3d59200", "specHash": "630fc85", "version": "1.15.1" }

package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/internal/utilsBrowser.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,12 @@ export function createAgent(options?: AgentOptions, proxyConfig?: any): Agent {
267267
* @private
268268
*/
269269
export function jsonStringifyWithEscapedUnicode(body: string) {
270-
return body.replace(
271-
/[\u007f-\uffff]/g,
272-
(char) => `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`,
273-
);
270+
return body
271+
.replace(
272+
/[\u007f-\uffff]/g,
273+
(char) => `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`,
274+
)
275+
.replace(/(?<!\\)\//g, '\\/');
274276
}
275277

276278
/**
@@ -289,11 +291,9 @@ export async function computeWebhookSignature(
289291
[key: string]: string;
290292
},
291293
signatureKey: string,
294+
escapeBody: boolean = false,
292295
): Promise<string | null> {
293-
const escapedBody = jsonStringifyWithEscapedUnicode(body).replace(
294-
/(?<!\\)\//g,
295-
'\\/',
296-
);
296+
const escapedBody = escapeBody ? jsonStringifyWithEscapedUnicode(body) : body;
297297
if (headers['box-signature-version'] !== '1') {
298298
return null;
299299
}

src/internal/utilsNode.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,19 @@ export function createAgent(options?: AgentOptions, proxyConfig?: any): Agent {
215215
}
216216

217217
/**
218-
* Stringify JSON with escaped multibyte Unicode characters to ensure computed signatures match PHP's default behavior
218+
* Stringify JSON with escaped multibyte Unicode characters and slashes to ensure computed signatures match PHP's default behavior
219219
*
220220
* @param {Object} body - The parsed JSON object
221221
* @returns {string} - Stringified JSON with escaped multibyte Unicode characters
222222
* @private
223223
*/
224224
export function jsonStringifyWithEscapedUnicode(body: string) {
225-
return body.replace(
226-
/[\u007f-\uffff]/g,
227-
(char) => `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`,
228-
);
225+
return body
226+
.replace(
227+
/[\u007f-\uffff]/g,
228+
(char) => `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`,
229+
)
230+
.replace(/(?<!\\)\//g, '\\/');
229231
}
230232

231233
/**
@@ -235,6 +237,7 @@ export function jsonStringifyWithEscapedUnicode(body: string) {
235237
* @param {string} body - The request body of the webhook message
236238
* @param {Object} headers - The request headers of the webhook message
237239
* @param {string} signatureKey - The signature to verify the message with
240+
* @param {string} escapeBody - Indicates if payload should be escaped or left as is
238241
* @returns {?string} - The message signature (or null, if it can't be computed)
239242
* @private
240243
*/
@@ -244,11 +247,9 @@ export async function computeWebhookSignature(
244247
[key: string]: string;
245248
},
246249
signatureKey: string,
250+
escapeBody: boolean = false,
247251
): Promise<string | null> {
248-
const escapedBody = jsonStringifyWithEscapedUnicode(body).replace(
249-
/(?<!\\)\//g,
250-
'\\/',
251-
);
252+
const escapedBody = escapeBody ? jsonStringifyWithEscapedUnicode(body) : body;
252253
if (headers['box-signature-version'] !== '1') {
253254
return null;
254255
}

src/managers/webhooks.generated.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -680,14 +680,28 @@ export class WebhooksManager {
680680
}
681681
if (
682682
primaryKey &&
683-
(await computeWebhookSignature(body, headers, primaryKey)) ==
683+
(await computeWebhookSignature(body, headers, primaryKey, false)) ==
684684
headers['box-signature-primary']
685685
) {
686686
return true;
687687
}
688+
if (
689+
primaryKey &&
690+
(await computeWebhookSignature(body, headers, primaryKey, true)) ==
691+
headers['box-signature-primary']
692+
) {
693+
return true;
694+
}
695+
if (
696+
secondaryKey &&
697+
(await computeWebhookSignature(body, headers, secondaryKey, false)) ==
698+
headers['box-signature-secondary']
699+
) {
700+
return true;
701+
}
688702
if (
689703
secondaryKey &&
690-
(await computeWebhookSignature(body, headers, secondaryKey)) ==
704+
(await computeWebhookSignature(body, headers, secondaryKey, true)) ==
691705
headers['box-signature-secondary']
692706
) {
693707
return true;

src/test/webhooks.generated.test.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,13 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
196196
body,
197197
{ ...headers, ...{ ['box-delivery-timestamp']: currentDatetime } },
198198
primaryKey,
199+
true,
199200
),
200201
['box-signature-secondary']: await computeWebhookSignature(
201202
body,
202203
{ ...headers, ...{ ['box-delivery-timestamp']: currentDatetime } },
203204
secondaryKey,
205+
true,
204206
),
205207
},
206208
};
@@ -217,6 +219,7 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
217219
...{ ['box-delivery-timestamp']: currentDatetime },
218220
},
219221
primaryKey,
222+
true,
220223
),
221224
['box-signature-secondary']: await computeWebhookSignature(
222225
bodyWithJapanese,
@@ -225,6 +228,7 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
225228
...{ ['box-delivery-timestamp']: currentDatetime },
226229
},
227230
secondaryKey,
231+
true,
228232
),
229233
},
230234
};
@@ -238,11 +242,13 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
238242
body,
239243
{ ...headers, ...{ ['box-delivery-timestamp']: futureDatetime } },
240244
primaryKey,
245+
true,
241246
),
242247
['box-signature-secondary']: await computeWebhookSignature(
243248
body,
244249
{ ...headers, ...{ ['box-delivery-timestamp']: futureDatetime } },
245250
secondaryKey,
251+
true,
246252
),
247253
},
248254
};
@@ -256,11 +262,13 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
256262
body,
257263
{ ...headers, ...{ ['box-delivery-timestamp']: pastDatetime } },
258264
primaryKey,
265+
true,
259266
),
260267
['box-signature-secondary']: await computeWebhookSignature(
261268
body,
262269
{ ...headers, ...{ ['box-delivery-timestamp']: pastDatetime } },
263270
secondaryKey,
271+
true,
264272
),
265273
},
266274
};
@@ -272,23 +280,23 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
272280
} = { ...headers, ...{ ['box-signature-algorithm']: 'HmacSHA1' } };
273281
if (
274282
!(
275-
(await computeWebhookSignature(body, headers, primaryKey)) ==
283+
(await computeWebhookSignature(body, headers, primaryKey, true)) ==
276284
headers['box-signature-primary']
277285
)
278286
) {
279287
throw new Error('Assertion failed');
280288
}
281289
if (
282290
!(
283-
(await computeWebhookSignature(body, headers, secondaryKey)) ==
291+
(await computeWebhookSignature(body, headers, secondaryKey, true)) ==
284292
headers['box-signature-secondary']
285293
)
286294
) {
287295
throw new Error('Assertion failed');
288296
}
289297
if (
290298
!!(
291-
(await computeWebhookSignature(body, headers, incorrectKey)) ==
299+
(await computeWebhookSignature(body, headers, incorrectKey, true)) ==
292300
headers['box-signature-primary']
293301
)
294302
) {
@@ -300,6 +308,7 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
300308
bodyWithJapanese,
301309
headersWithJapanese,
302310
primaryKey,
311+
true,
303312
)) == headersWithJapanese['box-signature-primary']
304313
)
305314
) {
@@ -311,6 +320,7 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
311320
bodyWithEmoji,
312321
headersWithEmoji,
313322
primaryKey,
323+
true,
314324
)) == headersWithEmoji['box-signature-primary']
315325
)
316326
) {
@@ -322,6 +332,7 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
322332
bodyWithCarriageReturn,
323333
headersWithCarriageReturn,
324334
primaryKey,
335+
true,
325336
)) == headersWithCarriageReturn['box-signature-primary']
326337
)
327338
) {
@@ -333,6 +344,7 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
333344
bodyWithForwardSlash,
334345
headersWithForwardSlash,
335346
primaryKey,
347+
true,
336348
)) == headersWithForwardSlash['box-signature-primary']
337349
)
338350
) {
@@ -344,6 +356,7 @@ test('testWebhookValidation', async function testWebhookValidation(): Promise<an
344356
bodyWithBackSlash,
345357
headersWithBackSlash,
346358
primaryKey,
359+
true,
347360
)) == headersWithBackSlash['box-signature-primary']
348361
)
349362
) {

0 commit comments

Comments
 (0)