github.com/mailgun/mailgun-go/v3@v3.6.4/webhooks_test.go (about) 1 package mailgun_test 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/hmac" 7 "crypto/sha256" 8 "encoding/hex" 9 "io" 10 "mime/multipart" 11 "net/http" 12 "net/url" 13 "strings" 14 "testing" 15 16 "github.com/facebookgo/ensure" 17 "github.com/mailgun/mailgun-go/v3" 18 ) 19 20 func TestGetWebhook(t *testing.T) { 21 mg := mailgun.NewMailgun(testDomain, testKey) 22 mg.SetAPIBase(server.URL()) 23 24 ctx := context.Background() 25 list, err := mg.ListWebhooks(ctx) 26 ensure.Nil(t, err) 27 ensure.DeepEqual(t, len(list), 2) 28 29 urls, err := mg.GetWebhook(ctx, "new-webhook") 30 ensure.Nil(t, err) 31 32 ensure.DeepEqual(t, urls, []string{"http://example.com/new"}) 33 } 34 35 func TestWebhookCRUD(t *testing.T) { 36 mg := mailgun.NewMailgun(testDomain, testKey) 37 mg.SetAPIBase(server.URL()) 38 39 ctx := context.Background() 40 list, err := mg.ListWebhooks(ctx) 41 ensure.Nil(t, err) 42 ensure.DeepEqual(t, len(list), 2) 43 44 var countHooks = func() int { 45 hooks, err := mg.ListWebhooks(ctx) 46 ensure.Nil(t, err) 47 return len(hooks) 48 } 49 hookCount := countHooks() 50 51 webHookURLs := []string{"http://api.mailgun.net/webhook"} 52 ensure.Nil(t, mg.CreateWebhook(ctx, "deliver", webHookURLs)) 53 54 defer func() { 55 ensure.Nil(t, mg.DeleteWebhook(ctx, "deliver")) 56 newCount := countHooks() 57 ensure.DeepEqual(t, newCount, hookCount) 58 }() 59 60 newCount := countHooks() 61 ensure.False(t, newCount <= hookCount) 62 63 urls, err := mg.GetWebhook(ctx, "deliver") 64 ensure.Nil(t, err) 65 ensure.DeepEqual(t, urls, webHookURLs) 66 67 updatedWebHookURL := []string{"http://api.mailgun.net/messages"} 68 ensure.Nil(t, mg.UpdateWebhook(ctx, "deliver", updatedWebHookURL)) 69 70 hooks, err := mg.ListWebhooks(ctx) 71 ensure.Nil(t, err) 72 ensure.DeepEqual(t, hooks["deliver"], updatedWebHookURL) 73 } 74 75 var signedTests = []bool{ 76 true, 77 false, 78 } 79 80 func TestVerifyWebhookSignature(t *testing.T) { 81 mg := mailgun.NewMailgun(testDomain, testKey) 82 83 for _, v := range signedTests { 84 fields := getSignatureFields(mg.APIKey(), v) 85 sig := mailgun.Signature{ 86 TimeStamp: fields["timestamp"], 87 Token: fields["token"], 88 Signature: fields["signature"], 89 } 90 91 verified, err := mg.VerifyWebhookSignature(sig) 92 ensure.Nil(t, err) 93 94 if v != verified { 95 t.Errorf("VerifyWebhookSignature should return '%v' but got '%v'", v, verified) 96 } 97 } 98 } 99 100 func TestVerifyWebhookRequest_Form(t *testing.T) { 101 mg := mailgun.NewMailgun(testDomain, testKey) 102 103 for _, v := range signedTests { 104 fields := getSignatureFields(mg.APIKey(), v) 105 req := buildFormRequest(fields) 106 107 verified, err := mg.VerifyWebhookRequest(req) 108 ensure.Nil(t, err) 109 110 if v != verified { 111 t.Errorf("VerifyWebhookRequest should return '%v' but got '%v'", v, verified) 112 } 113 } 114 } 115 116 func TestVerifyWebhookRequest_MultipartForm(t *testing.T) { 117 mg := mailgun.NewMailgun(testDomain, testKey) 118 119 for _, v := range signedTests { 120 fields := getSignatureFields(mg.APIKey(), v) 121 req := buildMultipartFormRequest(fields) 122 123 verified, err := mg.VerifyWebhookRequest(req) 124 ensure.Nil(t, err) 125 126 if v != verified { 127 t.Errorf("VerifyWebhookRequest should return '%v' but got '%v'", v, verified) 128 } 129 } 130 } 131 132 func buildFormRequest(fields map[string]string) *http.Request { 133 values := url.Values{} 134 135 for k, v := range fields { 136 values.Add(k, v) 137 } 138 139 r := strings.NewReader(values.Encode()) 140 req, _ := http.NewRequest("POST", "/", r) 141 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 142 143 return req 144 } 145 146 func buildMultipartFormRequest(fields map[string]string) *http.Request { 147 buf := &bytes.Buffer{} 148 writer := multipart.NewWriter(buf) 149 150 for k, v := range fields { 151 writer.WriteField(k, v) 152 } 153 154 writer.Close() 155 156 req, _ := http.NewRequest("POST", "/", buf) 157 req.Header.Set("Content-type", writer.FormDataContentType()) 158 159 return req 160 } 161 162 func getSignatureFields(key string, signed bool) map[string]string { 163 badSignature := hex.EncodeToString([]byte("badsignature")) 164 165 fields := map[string]string{ 166 "token": "token", 167 "timestamp": "123456789", 168 "signature": badSignature, 169 } 170 171 if signed { 172 h := hmac.New(sha256.New, []byte(key)) 173 io.WriteString(h, fields["timestamp"]) 174 io.WriteString(h, fields["token"]) 175 hash := h.Sum(nil) 176 177 fields["signature"] = hex.EncodeToString(hash) 178 } 179 180 return fields 181 }