/opt/mawid/apps/api/src/whatsapp
NameSizeModeActions
owner-notifier.service.ts17450644editdlrm
wa-core.module.ts13520644editdlrm
wa-http.client.ts17360644editdlrm
wa-inbound.service.spec.ts50660644editdlrm
wa-inbound.service.ts54310644editdlrm
wa-outbound.worker.ts27230644editdlrm
wa-queue.ts4470644editdlrm
wa-sender.service.ts49590644editdlrm
wa-signature.spec.ts12640644editdlrm
wa-signature.ts6620644editdlrm
wa-types.ts16830644editdlrm
wa-webhook.controller.spec.ts26840644editdlrm
wa-webhook.controller.ts23080644editdlrm
wa-window.spec.ts8600644editdlrm
wa-window.ts5090644editdlrm
whatsapp.module.ts5790644editdlrm
Edit: /opt/mawid/apps/api/src/whatsapp/wa-webhook.controller.spec.ts (2684B)
import { BadRequestException, ForbiddenException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { createHmac } from 'node:crypto'; import { WaWebhookController } from './wa-webhook.controller'; import type { WaInboundService } from './wa-inbound.service'; const APP_SECRET = 'test-app-secret'; const VERIFY_TOKEN = 'test-verify-token'; function makeController(process = jest.fn()) { const config = { get: (key: string) => ({ WA_APP_SECRET: APP_SECRET, WA_WEBHOOK_VERIFY_TOKEN: VERIFY_TOKEN })[key], } as unknown as ConfigService; const inbound = { process } as unknown as WaInboundService; return { controller: new WaWebhookController(config, inbound), process }; } function makeRequest(payload: object, rawBodyOverride?: Buffer) { const rawBody = Buffer.from(JSON.stringify(payload)); return { rawBody: rawBodyOverride ?? rawBody, body: payload, headers: { 'x-hub-signature-256': `sha256=${createHmac('sha256', APP_SECRET).update(rawBody).digest('hex')}`, }, } as never; } describe('WaWebhookController', () => { describe('GET verify handshake', () => { it('returns the challenge for the correct token', () => { const { controller } = makeController(); expect(controller.verify('subscribe', VERIFY_TOKEN, '12345')).toBe('12345'); }); it('rejects a wrong token', () => { const { controller } = makeController(); expect(() => controller.verify('subscribe', 'wrong', '12345')).toThrow(ForbiddenException); }); }); describe('POST receive', () => { const payload = { object: 'whatsapp_business_account', entry: [] }; it('accepts a correctly signed payload', async () => { const { controller, process } = makeController(); await expect(controller.receive(makeRequest(payload))).resolves.toEqual({ received: true }); expect(process).toHaveBeenCalledWith(payload); }); it('rejects a tampered payload', async () => { const { controller, process } = makeController(); // Signature is computed over the original payload, but the delivered raw // body was altered in transit. const tampered = makeRequest( payload, Buffer.from(JSON.stringify({ ...payload, entry: [{ id: 'evil' }] })), ); await expect(controller.receive(tampered)).rejects.toThrow(ForbiddenException); expect(process).not.toHaveBeenCalled(); }); it('rejects an unexpected webhook object', async () => { const { controller } = makeController(); await expect(controller.receive(makeRequest({ object: 'page' }))).rejects.toThrow( BadRequestException, ); }); }); });