newsbox/actions/mailgun.go
Adriano Caloiaro 8ae801ae5f
Initial commit
2023-02-15 08:57:48 -08:00

107 lines
2.4 KiB
Go

package actions
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"newsbox/internal"
"newsbox/models"
"newsbox/workers"
"strings"
"github.com/gobuffalo/buffalo"
"github.com/gobuffalo/envy"
"github.com/gobuffalo/pop/v6"
"github.com/gofrs/uuid"
"github.com/mailgun/mailgun-go/v4"
)
// MailgunWebhook handles new message webhooks from Mailgun
func MailgunWebhook(c buffalo.Context) (err error) {
mgApiKey, err := envy.MustGet("MAILGUN_API_KEY")
if err != nil {
log.Println("MAILGUN_API_KEY not set")
return errors.New("mailgun api key not set")
}
mg := mailgun.NewMailgun(internal.SiteDomain(), mgApiKey)
m := &models.Message{}
if err = c.Bind(m); err != nil {
return
}
sig := mailgun.Signature{
TimeStamp: fmt.Sprintf("%d", m.Timestamp),
Token: m.Token,
Signature: m.Signature,
}
verified, err := mg.VerifyWebhookSignature(sig)
if err != nil {
log.Printf("mailgun signature verificaton failed: %s\n", err)
c.Response().WriteHeader(http.StatusNotAcceptable)
return
}
if !verified {
log.Printf("mailgun signature verificaton failed: %s\n", err)
c.Response().WriteHeader(http.StatusNotAcceptable)
return
}
// Naively extract the username from the recipient and check a user exists that corresponds with that user
username := usernameFromRecipient(m.To)
if username == "" {
err = fmt.Errorf("couldn't extract username from email address: %s", m.To)
log.Println(err)
return err
}
tx := c.Value("tx").(*pop.Connection)
u := &models.User{}
err = tx.EagerPreload().Where("username = ?", username).First(u)
if err != nil {
log.Println(err)
return err
}
if u.ID == uuid.Nil {
err = fmt.Errorf("no such user: %v", u)
return
}
m.OwnerID = u.ID
if err = tx.Save(m); err != nil {
return err
}
js, _ := json.MarshalIndent(&m, "", "\t")
_, err = workers.W.EnqueueJob("incoming_email", js)
if err != nil {
c.Response().Write([]byte("Unable to queue message"))
c.Response().WriteHeader(400)
return
}
c.Response().Write(js)
c.Response().WriteHeader(200)
return nil
}
// usernameFromRecipient extracts the Newsbox username from the recipient's email address
// recipients may be of the following forms:
// <username>@<site domain>
// <username>+<anything>@<site domain>
func usernameFromRecipient(recipient string) (username string) {
if strings.Contains(recipient, "+") {
username = strings.Split(recipient, "+")[0]
} else {
username = strings.Split(recipient, "@")[0]
}
return
}