n8n/packages/nodes-base/nodes/Formstack/test/FormstackTriggerHelpers.test.ts
Dawid Myslak 4e2865206c
feat(Formstack Trigger Node): Add webhook request verification (#29495)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 08:07:07 +00:00

101 lines
2.8 KiB
TypeScript

import { createHmac } from 'crypto';
import { verifySignature } from '../FormstackTriggerHelpers';
describe('FormstackTriggerHelpers', () => {
let mockWebhookFunctions: any;
const testSecret = 'test-secret-key-12345';
const testPayload = Buffer.from('{"FormID":"123","UniqueID":"abc"}');
beforeEach(() => {
jest.clearAllMocks();
mockWebhookFunctions = {
getRequestObject: jest.fn(),
getWorkflowStaticData: jest.fn(),
};
});
describe('verifySignature', () => {
it('should return true when no secret is configured', () => {
mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({});
mockWebhookFunctions.getRequestObject.mockReturnValue({
header: jest.fn().mockReturnValue(null),
rawBody: testPayload,
});
const result = verifySignature.call(mockWebhookFunctions);
expect(result).toBe(true);
});
it('should return true when signatures match', () => {
const hmac = createHmac('sha256', testSecret);
hmac.update(testPayload);
const expectedSignature = `sha256=${hmac.digest('hex')}`;
mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({
webhookSecret: testSecret,
});
mockWebhookFunctions.getRequestObject.mockReturnValue({
header: jest.fn().mockImplementation((header) => {
if (header === 'x-fs-signature') return expectedSignature;
return null;
}),
rawBody: testPayload,
});
const result = verifySignature.call(mockWebhookFunctions);
expect(result).toBe(true);
});
it('should return false when signatures do not match', () => {
const wrongSignature = `sha256=${'0'.repeat(64)}`;
mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({
webhookSecret: testSecret,
});
mockWebhookFunctions.getRequestObject.mockReturnValue({
header: jest.fn().mockImplementation((header) => {
if (header === 'x-fs-signature') return wrongSignature;
return null;
}),
rawBody: testPayload,
});
const result = verifySignature.call(mockWebhookFunctions);
expect(result).toBe(false);
});
it('should return false when signature header is missing', () => {
mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({
webhookSecret: testSecret,
});
mockWebhookFunctions.getRequestObject.mockReturnValue({
header: jest.fn().mockReturnValue(null),
rawBody: testPayload,
});
const result = verifySignature.call(mockWebhookFunctions);
expect(result).toBe(false);
});
it('should return false when raw body is missing', () => {
mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({
webhookSecret: testSecret,
});
mockWebhookFunctions.getRequestObject.mockReturnValue({
header: jest.fn().mockReturnValue('sha256=anything'),
rawBody: undefined,
});
const result = verifySignature.call(mockWebhookFunctions);
expect(result).toBe(false);
});
});
});