@@ -4,68 +4,88 @@ import { verifyWebhookSignature } from './webhook-signature.utils';
44// ── Helpers ───────────────────────────────────────────────────────────────────
55
66const secret = 'test-webhook-signing-secret' ;
7- const payload = Buffer . from ( JSON . stringify ( { event_type : 'buy' , amount : '10' } ) ) ;
7+ const payload = Buffer . from (
8+ JSON . stringify ( { event_type : 'buy' , amount : '10' } )
9+ ) ;
810
911function computeValidHeader ( ) : string {
10- const hex = crypto . createHmac ( 'sha256' , secret ) . update ( payload ) . digest ( 'hex' ) ;
11- return `sha256=${ hex } ` ;
12+ const hex = crypto
13+ . createHmac ( 'sha256' , secret )
14+ . update ( payload )
15+ . digest ( 'hex' ) ;
16+ return `sha256=${ hex } ` ;
1217}
1318
1419function flipHexChar ( char : string ) : string {
15- return char === '0' ? '1' : '0' ;
20+ return char === '0' ? '1' : '0' ;
1621}
1722
1823// ── Tests ─────────────────────────────────────────────────────────────────────
1924
2025describe ( 'verifyWebhookSignature' , ( ) => {
21- it ( 'returns true for a valid signature' , ( ) => {
22- expect ( verifyWebhookSignature ( payload , computeValidHeader ( ) , secret ) ) . toBe ( true ) ;
23- } ) ;
24-
25- it ( 'returns false when the signature differs in the last character' , ( ) => {
26- const header = computeValidHeader ( ) ;
27- const tampered =
28- header . slice ( 0 , - 1 ) + flipHexChar ( header [ header . length - 1 ] ) ;
29-
30- expect ( verifyWebhookSignature ( payload , tampered , secret ) ) . toBe ( false ) ;
31- } ) ;
32-
33- it ( 'returns false when the signature differs in the first character' , ( ) => {
34- const header = computeValidHeader ( ) ;
35- const prefix = 'sha256=' ;
36- const firstHexChar = header [ prefix . length ] ;
37- const tampered =
38- prefix + flipHexChar ( firstHexChar ) + header . slice ( prefix . length + 1 ) ;
39-
40- expect ( verifyWebhookSignature ( payload , tampered , secret ) ) . toBe ( false ) ;
41- } ) ;
42-
43- it ( 'returns false without throwing when the signature is one character shorter than expected' , ( ) => {
44- const header = computeValidHeader ( ) ;
45- const shortened = header . slice ( 0 , - 1 ) ;
46-
47- expect ( ( ) => verifyWebhookSignature ( payload , shortened , secret ) ) . not . toThrow ( ) ;
48- expect ( verifyWebhookSignature ( payload , shortened , secret ) ) . toBe ( false ) ;
49- } ) ;
50-
51- it ( 'returns false without throwing when the signature is one character longer than expected' , ( ) => {
52- const header = computeValidHeader ( ) ;
53- const lengthened = `${ header } a` ;
54-
55- expect ( ( ) => verifyWebhookSignature ( payload , lengthened , secret ) ) . not . toThrow ( ) ;
56- expect ( verifyWebhookSignature ( payload , lengthened , secret ) ) . toBe ( false ) ;
57- } ) ;
58-
59- it ( 'returns false without throwing for a malformed header' , ( ) => {
60- expect ( ( ) =>
61- verifyWebhookSignature ( payload , 'not-a-valid-header' , secret )
62- ) . not . toThrow ( ) ;
63- expect ( verifyWebhookSignature ( payload , 'not-a-valid-header' , secret ) ) . toBe (
64- false
65- ) ;
66- } ) ;
67-
68- it ( 'returns false for an empty header' , ( ) => {
69- expect ( verifyWebhookSignature ( payload , '' , secret ) ) . toBe ( false ) ;
70- } ) ;
26+ it ( 'returns true for a valid signature' , ( ) => {
27+ expect (
28+ verifyWebhookSignature ( payload , computeValidHeader ( ) , secret )
29+ ) . toBe ( true ) ;
30+ } ) ;
31+
32+ it ( 'returns false for a tampered payload' , ( ) => {
33+ const tamperedPayload = Buffer . from (
34+ JSON . stringify ( { event_type : 'buy' , amount : '999' } )
35+ ) ;
36+ expect (
37+ verifyWebhookSignature ( tamperedPayload , computeValidHeader ( ) , secret )
38+ ) . toBe ( false ) ;
39+ } ) ;
40+
41+ it ( 'returns false when the signature differs in the last character' , ( ) => {
42+ const header = computeValidHeader ( ) ;
43+ const tampered =
44+ header . slice ( 0 , - 1 ) + flipHexChar ( header [ header . length - 1 ] ) ;
45+
46+ expect ( verifyWebhookSignature ( payload , tampered , secret ) ) . toBe ( false ) ;
47+ } ) ;
48+
49+ it ( 'returns false when the signature differs in the first character' , ( ) => {
50+ const header = computeValidHeader ( ) ;
51+ const prefix = 'sha256=' ;
52+ const firstHexChar = header [ prefix . length ] ;
53+ const tampered =
54+ prefix + flipHexChar ( firstHexChar ) + header . slice ( prefix . length + 1 ) ;
55+
56+ expect ( verifyWebhookSignature ( payload , tampered , secret ) ) . toBe ( false ) ;
57+ } ) ;
58+
59+ it ( 'returns false without throwing when the signature is one character shorter than expected' , ( ) => {
60+ const header = computeValidHeader ( ) ;
61+ const shortened = header . slice ( 0 , - 1 ) ;
62+
63+ expect ( ( ) =>
64+ verifyWebhookSignature ( payload , shortened , secret )
65+ ) . not . toThrow ( ) ;
66+ expect ( verifyWebhookSignature ( payload , shortened , secret ) ) . toBe ( false ) ;
67+ } ) ;
68+
69+ it ( 'returns false without throwing when the signature is one character longer than expected' , ( ) => {
70+ const header = computeValidHeader ( ) ;
71+ const lengthened = `${ header } a` ;
72+
73+ expect ( ( ) =>
74+ verifyWebhookSignature ( payload , lengthened , secret )
75+ ) . not . toThrow ( ) ;
76+ expect ( verifyWebhookSignature ( payload , lengthened , secret ) ) . toBe ( false ) ;
77+ } ) ;
78+
79+ it ( 'returns false without throwing for a malformed header' , ( ) => {
80+ expect ( ( ) =>
81+ verifyWebhookSignature ( payload , 'not-a-valid-header' , secret )
82+ ) . not . toThrow ( ) ;
83+ expect (
84+ verifyWebhookSignature ( payload , 'not-a-valid-header' , secret )
85+ ) . toBe ( false ) ;
86+ } ) ;
87+
88+ it ( 'returns false for an empty header' , ( ) => {
89+ expect ( verifyWebhookSignature ( payload , '' , secret ) ) . toBe ( false ) ;
90+ } ) ;
7191} ) ;
0 commit comments