diff --git a/api.md b/api.md index c414b19a..686daf7c 100644 --- a/api.md +++ b/api.md @@ -472,13 +472,6 @@ Methods: - client.paperItems.retrieve(id) -> PaperItem - client.paperItems.list({ ...params }) -> PaperItemsPage -# Webhooks - -Methods: - -- client.webhooks.getSignature(payload, opts?) -> string -- client.webhooks.validateSignature(payload, headers, opts?) -> boolean - # VirtualAccounts Types: diff --git a/src/index.ts b/src/index.ts index 6020bb73..7aefef34 100644 --- a/src/index.ts +++ b/src/index.ts @@ -175,7 +175,6 @@ export class ModernTreasury extends Core.APIClient { transactions: API.Transactions = new API.Transactions(this); validations: API.Validations = new API.Validations(this); paperItems: API.PaperItems = new API.PaperItems(this); - webhooks: API.Webhooks = new API.Webhooks(this); virtualAccounts: API.VirtualAccounts = new API.VirtualAccounts(this); bulkRequests: API.BulkRequests = new API.BulkRequests(this); bulkResults: API.BulkResults = new API.BulkResults(this); @@ -472,8 +471,6 @@ export namespace ModernTreasury { export import PaperItemsPage = API.PaperItemsPage; export import PaperItemListParams = API.PaperItemListParams; - export import Webhooks = API.Webhooks; - export import VirtualAccounts = API.VirtualAccounts; export import VirtualAccount = API.VirtualAccount; export import VirtualAccountsPage = API.VirtualAccountsPage; diff --git a/src/resources/index.ts b/src/resources/index.ts index a01d0003..bbfdec74 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -248,4 +248,3 @@ export { VirtualAccountsPage, VirtualAccounts, } from './virtual-accounts'; -export { Webhooks } from './webhooks'; diff --git a/src/resources/webhooks.ts b/src/resources/webhooks.ts deleted file mode 100644 index 42d4a3a8..00000000 --- a/src/resources/webhooks.ts +++ /dev/null @@ -1,48 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { APIResource } from 'modern-treasury/resource'; -import { createHmac } from 'crypto'; -import type { HeadersLike } from 'modern-treasury/core'; -import { getRequiredHeader } from 'modern-treasury/core'; - -export class Webhooks extends APIResource { - /** - * To verify that a webhook was actually sent by Modern Treasury, every payload is - * signed with a signature that is passed through the `X-Signature` HTTP header. - * - * This method will generate a signature based off of your webhook key which can be - * found in the Developer Settings, - * https://app.moderntreasury.com/developers/webhooks, and the webhook payload. - * - * You can then compare the generated signature with the signature sent with the - * request, if they match then the webhook was sent by Modern Treasury. - */ - getSignature(payload: string, opts?: { key?: string | null | undefined }): string { - const key = opts?.key || this._client.webhookKey; - if (key == null) { - throw new Error( - "The webhook key must either be set using the env var, MODERN_TREASURY_WEBHOOK_KEY, on the client class, new ModernTreasury({ webhookKey: '123' }) or passed to this function", - ); - } - if (!key) { - throw new Error('The webhook key is set but appears to be empty.'); - } - - return createHmac('sha256', key).update(payload, 'utf8').digest('hex'); - } - - /** - * Returns whether or not the webhook payload was sent by Modern Treasury. - */ - validateSignature( - payload: string, - headers: string | HeadersLike, - opts?: { key?: string | null | undefined }, - ): boolean { - const signature = this.getSignature(payload, opts); - const expectedSignature = - typeof headers === 'string' ? headers : getRequiredHeader(headers, 'X-Signature'); - if (!expectedSignature) throw new Error('Could not find X-Signature header'); - return signature === expectedSignature; - } -} diff --git a/tests/api-resources/webhooks.test.ts b/tests/api-resources/webhooks.test.ts deleted file mode 100644 index 816a364c..00000000 --- a/tests/api-resources/webhooks.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import ModernTreasury from 'modern-treasury'; - -const modernTreasury = new ModernTreasury({ - apiKey: 'My API Key', - organizationId: 'my-organization-ID', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); - -describe('resource webhooks', () => { - it.each([ - ['foo', '08ba357e274f528065766c770a639abf6809b39ccfd37c2a3157c7f51954da0a'], - ['{"foo":"bar"}', '57e14f6f354543f0101fb06ea24df7731d90087b76651e3497345e22a3622940'], - [ - '{"foo":"bar","bar":"baz","a": true}', - 'ec1c86d16075e6937fc26d55b7dc60bac9b1178a2f714312f7c5cb13a319b0ac', - ], - [ - '{"a":{"b":{"c":{"d":[null,1,true,false,["foo",{"bar":[true, false]}]]}}}}', - '39b6fc0f5b02a5aefbdd7fb337245b4209036334e837d8c5b6a4092965ebc0a5', - ], - ])('getSignature', (payload, expected) => { - const signature = modernTreasury.webhooks.getSignature(payload, { key: 'foo' }); - expect(signature).toEqual(expected); - }); - - it('getSignature: Throws an error when the key has not been set', () => { - const client = new ModernTreasury({ - apiKey: 'something1234', - baseURL: 'http://127.0.0.1:4010', - organizationId: 'c40c0b40-11d3-42ee-8f2e-18ee8b8239aa', - }); - expect(() => client.webhooks.getSignature('bar')).toThrowError(/webhook key/); - }); - - it('getSignature: Uses the webhook key set at the client level', () => { - const client = new ModernTreasury({ - apiKey: 'something1234', - baseURL: 'http://127.0.0.1:4010', - organizationId: 'c40c0b40-11d3-42ee-8f2e-18ee8b8239aa', - webhookKey: 'hello, world', - }); - const payload = '{"foo":"bar"}'; - const signature = client.webhooks.getSignature(payload); - expect(signature).toEqual('07e118b4a9818c9242baf9009e76a78c29aeb015da93f600d514b77185247069'); - - const otherSignature = modernTreasury.webhooks.getSignature(payload, { key: 'foo' }); - expect(otherSignature).not.toEqual(signature); - }); - - 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 X-Signature header'); - }); - - it('validateSignature: Correctly verifies against the expected signature', () => { - const payload = '{"foo":"bar"}'; - expect( - modernTreasury.webhooks.validateSignature( - payload, - /* headers */ { 'X-Signature': '57e14f6f354543f0101fb06ea24df7731d90087b76651e3497345e22a3622940' }, - { - key: 'foo', - }, - ), - ).toBe(true); - - // lowercased header - expect( - modernTreasury.webhooks.validateSignature( - payload, - /* headers */ { 'x-signature': '57e14f6f354543f0101fb06ea24df7731d90087b76651e3497345e22a3622940' }, - { - key: 'foo', - }, - ), - ).toBe(true); - - // modified payload - expect( - modernTreasury.webhooks.validateSignature( - payload + 'foo', - /* headers */ { 'X-Signature': '57e14f6f354543f0101fb06ea24df7731d90087b76651e3497345e22a3622940' }, - { - key: 'foo', - }, - ), - ).toBe(false); - - // modified signature - expect( - modernTreasury.webhooks.validateSignature( - payload, - /* headers */ { 'X-Signature': 'hello' }, - { - key: 'foo', - }, - ), - ).toBe(false); - }); -});