158 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package mailgun
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"crypto/hmac"
 | |
| 	"crypto/sha256"
 | |
| 	"crypto/subtle"
 | |
| 	"encoding/hex"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 
 | |
| 	"github.com/mailgun/mailgun-go/v3/events"
 | |
| )
 | |
| 
 | |
| type UrlOrUrls struct {
 | |
| 	Urls []string `json:"urls"`
 | |
| 	Url  string   `json:"url"`
 | |
| }
 | |
| 
 | |
| type WebHooksListResponse struct {
 | |
| 	Webhooks map[string]UrlOrUrls `json:"webhooks"`
 | |
| }
 | |
| 
 | |
| type WebHookResponse struct {
 | |
| 	Webhook UrlOrUrls `json:"webhook"`
 | |
| }
 | |
| 
 | |
| // ListWebhooks returns the complete set of webhooks configured for your domain.
 | |
| // Note that a zero-length mapping is not an error.
 | |
| func (mg *MailgunImpl) ListWebhooks(ctx context.Context) (map[string][]string, error) {
 | |
| 	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint))
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 
 | |
| 	var body WebHooksListResponse
 | |
| 	err := getResponseFromJSON(ctx, r, &body)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	hooks := make(map[string][]string, 0)
 | |
| 	for k, v := range body.Webhooks {
 | |
| 		if v.Url != "" {
 | |
| 			hooks[k] = []string{v.Url}
 | |
| 		}
 | |
| 		if len(v.Urls) != 0 {
 | |
| 			hooks[k] = append(hooks[k], v.Urls...)
 | |
| 		}
 | |
| 	}
 | |
| 	return hooks, nil
 | |
| }
 | |
| 
 | |
| // CreateWebhook installs a new webhook for your domain.
 | |
| func (mg *MailgunImpl) CreateWebhook(ctx context.Context, kind string, urls []string) error {
 | |
| 	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint))
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	p := newUrlEncodedPayload()
 | |
| 	p.addValue("id", kind)
 | |
| 	for _, url := range urls {
 | |
| 		p.addValue("url", url)
 | |
| 	}
 | |
| 	_, err := makePostRequest(ctx, r, p)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // DeleteWebhook removes the specified webhook from your domain's configuration.
 | |
| func (mg *MailgunImpl) DeleteWebhook(ctx context.Context, kind string) error {
 | |
| 	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint) + "/" + kind)
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	_, err := makeDeleteRequest(ctx, r)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // GetWebhook retrieves the currently assigned webhook URL associated with the provided type of webhook.
 | |
| func (mg *MailgunImpl) GetWebhook(ctx context.Context, kind string) ([]string, error) {
 | |
| 	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint) + "/" + kind)
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	var body WebHookResponse
 | |
| 	if err := getResponseFromJSON(ctx, r, &body); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if body.Webhook.Url != "" {
 | |
| 		return []string{body.Webhook.Url}, nil
 | |
| 	}
 | |
| 	if len(body.Webhook.Urls) != 0 {
 | |
| 		return body.Webhook.Urls, nil
 | |
| 	}
 | |
| 	return nil, fmt.Errorf("webhook '%s' returned no urls", kind)
 | |
| }
 | |
| 
 | |
| // UpdateWebhook replaces one webhook setting for another.
 | |
| func (mg *MailgunImpl) UpdateWebhook(ctx context.Context, kind string, urls []string) error {
 | |
| 	r := newHTTPRequest(generateDomainApiUrl(mg, webhooksEndpoint) + "/" + kind)
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	p := newUrlEncodedPayload()
 | |
| 	for _, url := range urls {
 | |
| 		p.addValue("url", url)
 | |
| 	}
 | |
| 	_, err := makePutRequest(ctx, r, p)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // Represents the signature portion of the webhook POST body
 | |
| type Signature struct {
 | |
| 	TimeStamp string `json:"timestamp"`
 | |
| 	Token     string `json:"token"`
 | |
| 	Signature string `json:"signature"`
 | |
| }
 | |
| 
 | |
| // Represents the JSON payload provided when a Webhook is called by mailgun
 | |
| type WebhookPayload struct {
 | |
| 	Signature Signature      `json:"signature"`
 | |
| 	EventData events.RawJSON `json:"event-data"`
 | |
| }
 | |
| 
 | |
| // Use this method to parse the webhook signature given as JSON in the webhook response
 | |
| func (mg *MailgunImpl) VerifyWebhookSignature(sig Signature) (verified bool, err error) {
 | |
| 	h := hmac.New(sha256.New, []byte(mg.APIKey()))
 | |
| 	io.WriteString(h, sig.TimeStamp)
 | |
| 	io.WriteString(h, sig.Token)
 | |
| 
 | |
| 	calculatedSignature := h.Sum(nil)
 | |
| 	signature, err := hex.DecodeString(sig.Signature)
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	if len(calculatedSignature) != len(signature) {
 | |
| 		return false, nil
 | |
| 	}
 | |
| 
 | |
| 	return subtle.ConstantTimeCompare(signature, calculatedSignature) == 1, nil
 | |
| }
 | |
| 
 | |
| // Deprecated: Please use the VerifyWebhookSignature() to parse the latest
 | |
| // version of WebHooks from mailgun
 | |
| func (mg *MailgunImpl) VerifyWebhookRequest(req *http.Request) (verified bool, err error) {
 | |
| 	h := hmac.New(sha256.New, []byte(mg.APIKey()))
 | |
| 	io.WriteString(h, req.FormValue("timestamp"))
 | |
| 	io.WriteString(h, req.FormValue("token"))
 | |
| 
 | |
| 	calculatedSignature := h.Sum(nil)
 | |
| 	signature, err := hex.DecodeString(req.FormValue("signature"))
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	if len(calculatedSignature) != len(signature) {
 | |
| 		return false, nil
 | |
| 	}
 | |
| 
 | |
| 	return subtle.ConstantTimeCompare(signature, calculatedSignature) == 1, nil
 | |
| }
 |