Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkg/delivery/apns.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ func (a ApnsDelivery) buildNotification(req interfaces.SendRequest) *apns2.Notif
Custom("messageKind", string(req.MessageContext.MessageType)).
Custom("payloadFormat", req.PayloadFormat.String())

if req.TopicBytesB64 != "" {
notificationPayload = notificationPayload.Custom("topicBytesB64", req.TopicBytesB64)
}

if req.Subscription.IsSilent {
notificationPayload = notificationPayload.ContentAvailable()
} else {
Expand Down
21 changes: 20 additions & 1 deletion pkg/delivery/apns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func buildDeliveryRequest(t *testing.T, payloadFormat interfaces.PayloadFormat)
parsed, err := topics.ParseV3Topic(deliveryTestTopic)
require.NoError(t, err)
topicStr := topics.TopicToString(parsed)
return interfaces.SendRequest{
req := interfaces.SendRequest{
Topic: topicStr,
EncryptedMessage: []byte("test"),
PayloadFormat: payloadFormat,
Expand All @@ -32,6 +32,10 @@ func buildDeliveryRequest(t *testing.T, payloadFormat interfaces.PayloadFormat)
},
MessageContext: interfaces.MessageContext{MessageType: topics.V3Conversation},
}
if payloadFormat == interfaces.PayloadFormatV4 {
req.TopicBytesB64 = topics.TopicToBase64(parsed)
}
return req
}

func TestApns_PayloadIncludesPayloadFormat(t *testing.T) {
Expand Down Expand Up @@ -62,3 +66,18 @@ func Test_ApnsDelivery_BuildNotification_TopicField(t *testing.T) {
require.Equal(t, "device-token", notification.DeviceToken)
require.Equal(t, "com.example.app", notification.Topic)
}

func Test_ApnsDelivery_BuildNotification_V4TopicBytesB64(t *testing.T) {
a := ApnsDelivery{opts: options.ApnsOptions{Topic: "com.example.app"}}
req := buildDeliveryRequest(t, interfaces.PayloadFormatV4)

notification := a.buildNotification(req)
payloadBytes, err := notification.Payload.(*payload.Payload).MarshalJSON()
require.NoError(t, err)

var p map[string]interface{}
require.NoError(t, json.Unmarshal(payloadBytes, &p))
require.Equal(t, deliveryTestTopic, p["topic"])
require.Equal(t, req.TopicBytesB64, p["topicBytesB64"])
require.Equal(t, "v4", p["payloadFormat"])
}
26 changes: 19 additions & 7 deletions pkg/delivery/fcm.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,7 @@ func (f FcmDelivery) Send(ctx context.Context, req interfaces.SendRequest) error
APNS: &messaging.APNSConfig{
Headers: apnsHeaders,
Payload: &messaging.APNSPayload{
CustomData: map[string]interface{}{
"topic": req.Topic,
"encryptedMessage": data["encryptedMessage"],
"messageType": data["messageType"],
"payloadFormat": data["payloadFormat"],
},
CustomData: buildFcmApnsCustomData(req, data),
Aps: &messaging.Aps{
ContentAvailable: req.Subscription.IsSilent,
MutableContent: !req.Subscription.IsSilent,
Expand All @@ -93,11 +88,28 @@ func (f FcmDelivery) Send(ctx context.Context, req interfaces.SendRequest) error
return err
}

func buildFcmApnsCustomData(req interfaces.SendRequest, data map[string]string) map[string]interface{} {
customData := map[string]interface{}{
"topic": req.Topic,
"encryptedMessage": data["encryptedMessage"],
"messageType": data["messageType"],
"payloadFormat": data["payloadFormat"],
}
if req.TopicBytesB64 != "" {
customData["topicBytesB64"] = req.TopicBytesB64
}
return customData
}

func buildFcmData(req interfaces.SendRequest) map[string]string {
return map[string]string{
data := map[string]string{
"topic": req.Topic,
"encryptedMessage": base64.StdEncoding.EncodeToString(req.EncryptedMessage),
"messageType": string(req.MessageContext.MessageType),
"payloadFormat": req.PayloadFormat.String(),
}
if req.TopicBytesB64 != "" {
data["topicBytesB64"] = req.TopicBytesB64
}
return data
}
9 changes: 9 additions & 0 deletions pkg/delivery/fcm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ func Test_BuildFcmData_TopicField(t *testing.T) {
require.Equal(t, base64.StdEncoding.EncodeToString([]byte("test")), data["encryptedMessage"])
require.Equal(t, "v3-conversation", data["messageType"])
}

func Test_BuildFcmData_V4TopicBytesB64(t *testing.T) {
req := buildDeliveryRequest(t, interfaces.PayloadFormatV4)

data := buildFcmData(req)
require.Equal(t, deliveryTestTopic, data["topic"])
require.Equal(t, req.TopicBytesB64, data["topicBytesB64"])
require.Equal(t, "v4", data["payloadFormat"])
}
3 changes: 3 additions & 0 deletions pkg/interfaces/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ type Subscription struct {
type SendRequest struct {
IdempotencyKey string `json:"-"`
Topic string `json:"-"`
TopicBytesB64 string `json:"-"`
EncryptedMessage []byte `json:"-"`
PayloadFormat PayloadFormat `json:"-"`
MessageContext MessageContext `json:"-"`
Expand All @@ -142,6 +143,7 @@ type sendRequestJSON struct {
Installation Installation `json:"installation"`
Subscription Subscription `json:"subscription"`
PayloadFormat PayloadFormat `json:"payload_format,omitempty"`
TopicBytesB64 string `json:"topicBytesB64,omitempty"`
}

func (r SendRequest) MarshalJSON() ([]byte, error) {
Expand All @@ -151,6 +153,7 @@ func (r SendRequest) MarshalJSON() ([]byte, error) {
Installation: r.Installation,
Subscription: r.Subscription,
PayloadFormat: r.PayloadFormat,
TopicBytesB64: r.TopicBytesB64,
}
out.Message.ContentTopic = r.Topic
out.Message.Message = r.EncryptedMessage
Expand Down
43 changes: 43 additions & 0 deletions pkg/interfaces/interfaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type sendRequestJSONFixture struct {
} `json:"message_context"`
Topic string `json:"topic"`
EncryptedMessage string `json:"encrypted_message"`
TopicBytesB64 string `json:"topicBytesB64"`
}

func TestPayloadFormat_String(t *testing.T) {
Expand Down Expand Up @@ -108,6 +109,48 @@ func TestSendRequest_MarshalJSON_BackwardCompatible(t *testing.T) {
require.Equal(t, "v3-welcome", result.MessageContext.MessageType)
}

func TestSendRequest_MarshalJSON_TopicBytesIncluded(t *testing.T) {
req := SendRequest{
IdempotencyKey: "abc123",
Topic: "/xmtp/mls/1/g-01020304/proto",
TopicBytesB64: "AQECBA==",
EncryptedMessage: []byte("encrypted-data"),
PayloadFormat: PayloadFormatV4,
MessageContext: MessageContext{MessageType: "v3-conversation"},
}

data, err := json.Marshal(req)
require.NoError(t, err)

var result sendRequestJSONFixture
require.NoError(t, json.Unmarshal(data, &result))

require.Equal(t, "/xmtp/mls/1/g-01020304/proto", result.Message.ContentTopic)
require.Equal(t, "AQECBA==", result.TopicBytesB64)
}

func TestSendRequest_MarshalJSON_TopicBytesOmittedWhenEmpty(t *testing.T) {
req := SendRequest{
IdempotencyKey: "abc123",
Topic: "/xmtp/mls/1/g-01020304/proto",
EncryptedMessage: []byte("encrypted-data"),
PayloadFormat: PayloadFormatV3,
MessageContext: MessageContext{MessageType: "v3-conversation"},
}

data, err := json.Marshal(req)
require.NoError(t, err)

var result sendRequestJSONFixture
require.NoError(t, json.Unmarshal(data, &result))

require.Empty(t, result.TopicBytesB64)
// Also verify it's not in the raw JSON at all
var raw map[string]interface{}
require.NoError(t, json.Unmarshal(data, &raw))
require.NotContains(t, raw, "topicBytesB64")
}

func Test_Subscription_MarshalJSON_TopicV4NotSerialized(t *testing.T) {
tp := topic.NewTopic(topic.TopicKindGroupMessagesV1, []byte{0x24, 0xce})
sub := Subscription{TopicV4: tp, Topic: "", IsSilent: false}
Expand Down
3 changes: 2 additions & 1 deletion pkg/xmtp/v4_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ func buildV4SendRequest(

return interfaces.SendRequest{
IdempotencyKey: idempotencyKey,
Topic: topics.TopicToBase64(targetTopic),
Topic: topics.TopicToLegacy(targetTopic),
TopicBytesB64: topics.TopicToBase64(targetTopic),
EncryptedMessage: envBytes,
PayloadFormat: interfaces.PayloadFormatV4,
MessageContext: messageContext,
Expand Down
9 changes: 6 additions & 3 deletions pkg/xmtp/v4_listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ func TestV4Listener_ProcessGroupMessage_V4Format(t *testing.T) {
require.Len(t, sendReqs, 1)
capturedReq := testutils.RequireSendRequestForInstallation(t, sendReqs, "inst-v4")
require.Equal(t, interfaces.PayloadFormatV4, capturedReq.PayloadFormat)
require.Equal(t, topicutil.TopicToBase64(groupTopic), capturedReq.Topic)
require.Equal(t, topicutil.TopicToLegacy(groupTopic), capturedReq.Topic)
require.Equal(t, topicutil.TopicToBase64(groupTopic), capturedReq.TopicBytesB64)
require.NotEmpty(t, capturedReq.EncryptedMessage)
require.Equal(t, topicutil.V3Conversation, capturedReq.MessageContext.MessageType)

Expand Down Expand Up @@ -296,7 +297,8 @@ func TestV4Listener_ProcessGroupMessage_MixedFormats(t *testing.T) {

v4Req := testutils.RequireSendRequestForInstallation(t, sendReqs, "inst-mixed-v4")
require.Equal(t, interfaces.PayloadFormatV4, v4Req.PayloadFormat)
require.Equal(t, topicutil.TopicToBase64(groupTopic), v4Req.Topic)
require.Equal(t, topicutil.TopicToLegacy(groupTopic), v4Req.Topic)
require.Equal(t, topicutil.TopicToBase64(groupTopic), v4Req.TopicBytesB64)
}

// TestV4Listener_SkipNonConvertiblePayload_V3Format tests that a non-group/welcome payload
Expand Down Expand Up @@ -365,7 +367,8 @@ func TestV4Listener_DeliverNonConvertiblePayload_V4Format(t *testing.T) {
require.Len(t, sendReqs, 1)
capturedReq := testutils.RequireSendRequestForInstallation(t, sendReqs, "inst-payer-v4")
require.Equal(t, interfaces.PayloadFormatV4, capturedReq.PayloadFormat)
require.Equal(t, topicutil.TopicToBase64(payerReportTopic), capturedReq.Topic)
require.Equal(t, topicutil.TopicToLegacy(payerReportTopic), capturedReq.Topic)
require.Equal(t, topicutil.TopicToBase64(payerReportTopic), capturedReq.TopicBytesB64)
require.Equal(t, topicutil.Unknown, capturedReq.MessageContext.MessageType)

var deliveredEnv envelopesProto.OriginatorEnvelope
Expand Down
Loading