Skip to content

Commit

Permalink
feat: make webhook headers case insensitive (#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-bot committed Oct 12, 2023
1 parent a8599cd commit c838d5c
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 13 deletions.
35 changes: 26 additions & 9 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1053,16 +1053,33 @@ export const isHeadersProtocol = (headers: any): headers is HeadersProtocol => {
return typeof headers?.get === 'function';
};

export const getHeader = (headers: HeadersLike, key: string): string | null | undefined => {
const lowerKey = key.toLowerCase();
if (isHeadersProtocol(headers)) return headers.get(key) || headers.get(lowerKey);
const value = headers[key] || headers[lowerKey];
if (Array.isArray(value)) {
if (value.length <= 1) return value[0];
console.warn(`Received ${value.length} entries for the ${key} header, using the first entry.`);
return value[0];
export const getRequiredHeader = (headers: HeadersLike, header: string): string => {
const lowerCasedHeader = header.toLowerCase();
if (isHeadersProtocol(headers)) {
// to deal with the case where the header looks like Finch-Event-Id
const intercapsHeader =
header[0]?.toUpperCase() +
header.substring(1).replace(/([^\w])(\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());
for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {
const value = headers.get(key);
if (value) {
return value;
}
}
}
return value;

for (const [key, value] of Object.entries(headers)) {
if (key.toLowerCase() === lowerCasedHeader) {
if (Array.isArray(value)) {
if (value.length <= 1) return value[0];
console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);
return value[0];
}
return value;
}
}

throw new Error(`Could not find ${header} header`);
};

/**
Expand Down
7 changes: 4 additions & 3 deletions src/resources/webhooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { APIResource } from 'modern-treasury/resource';
import { createHmac } from 'crypto';
import type { HeadersLike } from 'modern-treasury/core';
import { getHeader } from 'modern-treasury/core';
import { getRequiredHeader } from 'modern-treasury/core';

export class Webhooks extends APIResource {
/**
Expand Down Expand Up @@ -40,8 +40,9 @@ export class Webhooks extends APIResource {
opts?: { key?: string | null | undefined },
): boolean {
const signature = this.getSignature(payload, opts);
const expectedSignature = typeof headers === 'string' ? headers : getHeader(headers, 'X-Signature');
if (!expectedSignature) throw new Error('Could not find an X-Signature header');
const expectedSignature =
typeof headers === 'string' ? headers : getRequiredHeader(headers, 'X-Signature');
if (!expectedSignature) throw new Error('Could not find X-Signature header');
return signature === expectedSignature;
}
}
2 changes: 1 addition & 1 deletion tests/api-resources/webhooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('resource webhooks', () => {
it('validateSignature: Throws an error when the X-Signature header is not present', () => {
expect(() =>
modernTreasury.webhooks.validateSignature('bar', /* headers */ {}, { key: 'foo' }),
).toThrowError('Could not find an X-Signature header');
).toThrowError('Could not find X-Signature header');
});

it('validateSignature: Correctly verifies against the expected signature', () => {
Expand Down

0 comments on commit c838d5c

Please sign in to comment.