mirror of
https://github.com/acaloiaro/newsbox
synced 2026-07-21 10:12:26 +00:00
107 lines
2.4 KiB
Go
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
|
|
}
|