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  }