Skip to content

Commit 153c4e9

Browse files
committed
updated handler for mb
1 parent 652f428 commit 153c4e9

File tree

2 files changed

+73
-36
lines changed

2 files changed

+73
-36
lines changed

Diff for: handlers/messagebird/handler.go

+43-17
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"encoding/hex"
1212
"log/slog"
1313
"strconv"
14-
14+
"errors"
1515
"fmt"
1616

1717
"net/http"
@@ -62,14 +62,16 @@ var statusMapping = map[string]courier.MsgStatus{
6262
"expired": courier.MsgStatusFailed,
6363
}
6464

65-
type ReceivedMessage struct {
66-
ID string `json:"id"`
67-
Recipient string `json:"recipient"`
68-
Originator string `json:"originator"`
69-
Body string `json:"body"`
70-
CreatedDatetime string `json:"createdDatetime"`
71-
MediaURLs []string `json:"mediaUrls"`
72-
MMS bool `json:"mms"`
65+
type formMessage struct {
66+
ID string `name:"id"`
67+
MID string `name:"mid"` //shortcode only
68+
Shortcode string `name:"shortcode"` //shortcode only
69+
Recipient string `name:"recipient" validate:"required"`
70+
Originator string `name:"originator"`
71+
Body string `name:"body"`
72+
MediaURLs []string `name:"mediaUrls"`
73+
MessageBody string `name:"message"` //shortcode only
74+
CreatedDatetime string `name:"receive_datetime" validate:"required"`
7375
}
7476

7577
func init() {
@@ -88,7 +90,7 @@ func newHandler(channelType courier.ChannelType, name string, validateSignatures
8890
// Initialize is called by the engine once everything is loaded
8991
func (h *handler) Initialize(s courier.Server) error {
9092
h.SetServer(s)
91-
s.AddHandlerRoute(h, http.MethodPost, "receive", courier.ChannelLogTypeMsgReceive, handlers.JSONPayload(h, h.receiveMessage))
93+
s.AddHandlerRoute(h, http.MethodPost, "receive", courier.ChannelLogTypeMsgReceive, h.receiveMessage)
9294
s.AddHandlerRoute(h, http.MethodGet, "status", courier.ChannelLogTypeMsgStatus, h.receiveStatus)
9395

9496
return nil
@@ -141,15 +143,32 @@ func (h *handler) receiveStatus(ctx context.Context, channel courier.Channel, w
141143
return handlers.WriteMsgStatusAndResponse(ctx, h, channel, status, w, r)
142144
}
143145

144-
func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, payload *ReceivedMessage, clog *courier.ChannelLog) ([]courier.Event, error) {
146+
func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w http.ResponseWriter, r *http.Request, clog *courier.ChannelLog) ([]courier.Event, error) {
145147
err := h.validateSignature(channel, r)
146148
if err != nil {
147149
return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err)
148150
}
149151

152+
payload := &formMessage{}
153+
err = handlers.DecodeAndValidateForm(payload, r)
154+
if err != nil {
155+
return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err)
156+
}
157+
158+
text := ""
159+
messageID := ""
160+
//chechk if shortcode or regular
161+
if payload.Shortcode != "" {
162+
text = payload.MessageBody
163+
messageID = payload.MID
164+
} else {
165+
text = payload.Body
166+
messageID = payload.ID
167+
}
168+
150169
// no message? ignore this
151-
if payload.Body == "" && !payload.MMS {
152-
return nil, handlers.WriteAndLogRequestIgnored(ctx, h, channel, w, r, "Ignoring request, no message")
170+
if text == "" && len(payload.MediaURLs) == 0 {
171+
return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, errors.New("no text or media"))
153172
}
154173

155174
// create our date from the timestamp
@@ -160,7 +179,7 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w
160179
shortCodeDateLayout := "20060102150405"
161180
date, err = time.Parse(shortCodeDateLayout, payload.CreatedDatetime)
162181
if err != nil {
163-
return nil, fmt.Errorf("unable to parse date '%s': %v", payload.CreatedDatetime, err)
182+
return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, fmt.Errorf("unable to parse date '%s': %v", payload.CreatedDatetime, err))
164183
}
165184
}
166185

@@ -169,13 +188,12 @@ func (h *handler) receiveMessage(ctx context.Context, channel courier.Channel, w
169188
if err != nil {
170189
return nil, handlers.WriteAndLogRequestError(ctx, h, channel, w, r, err)
171190
}
172-
text := payload.Body
173191

174192
// build our msg
175-
msg := h.Backend().NewIncomingMsg(channel, urn, text, payload.ID, clog).WithReceivedOn(date.UTC())
193+
msg := h.Backend().NewIncomingMsg(channel, urn, text, messageID, clog).WithReceivedOn(date.UTC())
176194

177195
// process any attached media
178-
if payload.MMS {
196+
if len(payload.MediaURLs) > 0 {
179197
for _, mediaURL := range payload.MediaURLs {
180198
msg.WithAttachment(mediaURL)
181199
}
@@ -312,3 +330,11 @@ func (h *handler) validateSignature(c courier.Channel, r *http.Request) error {
312330

313331
return nil
314332
}
333+
334+
// WriteMsgSuccessResponse writes a success response for the messages, MB expects an 'OK' body in our response
335+
func (h *handler) WriteMsgSuccessResponse(ctx context.Context, w http.ResponseWriter, msgs []courier.MsgIn) error {
336+
w.Header().Add("Content-type", "text/plain")
337+
w.WriteHeader(http.StatusOK)
338+
_, err := w.Write([]byte("OK"))
339+
return err
340+
}

Diff for: handlers/messagebird/handler_test.go

+30-19
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,29 @@ var testChannels = []courier.Channel{
2323

2424
const (
2525
receiveURL = "/c/mbd/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/receive"
26-
validReceive = `{"receiver":"18005551515","sender":"18885551515","message":"Test again","date":1690386569,"date_utc":1690418969,"reference":"1","id":"b6aae1b5dfb2427a8f7ea6a717ba31a9","message_id":"3b53c137369242138120d6b0b2122607","recipient":"18005551515","originator":"18885551515","body":"Test 3","createdDatetime":"2023-07-27T00:49:29+00:00","mms":false}`
27-
validReceiveShortCode = `{"receiver":"18005551515","sender":"18885551515","message":"Test again","date":1690386569,"date_utc":1690418969,"reference":"1","id":"b6aae1b5dfb2427a8f7ea6a717ba31a9","message_id":"3b53c137369242138120d6b0b2122607","recipient":"18005551515","originator":"18885551515","body":"Test 3","createdDatetime":"20230727004929","mms":false}`
28-
validReceiveMMS = `{"receiver":"18005551515","sender":"18885551515","message":"Test again","date":1690386569,"date_utc":1690418969,"reference":"1","id":"b6aae1b5dfb2427a8f7ea6a717ba31a9","message_id":"3b53c137369242138120d6b0b2122607","recipient":"18005551515","originator":"18885551515","mediaURLs":["https://foo.bar/image.jpg"],"createdDatetime":"2023-07-27T00:49:29+00:00","mms":true}`
26+
validReceive = "receiver=18005551515&sender=18885551515&body=Test+again&date=1690386569&date_utc=1690418969&reference=1&id=b6aae1b5dfb2427a8f7ea6a717ba31a9&id=3b53c137369242138120d6b0b2122607&recipient=18005551515&originator=18885551515&body=Test+3&receive_datetime=2023-07-27T00%3A49%3A29%2B00%3A00&mms=false"
27+
invalidReceive = "recipient=18005551515&&receive_datetime=2023-07-27T00%3A49%3A29%2B00%3A00"
28+
validReceiveShortCode = "shortcode=51515&sender=18885551515&message=Test+again&date=1690386569&date_utc=1690418969&reference=1&id=b6aae1b5dfb2427a8f7ea6a717ba31a9&mid=3b53c137369242138120d6b0b2122607&recipient=18005551515&originator=18885551515&body=Test+3&receive_datetime=20230727004929&mms=false"
29+
validReceiveMMS = "receiver=18005551515&sender=18885551515&message=Test+again&date=1690386569&date_utc=1690418969&reference=1&id=b6aae1b5dfb2427a8f7ea6a717ba31a9&message_id=3b53c137369242138120d6b0b2122607&recipient=18005551515&originator=18885551515&mediaURLs=https%3A%2F%2Ffoo.bar%2Fimage.jpg&receive_datetime=2023-07-27T00%3A49%3A29%2B00%3A00&mms=true"
2930
statusBaseURL = "/c/mbd/8eb23e93-5ecb-45ba-b726-3b064e0c56ab/status?datacoding=plain&id=b6aae1b5dfb2427a8f7ea6a717ba31a9&mccmnc=310010&messageLength=4&messagePartCount=1&ported=0&price%5Bamount%5D=0.000&price%5Bcurrency%5D=USD&recipient=18885551515&reference=26&statusDatetime=2023-07-28T17%3A57%3A12%2B00%3A00"
3031
validSecret = "my_super_secret"
3132
validResponse = `{"id":"efa6405d518d4c0c88cce11f7db775fb","href":"https://rest.messagebird.com/mms/efa6405d518d4c0c88cce11f7db775fb","direction":"mt","originator":"+188885551515","subject":"Great logo","body":"Hi! Please have a look at this very nice logo of this cool company.","reference":"the-customers-reference","mediaUrls":["https://www.messagebird.com/assets/images/og/messagebird.gif"],"scheduledDatetime":null,"createdDatetime":"2017-09-01T10:00:00+00:00","recipients":{"totalCount":1,"totalSentCount":1,"totalDeliveredCount":0,"totalDeliveryFailedCount":0,"items":[{"recipient":18005551515,"status":"sent","statusDatetime":"2017-09-01T10:00:00+00:00"}]}}`
3233
invalidSecret = "bad_secret"
3334
)
3435

3536
func addValidSignature(r *http.Request) {
36-
body, _ := ReadBody(r, maxRequestBodyBytes)
37-
bodysig := calculateSignature(body)
37+
var bodysig string
38+
if r.Body == nil {
39+
bodysig = calculateSignature([]byte(""))
40+
} else {
41+
body, _ := ReadBody(r, maxRequestBodyBytes)
42+
if len(body) > 0 {
43+
bodysig = calculateSignature(body)
44+
} else {
45+
bodysig = calculateSignature([]byte(""))
46+
}
47+
}
48+
3849
urlsig := calculateSignature([]byte("https://localhost" + r.URL.Path))
3950
t := jwt.NewWithClaims(jwt.SigningMethodHS256,
4051
jwt.MapClaims{
@@ -88,43 +99,43 @@ func addInvalidBodyHash(r *http.Request) {
8899
var defaultReceiveTestCases = []IncomingTestCase{
89100
{
90101
Label: "Receive Valid text w Signature",
91-
Headers: map[string]string{"Content-Type": "application/json"},
102+
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
92103
URL: receiveURL,
93104
Data: validReceive,
94105
ExpectedRespStatus: 200,
95-
ExpectedBodyContains: "Message Accepted",
106+
ExpectedBodyContains: "OK",
96107
ExpectedMsgText: Sp("Test 3"),
97108
ExpectedURN: "tel:+18885551515",
98109
ExpectedDate: time.Date(2023, time.July, 27, 00, 49, 29, 0, time.UTC),
99110
PrepRequest: addValidSignature,
100111
},
101112
{
102113
Label: "Receive Valid text w shortcode date",
103-
Headers: map[string]string{"Content-Type": "application/json"},
114+
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
104115
URL: receiveURL,
105116
Data: validReceiveShortCode,
106117
ExpectedRespStatus: 200,
107-
ExpectedBodyContains: "Message Accepted",
108-
ExpectedMsgText: Sp("Test 3"),
118+
ExpectedBodyContains: "OK",
119+
ExpectedMsgText: Sp("Test again"),
109120
ExpectedURN: "tel:+18885551515",
110121
ExpectedDate: time.Date(2023, time.July, 27, 00, 49, 29, 0, time.UTC),
111122
PrepRequest: addValidSignature,
112123
},
113124
{
114125
Label: "Receive Valid w image w Signature",
115-
Headers: map[string]string{"Content-Type": "application/json"},
126+
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
116127
URL: receiveURL,
117128
Data: validReceiveMMS,
118129
ExpectedRespStatus: 200,
119-
ExpectedBodyContains: "Message Accepted",
130+
ExpectedBodyContains: "OK",
120131
ExpectedAttachments: []string{"https://foo.bar/image.jpg"},
121132
ExpectedURN: "tel:+18885551515",
122133
ExpectedDate: time.Date(2023, time.July, 27, 00, 49, 29, 0, time.UTC),
123134
PrepRequest: addValidSignature,
124135
},
125136
{
126137
Label: "Bad JWT Signature",
127-
Headers: map[string]string{"Content-Type": "application/json"},
138+
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
128139
URL: receiveURL,
129140
Data: validReceive,
130141
ExpectedRespStatus: 400,
@@ -133,28 +144,28 @@ var defaultReceiveTestCases = []IncomingTestCase{
133144
},
134145
{
135146
Label: "Missing JWT Signature Header",
136-
Headers: map[string]string{"Content-Type": "application/json"},
147+
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
137148
URL: receiveURL,
138149
Data: validReceive,
139150
ExpectedRespStatus: 400,
140151
ExpectedBodyContains: `{"message":"Error","data":[{"type":"error","error":"missing request signature"}]}`,
141152
},
142153
{
143154
Label: "Receive Valid w Signature but non-matching body hash",
144-
Headers: map[string]string{"Content-Type": "application/json"},
155+
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
145156
URL: receiveURL,
146157
Data: validReceive,
147158
ExpectedRespStatus: 400,
148159
ExpectedBodyContains: `{"message":"Error","data":[{"type":"error","error":"invalid request signature, signature doesn't match expected signature for body."}]}`,
149160
PrepRequest: addInvalidBodyHash,
150161
},
151162
{
152-
Label: "Bad JSON",
153-
Headers: map[string]string{"Content-Type": "application/json"},
163+
Label: "Empty Body",
164+
Headers: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
154165
URL: receiveURL,
155-
Data: "empty",
166+
Data: invalidReceive,
156167
ExpectedRespStatus: 400,
157-
ExpectedBodyContains: `{"message":"Error","data":[{"type":"error","error":"unable to parse request JSON: invalid character 'e' looking for beginning of value"}]}`,
168+
ExpectedBodyContains: `{"message":"Error","data":[{"type":"error","error":"no text or media"}]}`,
158169
PrepRequest: addValidSignature,
159170
},
160171
{

0 commit comments

Comments
 (0)