Webhook-to-SSE gateway with hierarchical topic routing and signature verification
1package main
2
3import (
4 "crypto/hmac"
5 "crypto/sha1"
6 "crypto/sha256"
7 "encoding/hex"
8 "net/http"
9 "testing"
10)
11
12func computeHMACSHA256(secret, body string) string {
13 mac := hmac.New(sha256.New, []byte(secret))
14 mac.Write([]byte(body))
15 return "sha256=" + hex.EncodeToString(mac.Sum(nil))
16}
17
18func computeHMACSHA1(secret, body string) string {
19 mac := hmac.New(sha1.New, []byte(secret))
20 mac.Write([]byte(body))
21 return "sha1=" + hex.EncodeToString(mac.Sum(nil))
22}
23
24func TestNewVerifier_hmacSHA256(t *testing.T) {
25 v, err := NewVerifier("hmac-sha256")
26 if err != nil {
27 t.Fatalf("unexpected error: %v", err)
28 }
29 if v == nil {
30 t.Fatal("expected verifier, got nil")
31 }
32}
33
34func TestNewVerifier_hmacSHA1(t *testing.T) {
35 v, err := NewVerifier("hmac-sha1")
36 if err != nil {
37 t.Fatalf("unexpected error: %v", err)
38 }
39 if v == nil {
40 t.Fatal("expected verifier, got nil")
41 }
42}
43
44func TestNewVerifier_unknown(t *testing.T) {
45 _, err := NewVerifier("unknown-method")
46 if err == nil {
47 t.Fatal("expected error for unknown method")
48 }
49}
50
51func TestHMACSHA256_validSignature(t *testing.T) {
52 secret := "test-secret"
53 body := `{"action":"push"}`
54 sig := computeHMACSHA256(secret, body)
55
56 v, _ := NewVerifier("hmac-sha256")
57 headers := http.Header{"X-Hub-Signature-256": {sig}}
58 err := v.Verify([]byte(body), headers, secret, "X-Hub-Signature-256")
59 if err != nil {
60 t.Fatalf("expected valid signature, got error: %v", err)
61 }
62}
63
64func TestHMACSHA256_invalidSignature(t *testing.T) {
65 v, _ := NewVerifier("hmac-sha256")
66 headers := http.Header{"X-Hub-Signature-256": {"sha256=deadbeef"}}
67 err := v.Verify([]byte("body"), headers, "secret", "X-Hub-Signature-256")
68 if err == nil {
69 t.Fatal("expected error for invalid signature")
70 }
71}
72
73func TestHMACSHA256_missingHeader(t *testing.T) {
74 v, _ := NewVerifier("hmac-sha256")
75 headers := http.Header{}
76 err := v.Verify([]byte("body"), headers, "secret", "X-Hub-Signature-256")
77 if err == nil {
78 t.Fatal("expected error for missing signature header")
79 }
80}
81
82func TestHMACSHA1_validSignature(t *testing.T) {
83 secret := "test-secret"
84 body := `{"action":"push"}`
85 sig := computeHMACSHA1(secret, body)
86
87 v, _ := NewVerifier("hmac-sha1")
88 headers := http.Header{"X-Hub-Signature": {sig}}
89 err := v.Verify([]byte(body), headers, secret, "X-Hub-Signature")
90 if err != nil {
91 t.Fatalf("expected valid signature, got error: %v", err)
92 }
93}
94
95func TestHMACSHA256_wrongPrefix(t *testing.T) {
96 v, _ := NewVerifier("hmac-sha256")
97 headers := http.Header{"X-Hub-Signature-256": {"sha1=abc123"}}
98 err := v.Verify([]byte("body"), headers, "secret", "X-Hub-Signature-256")
99 if err == nil {
100 t.Fatal("expected error for wrong prefix")
101 }
102}
103
104func TestHMACSHA256_invalidHex(t *testing.T) {
105 v, _ := NewVerifier("hmac-sha256")
106 headers := http.Header{"X-Hub-Signature-256": {"sha256=not-hex!"}}
107 err := v.Verify([]byte("body"), headers, "secret", "X-Hub-Signature-256")
108 if err == nil {
109 t.Fatal("expected error for invalid hex")
110 }
111}
112
113func TestHMACSHA1_invalidSignature(t *testing.T) {
114 v, _ := NewVerifier("hmac-sha1")
115 headers := http.Header{"X-Hub-Signature": {"sha1=deadbeef"}}
116 err := v.Verify([]byte("body"), headers, "secret", "X-Hub-Signature")
117 if err == nil {
118 t.Fatal("expected error for invalid signature")
119 }
120}