From a15919527b47c0591e4d5a614d678a1a420c89a2 Mon Sep 17 00:00:00 2001 From: Andrea Maria Piana Date: Thu, 2 Jul 2020 10:08:19 +0200 Subject: [PATCH] implement handle push notification registration --- protocol/protobuf/push_notifications.pb.go | 267 +++++++---------- protocol/protobuf/push_notifications.proto | 7 +- .../push_notification.go | 4 +- .../push_notification_test.go | 4 +- protocol/push_notification_server/errors.go | 12 + .../push_notification_server.go | 98 +++--- .../push_notification_server_persistence.go | 32 +- ...sh_notification_server_persistence_test.go | 8 +- .../push_notification_server_test.go | 280 ++++++++++++++++-- 9 files changed, 467 insertions(+), 245 deletions(-) create mode 100644 protocol/push_notification_server/errors.go diff --git a/protocol/protobuf/push_notifications.pb.go b/protocol/protobuf/push_notifications.pb.go index 3d7fda805..3694c30ff 100644 --- a/protocol/protobuf/push_notifications.pb.go +++ b/protocol/protobuf/push_notifications.pb.go @@ -20,32 +20,32 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -type PushNotificationOptions_TokenType int32 +type PushNotificationRegistration_TokenType int32 const ( - PushNotificationOptions_UNKNOWN_TOKEN_TYPE PushNotificationOptions_TokenType = 0 - PushNotificationOptions_APN_TOKEN PushNotificationOptions_TokenType = 1 - PushNotificationOptions_FIREBASE_TOKEN PushNotificationOptions_TokenType = 2 + PushNotificationRegistration_UNKNOWN_TOKEN_TYPE PushNotificationRegistration_TokenType = 0 + PushNotificationRegistration_APN_TOKEN PushNotificationRegistration_TokenType = 1 + PushNotificationRegistration_FIREBASE_TOKEN PushNotificationRegistration_TokenType = 2 ) -var PushNotificationOptions_TokenType_name = map[int32]string{ +var PushNotificationRegistration_TokenType_name = map[int32]string{ 0: "UNKNOWN_TOKEN_TYPE", 1: "APN_TOKEN", 2: "FIREBASE_TOKEN", } -var PushNotificationOptions_TokenType_value = map[string]int32{ +var PushNotificationRegistration_TokenType_value = map[string]int32{ "UNKNOWN_TOKEN_TYPE": 0, "APN_TOKEN": 1, "FIREBASE_TOKEN": 2, } -func (x PushNotificationOptions_TokenType) String() string { - return proto.EnumName(PushNotificationOptions_TokenType_name, int32(x)) +func (x PushNotificationRegistration_TokenType) String() string { + return proto.EnumName(PushNotificationRegistration_TokenType_name, int32(x)) } -func (PushNotificationOptions_TokenType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{1, 0} +func (PushNotificationRegistration_TokenType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_200acd86044eaa5d, []int{0, 0} } type PushNotificationRegistrationResponse_ErrorType int32 @@ -79,153 +79,106 @@ func (x PushNotificationRegistrationResponse_ErrorType) String() string { } func (PushNotificationRegistrationResponse_ErrorType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{2, 0} + return fileDescriptor_200acd86044eaa5d, []int{1, 0} } -type PushNotificationTokenPair struct { - Token []byte `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` - PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type PushNotificationRegistration struct { + TokenType PushNotificationRegistration_TokenType `protobuf:"varint,1,opt,name=token_type,json=tokenType,proto3,enum=protobuf.PushNotificationRegistration_TokenType" json:"token_type,omitempty"` + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + InstallationId string `protobuf:"bytes,3,opt,name=installation_id,json=installationId,proto3" json:"installation_id,omitempty"` + AccessToken string `protobuf:"bytes,4,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"` + Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"` + Version uint64 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"` + AllowedUserList [][]byte `protobuf:"bytes,7,rep,name=allowed_user_list,json=allowedUserList,proto3" json:"allowed_user_list,omitempty"` + BlockedChatList [][]byte `protobuf:"bytes,8,rep,name=blocked_chat_list,json=blockedChatList,proto3" json:"blocked_chat_list,omitempty"` + Unregister bool `protobuf:"varint,9,opt,name=unregister,proto3" json:"unregister,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *PushNotificationTokenPair) Reset() { *m = PushNotificationTokenPair{} } -func (m *PushNotificationTokenPair) String() string { return proto.CompactTextString(m) } -func (*PushNotificationTokenPair) ProtoMessage() {} -func (*PushNotificationTokenPair) Descriptor() ([]byte, []int) { +func (m *PushNotificationRegistration) Reset() { *m = PushNotificationRegistration{} } +func (m *PushNotificationRegistration) String() string { return proto.CompactTextString(m) } +func (*PushNotificationRegistration) ProtoMessage() {} +func (*PushNotificationRegistration) Descriptor() ([]byte, []int) { return fileDescriptor_200acd86044eaa5d, []int{0} } -func (m *PushNotificationTokenPair) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PushNotificationTokenPair.Unmarshal(m, b) +func (m *PushNotificationRegistration) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PushNotificationRegistration.Unmarshal(m, b) } -func (m *PushNotificationTokenPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PushNotificationTokenPair.Marshal(b, m, deterministic) +func (m *PushNotificationRegistration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PushNotificationRegistration.Marshal(b, m, deterministic) } -func (m *PushNotificationTokenPair) XXX_Merge(src proto.Message) { - xxx_messageInfo_PushNotificationTokenPair.Merge(m, src) +func (m *PushNotificationRegistration) XXX_Merge(src proto.Message) { + xxx_messageInfo_PushNotificationRegistration.Merge(m, src) } -func (m *PushNotificationTokenPair) XXX_Size() int { - return xxx_messageInfo_PushNotificationTokenPair.Size(m) +func (m *PushNotificationRegistration) XXX_Size() int { + return xxx_messageInfo_PushNotificationRegistration.Size(m) } -func (m *PushNotificationTokenPair) XXX_DiscardUnknown() { - xxx_messageInfo_PushNotificationTokenPair.DiscardUnknown(m) +func (m *PushNotificationRegistration) XXX_DiscardUnknown() { + xxx_messageInfo_PushNotificationRegistration.DiscardUnknown(m) } -var xxx_messageInfo_PushNotificationTokenPair proto.InternalMessageInfo +var xxx_messageInfo_PushNotificationRegistration proto.InternalMessageInfo -func (m *PushNotificationTokenPair) GetToken() []byte { - if m != nil { - return m.Token - } - return nil -} - -func (m *PushNotificationTokenPair) GetPublicKey() []byte { - if m != nil { - return m.PublicKey - } - return nil -} - -type PushNotificationOptions struct { - TokenType PushNotificationOptions_TokenType `protobuf:"varint,1,opt,name=token_type,json=tokenType,proto3,enum=protobuf.PushNotificationOptions_TokenType" json:"token_type,omitempty"` - Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` - InstallationId string `protobuf:"bytes,3,opt,name=installation_id,json=installationId,proto3" json:"installation_id,omitempty"` - AccessToken string `protobuf:"bytes,4,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"` - Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"` - Version uint64 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"` - AllowedUserList [][]byte `protobuf:"bytes,7,rep,name=allowed_user_list,json=allowedUserList,proto3" json:"allowed_user_list,omitempty"` - BlockedChatList [][]byte `protobuf:"bytes,8,rep,name=blocked_chat_list,json=blockedChatList,proto3" json:"blocked_chat_list,omitempty"` - Unregister bool `protobuf:"varint,9,opt,name=unregister,proto3" json:"unregister,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *PushNotificationOptions) Reset() { *m = PushNotificationOptions{} } -func (m *PushNotificationOptions) String() string { return proto.CompactTextString(m) } -func (*PushNotificationOptions) ProtoMessage() {} -func (*PushNotificationOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{1} -} - -func (m *PushNotificationOptions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PushNotificationOptions.Unmarshal(m, b) -} -func (m *PushNotificationOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PushNotificationOptions.Marshal(b, m, deterministic) -} -func (m *PushNotificationOptions) XXX_Merge(src proto.Message) { - xxx_messageInfo_PushNotificationOptions.Merge(m, src) -} -func (m *PushNotificationOptions) XXX_Size() int { - return xxx_messageInfo_PushNotificationOptions.Size(m) -} -func (m *PushNotificationOptions) XXX_DiscardUnknown() { - xxx_messageInfo_PushNotificationOptions.DiscardUnknown(m) -} - -var xxx_messageInfo_PushNotificationOptions proto.InternalMessageInfo - -func (m *PushNotificationOptions) GetTokenType() PushNotificationOptions_TokenType { +func (m *PushNotificationRegistration) GetTokenType() PushNotificationRegistration_TokenType { if m != nil { return m.TokenType } - return PushNotificationOptions_UNKNOWN_TOKEN_TYPE + return PushNotificationRegistration_UNKNOWN_TOKEN_TYPE } -func (m *PushNotificationOptions) GetToken() string { +func (m *PushNotificationRegistration) GetToken() string { if m != nil { return m.Token } return "" } -func (m *PushNotificationOptions) GetInstallationId() string { +func (m *PushNotificationRegistration) GetInstallationId() string { if m != nil { return m.InstallationId } return "" } -func (m *PushNotificationOptions) GetAccessToken() string { +func (m *PushNotificationRegistration) GetAccessToken() string { if m != nil { return m.AccessToken } return "" } -func (m *PushNotificationOptions) GetEnabled() bool { +func (m *PushNotificationRegistration) GetEnabled() bool { if m != nil { return m.Enabled } return false } -func (m *PushNotificationOptions) GetVersion() uint64 { +func (m *PushNotificationRegistration) GetVersion() uint64 { if m != nil { return m.Version } return 0 } -func (m *PushNotificationOptions) GetAllowedUserList() [][]byte { +func (m *PushNotificationRegistration) GetAllowedUserList() [][]byte { if m != nil { return m.AllowedUserList } return nil } -func (m *PushNotificationOptions) GetBlockedChatList() [][]byte { +func (m *PushNotificationRegistration) GetBlockedChatList() [][]byte { if m != nil { return m.BlockedChatList } return nil } -func (m *PushNotificationOptions) GetUnregister() bool { +func (m *PushNotificationRegistration) GetUnregister() bool { if m != nil { return m.Unregister } @@ -245,7 +198,7 @@ func (m *PushNotificationRegistrationResponse) Reset() { *m = PushNotifi func (m *PushNotificationRegistrationResponse) String() string { return proto.CompactTextString(m) } func (*PushNotificationRegistrationResponse) ProtoMessage() {} func (*PushNotificationRegistrationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{2} + return fileDescriptor_200acd86044eaa5d, []int{1} } func (m *PushNotificationRegistrationResponse) XXX_Unmarshal(b []byte) error { @@ -300,7 +253,7 @@ func (m *PushNotificationAdvertisementInfo) Reset() { *m = PushNotificat func (m *PushNotificationAdvertisementInfo) String() string { return proto.CompactTextString(m) } func (*PushNotificationAdvertisementInfo) ProtoMessage() {} func (*PushNotificationAdvertisementInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{3} + return fileDescriptor_200acd86044eaa5d, []int{2} } func (m *PushNotificationAdvertisementInfo) XXX_Unmarshal(b []byte) error { @@ -353,7 +306,7 @@ func (m *ContactCodeAdvertisement) Reset() { *m = ContactCodeAdvertiseme func (m *ContactCodeAdvertisement) String() string { return proto.CompactTextString(m) } func (*ContactCodeAdvertisement) ProtoMessage() {} func (*ContactCodeAdvertisement) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{4} + return fileDescriptor_200acd86044eaa5d, []int{3} } func (m *ContactCodeAdvertisement) XXX_Unmarshal(b []byte) error { @@ -392,7 +345,7 @@ func (m *PushNotificationQuery) Reset() { *m = PushNotificationQuery{} } func (m *PushNotificationQuery) String() string { return proto.CompactTextString(m) } func (*PushNotificationQuery) ProtoMessage() {} func (*PushNotificationQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{5} + return fileDescriptor_200acd86044eaa5d, []int{4} } func (m *PushNotificationQuery) XXX_Unmarshal(b []byte) error { @@ -434,7 +387,7 @@ func (m *PushNotificationQueryInfo) Reset() { *m = PushNotificationQuery func (m *PushNotificationQueryInfo) String() string { return proto.CompactTextString(m) } func (*PushNotificationQueryInfo) ProtoMessage() {} func (*PushNotificationQueryInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{6} + return fileDescriptor_200acd86044eaa5d, []int{5} } func (m *PushNotificationQueryInfo) XXX_Unmarshal(b []byte) error { @@ -494,7 +447,7 @@ func (m *PushNotificationQueryResponse) Reset() { *m = PushNotificationQ func (m *PushNotificationQueryResponse) String() string { return proto.CompactTextString(m) } func (*PushNotificationQueryResponse) ProtoMessage() {} func (*PushNotificationQueryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{7} + return fileDescriptor_200acd86044eaa5d, []int{6} } func (m *PushNotificationQueryResponse) XXX_Unmarshal(b []byte) error { @@ -534,7 +487,7 @@ func (m *PushNotification) Reset() { *m = PushNotification{} } func (m *PushNotification) String() string { return proto.CompactTextString(m) } func (*PushNotification) ProtoMessage() {} func (*PushNotification) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{8} + return fileDescriptor_200acd86044eaa5d, []int{7} } func (m *PushNotification) XXX_Unmarshal(b []byte) error { @@ -583,7 +536,7 @@ func (m *PushNotificationRequest) Reset() { *m = PushNotificationRequest func (m *PushNotificationRequest) String() string { return proto.CompactTextString(m) } func (*PushNotificationRequest) ProtoMessage() {} func (*PushNotificationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{9} + return fileDescriptor_200acd86044eaa5d, []int{8} } func (m *PushNotificationRequest) XXX_Unmarshal(b []byte) error { @@ -643,7 +596,7 @@ func (m *PushNotificationAcknowledgement) Reset() { *m = PushNotificatio func (m *PushNotificationAcknowledgement) String() string { return proto.CompactTextString(m) } func (*PushNotificationAcknowledgement) ProtoMessage() {} func (*PushNotificationAcknowledgement) Descriptor() ([]byte, []int) { - return fileDescriptor_200acd86044eaa5d, []int{10} + return fileDescriptor_200acd86044eaa5d, []int{9} } func (m *PushNotificationAcknowledgement) XXX_Unmarshal(b []byte) error { @@ -672,10 +625,9 @@ func (m *PushNotificationAcknowledgement) GetId() string { } func init() { - proto.RegisterEnum("protobuf.PushNotificationOptions_TokenType", PushNotificationOptions_TokenType_name, PushNotificationOptions_TokenType_value) + proto.RegisterEnum("protobuf.PushNotificationRegistration_TokenType", PushNotificationRegistration_TokenType_name, PushNotificationRegistration_TokenType_value) proto.RegisterEnum("protobuf.PushNotificationRegistrationResponse_ErrorType", PushNotificationRegistrationResponse_ErrorType_name, PushNotificationRegistrationResponse_ErrorType_value) - proto.RegisterType((*PushNotificationTokenPair)(nil), "protobuf.PushNotificationTokenPair") - proto.RegisterType((*PushNotificationOptions)(nil), "protobuf.PushNotificationOptions") + proto.RegisterType((*PushNotificationRegistration)(nil), "protobuf.PushNotificationRegistration") proto.RegisterType((*PushNotificationRegistrationResponse)(nil), "protobuf.PushNotificationRegistrationResponse") proto.RegisterType((*PushNotificationAdvertisementInfo)(nil), "protobuf.PushNotificationAdvertisementInfo") proto.RegisterType((*ContactCodeAdvertisement)(nil), "protobuf.ContactCodeAdvertisement") @@ -690,54 +642,53 @@ func init() { func init() { proto.RegisterFile("push_notifications.proto", fileDescriptor_200acd86044eaa5d) } var fileDescriptor_200acd86044eaa5d = []byte{ - // 781 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0xdd, 0x6e, 0xe2, 0x46, - 0x14, 0xae, 0x0d, 0x49, 0xf0, 0x09, 0x25, 0x64, 0x94, 0x1f, 0x37, 0x52, 0x1a, 0xe2, 0x56, 0x2a, - 0x6a, 0x25, 0xa4, 0xa6, 0x52, 0x9b, 0x5b, 0x4a, 0x9c, 0xd6, 0x4d, 0x30, 0x74, 0x80, 0xfe, 0x5c, - 0x59, 0xc6, 0x1e, 0xc2, 0x08, 0xc7, 0xf6, 0x7a, 0xc6, 0x89, 0xb8, 0x58, 0x69, 0x9f, 0x60, 0xdf, - 0x64, 0x6f, 0x72, 0xbb, 0x2f, 0xb7, 0xf2, 0xd8, 0x06, 0x62, 0x48, 0x94, 0x2b, 0x7c, 0xce, 0x9c, - 0xdf, 0xef, 0x9c, 0xef, 0x00, 0x6a, 0x18, 0xb3, 0xa9, 0xe5, 0x07, 0x9c, 0x4e, 0xa8, 0x63, 0x73, - 0x1a, 0xf8, 0xac, 0x15, 0x46, 0x01, 0x0f, 0x50, 0x45, 0xfc, 0x8c, 0xe3, 0x89, 0xd6, 0x87, 0x6f, - 0xfa, 0x31, 0x9b, 0x9a, 0x2b, 0x46, 0xc3, 0x60, 0x46, 0xfc, 0xbe, 0x4d, 0x23, 0x74, 0x00, 0x5b, - 0x3c, 0x11, 0x54, 0xa9, 0x21, 0x35, 0xab, 0x38, 0x15, 0xd0, 0x29, 0x40, 0x18, 0x8f, 0x3d, 0xea, - 0x58, 0x33, 0x32, 0x57, 0x65, 0xf1, 0xa4, 0xa4, 0x9a, 0x1b, 0x32, 0xd7, 0x3e, 0x97, 0xe0, 0xb8, - 0x18, 0xb2, 0x17, 0x8a, 0xec, 0xe8, 0x2f, 0x00, 0x11, 0xc3, 0xe2, 0xf3, 0x90, 0x88, 0xa8, 0xb5, - 0x8b, 0x9f, 0x5a, 0x79, 0x31, 0xad, 0x17, 0xdc, 0x5a, 0xa2, 0xa2, 0xe1, 0x3c, 0x24, 0x58, 0xe1, - 0xf9, 0xe7, 0xb2, 0xb8, 0xa4, 0x02, 0x25, 0x2f, 0xee, 0x07, 0xd8, 0xa3, 0x3e, 0xe3, 0xb6, 0xe7, - 0x89, 0x08, 0x16, 0x75, 0xd5, 0x92, 0x78, 0xaf, 0xad, 0xaa, 0x0d, 0x17, 0x9d, 0x43, 0xd5, 0x76, - 0x1c, 0xc2, 0x98, 0x95, 0x46, 0x29, 0x0b, 0xab, 0xdd, 0x54, 0x27, 0x12, 0x22, 0x15, 0x76, 0x88, - 0x6f, 0x8f, 0x3d, 0xe2, 0xaa, 0x5b, 0x0d, 0xa9, 0x59, 0xc1, 0xb9, 0x98, 0xbc, 0x3c, 0x90, 0x88, - 0xd1, 0xc0, 0x57, 0xb7, 0x1b, 0x52, 0xb3, 0x8c, 0x73, 0x11, 0xfd, 0x08, 0xfb, 0xb6, 0xe7, 0x05, - 0x8f, 0xc4, 0xb5, 0x62, 0x46, 0x22, 0xcb, 0xa3, 0x8c, 0xab, 0x3b, 0x8d, 0x52, 0xb3, 0x8a, 0xf7, - 0xb2, 0x87, 0x11, 0x23, 0xd1, 0x2d, 0x65, 0x3c, 0xb1, 0x1d, 0x7b, 0x81, 0x33, 0x23, 0xae, 0xe5, - 0x4c, 0x6d, 0x9e, 0xda, 0x56, 0x52, 0xdb, 0xec, 0xa1, 0x33, 0xb5, 0xb9, 0xb0, 0xfd, 0x16, 0x20, - 0xf6, 0x23, 0x72, 0x47, 0x19, 0x27, 0x91, 0xaa, 0x88, 0x72, 0x56, 0x34, 0xda, 0x35, 0x28, 0x0b, - 0x94, 0xd0, 0x11, 0xa0, 0x91, 0x79, 0x63, 0xf6, 0xfe, 0x35, 0xad, 0x61, 0xef, 0x46, 0x37, 0xad, - 0xe1, 0xff, 0x7d, 0xbd, 0xfe, 0x15, 0xfa, 0x1a, 0x94, 0x76, 0x3f, 0xd3, 0xd5, 0x25, 0x84, 0xa0, - 0x76, 0x6d, 0x60, 0xfd, 0xf7, 0xf6, 0x40, 0xcf, 0x74, 0xb2, 0xf6, 0x24, 0xc3, 0xf7, 0xc5, 0x31, - 0x60, 0x91, 0x24, 0xca, 0xbe, 0x59, 0x18, 0xf8, 0x8c, 0x24, 0x10, 0xb0, 0x58, 0x80, 0x25, 0xe6, - 0x58, 0xc1, 0xb9, 0x88, 0x4c, 0xd8, 0x22, 0x51, 0x14, 0x44, 0x62, 0x30, 0xb5, 0x8b, 0xcb, 0x97, - 0xe7, 0xbb, 0x29, 0x70, 0x4b, 0x4f, 0x7c, 0xc5, 0xb0, 0xd3, 0x30, 0xc9, 0xbe, 0x45, 0xe4, 0x5d, - 0x4c, 0x18, 0xcf, 0xa7, 0x59, 0xc5, 0x4a, 0xa6, 0x31, 0x5c, 0xed, 0x83, 0x04, 0xca, 0xc2, 0x67, - 0xb5, 0x75, 0x1d, 0xe3, 0x1e, 0xce, 0x5b, 0x3f, 0x84, 0xfd, 0x6e, 0xfb, 0xf6, 0xba, 0x87, 0xbb, - 0xfa, 0x95, 0xd5, 0xd5, 0x07, 0x83, 0xf6, 0x1f, 0x7a, 0x5d, 0x42, 0x07, 0x50, 0xff, 0x47, 0xc7, - 0x03, 0xa3, 0x67, 0x5a, 0x5d, 0x63, 0xd0, 0x6d, 0x0f, 0x3b, 0x7f, 0xd6, 0x65, 0x74, 0x02, 0x47, - 0x23, 0x73, 0x30, 0xea, 0xf7, 0x7b, 0x78, 0xa8, 0x5f, 0xad, 0x62, 0x58, 0x4a, 0x40, 0x33, 0xcc, - 0xa1, 0x8e, 0xcd, 0xf6, 0x6d, 0x9a, 0xa1, 0x5e, 0xd6, 0x3e, 0x4a, 0x70, 0x5e, 0xec, 0xad, 0xed, - 0x3e, 0x90, 0x88, 0x53, 0x46, 0xee, 0x89, 0xcf, 0x0d, 0x7f, 0x12, 0x14, 0x78, 0x23, 0x15, 0x78, - 0xb3, 0xb6, 0x90, 0xf2, 0xfa, 0x42, 0xbe, 0x75, 0xb9, 0xb5, 0xf7, 0xa0, 0x76, 0x02, 0x9f, 0xdb, - 0x0e, 0xef, 0x04, 0x2e, 0x79, 0x56, 0x0a, 0xb2, 0xe1, 0x68, 0xed, 0x2e, 0x58, 0xd4, 0x9f, 0x04, - 0xaa, 0xd4, 0x28, 0x35, 0x77, 0x5f, 0xe3, 0xe3, 0x5a, 0x4f, 0xf8, 0x20, 0x2c, 0x98, 0x24, 0x5a, - 0xed, 0x12, 0x0e, 0x8b, 0xae, 0x7f, 0xc7, 0x24, 0x9a, 0xa3, 0x33, 0xd8, 0x5d, 0x42, 0xc0, 0x44, - 0xc2, 0x2a, 0x86, 0x05, 0x06, 0x4c, 0x7b, 0x92, 0xd6, 0xef, 0x91, 0x70, 0x15, 0x08, 0x16, 0x21, - 0x92, 0xde, 0x04, 0x91, 0xbc, 0x91, 0xff, 0xcf, 0xa7, 0x51, 0x2a, 0x4e, 0x63, 0x23, 0x8f, 0xcb, - 0xc2, 0xaa, 0xc8, 0x63, 0xed, 0x3f, 0x38, 0xdd, 0x58, 0xf3, 0x82, 0x2b, 0xbf, 0x41, 0x79, 0x05, - 0xe0, 0xef, 0x5e, 0x06, 0x78, 0xd1, 0x2a, 0x16, 0x0e, 0x9a, 0x09, 0xf5, 0xa2, 0xc9, 0x5b, 0x40, - 0x38, 0x86, 0x1d, 0x71, 0x50, 0x16, 0xcd, 0x6f, 0x27, 0xa2, 0xe1, 0x6a, 0x9f, 0xa4, 0xf5, 0xdb, - 0x8c, 0x53, 0x26, 0xa1, 0x5f, 0xa1, 0x92, 0x91, 0x8a, 0x65, 0x85, 0x9e, 0xbc, 0xc2, 0xdc, 0x85, - 0x6d, 0x72, 0x08, 0xee, 0x09, 0x63, 0xf6, 0x1d, 0xc9, 0xfe, 0x0b, 0x72, 0x31, 0x81, 0x38, 0xfb, - 0x5c, 0x6e, 0xaa, 0x92, 0x69, 0xf2, 0x0b, 0x3c, 0xb3, 0x92, 0x40, 0x34, 0x22, 0xee, 0xf2, 0x02, - 0xcf, 0x70, 0xa6, 0xd2, 0x7e, 0x86, 0xb3, 0xb5, 0x1d, 0x74, 0x66, 0x7e, 0xf0, 0xe8, 0x11, 0xf7, - 0x2e, 0x5d, 0xe7, 0x1a, 0xc8, 0xd4, 0xcd, 0x40, 0x90, 0xa9, 0x3b, 0xde, 0x16, 0x35, 0xff, 0xf2, - 0x25, 0x00, 0x00, 0xff, 0xff, 0x01, 0x0b, 0xdd, 0xd4, 0xfd, 0x06, 0x00, 0x00, + // 763 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdd, 0x6e, 0xda, 0x48, + 0x14, 0x5e, 0x1b, 0x92, 0xe0, 0x13, 0x96, 0x90, 0x51, 0x7e, 0xbc, 0xd1, 0x66, 0x43, 0xbc, 0x2b, + 0x2d, 0x6a, 0x25, 0xd4, 0xa6, 0x52, 0x9b, 0x5b, 0x4a, 0x9c, 0xd6, 0x4a, 0x30, 0x74, 0x80, 0xfe, + 0x5c, 0x59, 0xc6, 0x1e, 0x82, 0x85, 0xe3, 0xa1, 0x9e, 0x71, 0x22, 0x2e, 0x2a, 0xf5, 0x09, 0xfa, + 0x26, 0xbd, 0xc9, 0x3b, 0xf4, 0xbd, 0x2a, 0x8f, 0x6d, 0x42, 0x80, 0x44, 0x5c, 0xd9, 0xe7, 0x9b, + 0xef, 0xcc, 0xcc, 0xf9, 0xce, 0xf9, 0x06, 0xd4, 0x71, 0xc4, 0x86, 0x56, 0x40, 0xb9, 0x37, 0xf0, + 0x1c, 0x9b, 0x7b, 0x34, 0x60, 0xb5, 0x71, 0x48, 0x39, 0x45, 0x05, 0xf1, 0xe9, 0x47, 0x03, 0xed, + 0x57, 0x0e, 0xfe, 0x6e, 0x47, 0x6c, 0x68, 0xce, 0xb0, 0x30, 0xb9, 0xf2, 0x18, 0x0f, 0xc5, 0x3f, + 0x6a, 0x01, 0x70, 0x3a, 0x22, 0x81, 0xc5, 0x27, 0x63, 0xa2, 0x4a, 0x15, 0xa9, 0x5a, 0x3a, 0x79, + 0x51, 0xcb, 0xf2, 0x6b, 0x4f, 0xe5, 0xd6, 0xba, 0x71, 0x62, 0x77, 0x32, 0x26, 0x58, 0xe1, 0xd9, + 0x2f, 0xda, 0x81, 0x35, 0x11, 0xa8, 0x72, 0x45, 0xaa, 0x2a, 0x38, 0x09, 0xd0, 0xff, 0xb0, 0xe5, + 0x05, 0x8c, 0xdb, 0xbe, 0x2f, 0x52, 0x2d, 0xcf, 0x55, 0x73, 0x62, 0xbd, 0x34, 0x0b, 0x1b, 0x2e, + 0x3a, 0x86, 0xa2, 0xed, 0x38, 0x84, 0x31, 0x2b, 0xd9, 0x25, 0x2f, 0x58, 0x9b, 0x09, 0x26, 0x0e, + 0x44, 0x2a, 0x6c, 0x90, 0xc0, 0xee, 0xfb, 0xc4, 0x55, 0xd7, 0x2a, 0x52, 0xb5, 0x80, 0xb3, 0x30, + 0x5e, 0xb9, 0x21, 0x21, 0xf3, 0x68, 0xa0, 0xae, 0x57, 0xa4, 0x6a, 0x1e, 0x67, 0x21, 0x7a, 0x06, + 0xdb, 0xb6, 0xef, 0xd3, 0x5b, 0xe2, 0x5a, 0x11, 0x23, 0xa1, 0xe5, 0x7b, 0x8c, 0xab, 0x1b, 0x95, + 0x5c, 0xb5, 0x88, 0xb7, 0xd2, 0x85, 0x1e, 0x23, 0xe1, 0xa5, 0xc7, 0x78, 0xcc, 0xed, 0xfb, 0xd4, + 0x19, 0x11, 0xd7, 0x72, 0x86, 0x36, 0x4f, 0xb8, 0x85, 0x84, 0x9b, 0x2e, 0x34, 0x86, 0x36, 0x17, + 0xdc, 0x7f, 0x00, 0xa2, 0x20, 0x14, 0xa2, 0x90, 0x50, 0x55, 0xc4, 0x75, 0x66, 0x10, 0xed, 0x1c, + 0x94, 0xa9, 0x4a, 0x68, 0x0f, 0x50, 0xcf, 0xbc, 0x30, 0x5b, 0x9f, 0x4c, 0xab, 0xdb, 0xba, 0xd0, + 0x4d, 0xab, 0xfb, 0xa5, 0xad, 0x97, 0xff, 0x40, 0x7f, 0x82, 0x52, 0x6f, 0xa7, 0x58, 0x59, 0x42, + 0x08, 0x4a, 0xe7, 0x06, 0xd6, 0xdf, 0xd6, 0x3b, 0x7a, 0x8a, 0xc9, 0xda, 0x9d, 0x0c, 0xff, 0x3d, + 0xd5, 0x0b, 0x4c, 0xd8, 0x98, 0x06, 0x8c, 0xc4, 0x12, 0xb0, 0x48, 0x88, 0x25, 0x9a, 0x59, 0xc0, + 0x59, 0x88, 0x4c, 0x58, 0x23, 0x61, 0x48, 0x43, 0xd1, 0x98, 0xd2, 0xc9, 0xe9, 0x6a, 0x4d, 0xce, + 0x36, 0xae, 0xe9, 0x71, 0xae, 0x68, 0x76, 0xb2, 0x0d, 0x3a, 0x04, 0x08, 0xc9, 0xd7, 0x88, 0x30, + 0x9e, 0x75, 0xb3, 0x88, 0x95, 0x14, 0x31, 0x5c, 0xed, 0xbb, 0x04, 0xca, 0x34, 0x67, 0xb6, 0x74, + 0x1d, 0xe3, 0x16, 0xce, 0x4a, 0xdf, 0x85, 0xed, 0x66, 0xfd, 0xf2, 0xbc, 0x85, 0x9b, 0xfa, 0x99, + 0xd5, 0xd4, 0x3b, 0x9d, 0xfa, 0x3b, 0xbd, 0x2c, 0xa1, 0x1d, 0x28, 0x7f, 0xd4, 0x71, 0xc7, 0x68, + 0x99, 0x56, 0xd3, 0xe8, 0x34, 0xeb, 0xdd, 0xc6, 0xfb, 0xb2, 0x8c, 0x0e, 0x60, 0xaf, 0x67, 0x76, + 0x7a, 0xed, 0x76, 0x0b, 0x77, 0xf5, 0xb3, 0x59, 0x0d, 0x73, 0xb1, 0x68, 0x86, 0xd9, 0xd5, 0xb1, + 0x59, 0xbf, 0x4c, 0x4e, 0x28, 0xe7, 0xb5, 0x1f, 0x12, 0x1c, 0xcf, 0xd7, 0x56, 0x77, 0x6f, 0x48, + 0xc8, 0x3d, 0x46, 0xae, 0x49, 0xc0, 0x8d, 0x60, 0x40, 0xe3, 0x3a, 0xc6, 0x51, 0xdf, 0xf7, 0x1c, + 0x6b, 0x44, 0x26, 0x42, 0xb4, 0x22, 0x56, 0x12, 0xe4, 0x82, 0x4c, 0x16, 0x06, 0x52, 0x5e, 0x1c, + 0xc8, 0x55, 0x87, 0x5b, 0xfb, 0x06, 0x6a, 0x83, 0x06, 0xdc, 0x76, 0x78, 0x83, 0xba, 0xe4, 0xc1, + 0x55, 0x90, 0x0d, 0x7b, 0x0b, 0x7e, 0xb6, 0xbc, 0x60, 0x40, 0x55, 0xa9, 0x92, 0xab, 0x6e, 0x9e, + 0x3c, 0x7f, 0xbc, 0x5f, 0x0b, 0x35, 0xe1, 0x9d, 0xf1, 0x1c, 0x25, 0x46, 0xb5, 0x53, 0xd8, 0x9d, + 0x4f, 0xfd, 0x10, 0x91, 0x70, 0x82, 0x8e, 0x60, 0xf3, 0x5e, 0x02, 0x26, 0x0e, 0x2c, 0x62, 0x98, + 0x6a, 0xc0, 0xb4, 0x3b, 0x09, 0xfe, 0x5a, 0x9a, 0x2a, 0x14, 0x9c, 0x97, 0x48, 0x5a, 0x49, 0x22, + 0x79, 0xa9, 0xff, 0x1f, 0x76, 0x23, 0x37, 0xdf, 0x8d, 0xa5, 0x3e, 0xce, 0x0b, 0xd6, 0xbc, 0x8f, + 0xb5, 0xcf, 0x70, 0xb8, 0xf4, 0xce, 0x53, 0xaf, 0xbc, 0x81, 0xfc, 0x8c, 0xc0, 0xff, 0x3e, 0x2e, + 0xf0, 0xb4, 0x54, 0x2c, 0x12, 0x34, 0x13, 0xca, 0xf3, 0x94, 0x55, 0x44, 0xd8, 0x87, 0x0d, 0xf1, + 0xa0, 0x4c, 0x8b, 0x5f, 0x8f, 0x43, 0xc3, 0xd5, 0x7e, 0x4a, 0xb0, 0xbf, 0x68, 0x42, 0xe1, 0x24, + 0xf4, 0x1a, 0x0a, 0xa9, 0xa9, 0x58, 0x7a, 0xd1, 0x83, 0x27, 0x9c, 0x3b, 0xe5, 0xc6, 0x0f, 0xc1, + 0x35, 0x61, 0xcc, 0xbe, 0x22, 0xe2, 0xb0, 0x22, 0xce, 0xc2, 0x58, 0xe2, 0xf4, 0xf7, 0x7e, 0x52, + 0x95, 0x14, 0xc9, 0x5e, 0xe0, 0x91, 0x15, 0x6f, 0xe4, 0x85, 0xc4, 0xbd, 0x7f, 0x81, 0x47, 0x38, + 0x85, 0xb4, 0x97, 0x70, 0xb4, 0x30, 0x83, 0xce, 0x28, 0xa0, 0xb7, 0x3e, 0x71, 0xaf, 0x92, 0x71, + 0x2e, 0x81, 0xec, 0xb9, 0xa9, 0x08, 0xb2, 0xe7, 0xf6, 0xd7, 0xc5, 0x9d, 0x5f, 0xfd, 0x0e, 0x00, + 0x00, 0xff, 0xff, 0x6a, 0xc9, 0xcf, 0x6e, 0xb5, 0x06, 0x00, 0x00, } diff --git a/protocol/protobuf/push_notifications.proto b/protocol/protobuf/push_notifications.proto index d552c11b3..21f11353c 100644 --- a/protocol/protobuf/push_notifications.proto +++ b/protocol/protobuf/push_notifications.proto @@ -2,12 +2,7 @@ syntax = "proto3"; package protobuf; -message PushNotificationTokenPair { - bytes token = 1; - bytes public_key = 2; -} - -message PushNotificationOptions { +message PushNotificationRegistration { enum TokenType { UNKNOWN_TOKEN_TYPE = 0; APN_TOKEN = 1; diff --git a/protocol/push_notification_client/push_notification.go b/protocol/push_notification_client/push_notification.go index eb7354ddd..ceae98e03 100644 --- a/protocol/push_notification_client/push_notification.go +++ b/protocol/push_notification_client/push_notification.go @@ -126,14 +126,14 @@ func (p *Client) allowedUserList(token []byte) ([][]byte, error) { return encryptedTokens, nil } -func (p *Client) buildPushNotificationOptionsMessage() (*protobuf.PushNotificationOptions, error) { +func (p *Client) buildPushNotificationRegistrationMessage() (*protobuf.PushNotificationRegistration, error) { token := uuid.New().String() allowedUserList, err := p.allowedUserList([]byte(token)) if err != nil { return nil, err } - options := &protobuf.PushNotificationOptions{ + options := &protobuf.PushNotificationRegistration{ AccessToken: token, Version: p.lastPushNotificationVersion + 1, InstallationId: p.config.InstallationID, diff --git a/protocol/push_notification_client/push_notification_test.go b/protocol/push_notification_client/push_notification_test.go index 6ae4a1b29..d0b058a16 100644 --- a/protocol/push_notification_client/push_notification_test.go +++ b/protocol/push_notification_client/push_notification_test.go @@ -67,7 +67,7 @@ func TestBuildPushNotificationRegisterMessage(t *testing.T) { // Set reader client.reader = bytes.NewReader([]byte(expectedUUID)) - options := &protobuf.PushNotificationOptions{ + options := &protobuf.PushNotificationRegistration{ Version: 1, AccessToken: expectedUUID, Token: myDeviceToken, @@ -77,7 +77,7 @@ func TestBuildPushNotificationRegisterMessage(t *testing.T) { AllowedUserList: [][]byte{encryptedToken}, } - actualMessage, err := client.buildPushNotificationOptionsMessage() + actualMessage, err := client.buildPushNotificationRegistrationMessage() require.NoError(t, err) require.Equal(t, options, actualMessage) diff --git a/protocol/push_notification_server/errors.go b/protocol/push_notification_server/errors.go new file mode 100644 index 000000000..69b24a837 --- /dev/null +++ b/protocol/push_notification_server/errors.go @@ -0,0 +1,12 @@ +package push_notification_server + +import "errors" + +var ErrInvalidPushNotificationRegistrationVersion = errors.New("invalid version") +var ErrEmptyPushNotificationRegistrationPayload = errors.New("empty payload") +var ErrMalformedPushNotificationRegistrationInstallationID = errors.New("invalid installationID") +var ErrEmptyPushNotificationRegistrationPublicKey = errors.New("no public key") +var ErrCouldNotUnmarshalPushNotificationRegistration = errors.New("could not unmarshal preferences") +var ErrInvalidCiphertextLength = errors.New("invalid cyphertext length") +var ErrMalformedPushNotificationRegistrationAccessToken = errors.New("invalid access token") +var ErrMalformedPushNotificationRegistrationDeviceToken = errors.New("invalid device token") diff --git a/protocol/push_notification_server/push_notification_server.go b/protocol/push_notification_server/push_notification_server.go index 1607fe2db..ed809d6ec 100644 --- a/protocol/push_notification_server/push_notification_server.go +++ b/protocol/push_notification_server/push_notification_server.go @@ -7,6 +7,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/ecdsa" + "golang.org/x/crypto/sha3" "github.com/golang/protobuf/proto" "github.com/google/uuid" @@ -18,15 +19,6 @@ import ( const encryptedPayloadKeyLength = 16 const nonceLength = 12 -var ErrInvalidPushNotificationOptionsVersion = errors.New("invalid version") -var ErrEmptyPushNotificationOptionsPayload = errors.New("empty payload") -var ErrMalformedPushNotificationOptionsInstallationID = errors.New("invalid installationID") -var ErrEmptyPushNotificationOptionsPublicKey = errors.New("no public key") -var ErrCouldNotUnmarshalPushNotificationOptions = errors.New("could not unmarshal preferences") -var ErrInvalidCiphertextLength = errors.New("invalid cyphertext length") -var ErrMalformedPushNotificationOptionsAccessToken = errors.New("invalid access token") -var ErrMalformedPushNotificationOptionsDeviceToken = errors.New("invalid device token") - type Config struct { // Identity is our identity key Identity *ecdsa.PrivateKey @@ -70,13 +62,13 @@ func (p *Server) decryptRegistration(publicKey *ecdsa.PublicKey, payload []byte) // ValidateRegistration validates a new message against the last one received for a given installationID and and public key // and return the decrypted message -func (p *Server) ValidateRegistration(publicKey *ecdsa.PublicKey, payload []byte) (*protobuf.PushNotificationOptions, error) { +func (p *Server) ValidateRegistration(publicKey *ecdsa.PublicKey, payload []byte) (*protobuf.PushNotificationRegistration, error) { if payload == nil { - return nil, ErrEmptyPushNotificationOptionsPayload + return nil, ErrEmptyPushNotificationRegistrationPayload } if publicKey == nil { - return nil, ErrEmptyPushNotificationOptionsPublicKey + return nil, ErrEmptyPushNotificationRegistrationPublicKey } decryptedPayload, err := p.decryptRegistration(publicKey, payload) @@ -84,52 +76,82 @@ func (p *Server) ValidateRegistration(publicKey *ecdsa.PublicKey, payload []byte return nil, err } - options := &protobuf.PushNotificationOptions{} + registration := &protobuf.PushNotificationRegistration{} - if err := proto.Unmarshal(decryptedPayload, options); err != nil { - return nil, ErrCouldNotUnmarshalPushNotificationOptions + if err := proto.Unmarshal(decryptedPayload, registration); err != nil { + return nil, ErrCouldNotUnmarshalPushNotificationRegistration } - if options.Version < 1 { - return nil, ErrInvalidPushNotificationOptionsVersion + if registration.Version < 1 { + return nil, ErrInvalidPushNotificationRegistrationVersion } - if err := p.validateUUID(options.InstallationId); err != nil { - return nil, ErrMalformedPushNotificationOptionsInstallationID + if err := p.validateUUID(registration.InstallationId); err != nil { + return nil, ErrMalformedPushNotificationRegistrationInstallationID } - previousOptions, err := p.persistence.GetPushNotificationOptions(publicKey, options.InstallationId) + previousRegistration, err := p.persistence.GetPushNotificationRegistration(publicKey, registration.InstallationId) if err != nil { return nil, err } - if previousOptions != nil && options.Version <= previousOptions.Version { - return nil, ErrInvalidPushNotificationOptionsVersion + if previousRegistration != nil && registration.Version <= previousRegistration.Version { + return nil, ErrInvalidPushNotificationRegistrationVersion } // Unregistering message - if options.Unregister { - return options, nil + if registration.Unregister { + return registration, nil } - if err := p.validateUUID(options.AccessToken); err != nil { - return nil, ErrMalformedPushNotificationOptionsAccessToken + if err := p.validateUUID(registration.AccessToken); err != nil { + return nil, ErrMalformedPushNotificationRegistrationAccessToken } - if len(options.Token) == 0 { - return nil, ErrMalformedPushNotificationOptionsDeviceToken + if len(registration.Token) == 0 { + return nil, ErrMalformedPushNotificationRegistrationDeviceToken } - return options, nil + return registration, nil } -func (p *Server) HandlePushNotificationOptions(publicKey *ecdsa.PublicKey, payload []byte) error { - - _, err := p.ValidateRegistration(publicKey, payload) - if err != nil { - return err +func (p *Server) HandlePushNotificationRegistration(publicKey *ecdsa.PublicKey, payload []byte) *protobuf.PushNotificationRegistrationResponse { + response := &protobuf.PushNotificationRegistrationResponse{ + RequestId: shake256(payload), } - return nil + + registration, err := p.ValidateRegistration(publicKey, payload) + if registration != nil { + } + + if err != nil { + if err == ErrInvalidPushNotificationRegistrationVersion { + response.Error = protobuf.PushNotificationRegistrationResponse_VERSION_MISMATCH + } else { + response.Error = protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE + } + return response + } + + if registration.Unregister { + // We save an empty registration, only keeping version and installation-id + emptyRegistration := &protobuf.PushNotificationRegistration{ + Version: registration.Version, + InstallationId: registration.InstallationId, + } + if err := p.persistence.SavePushNotificationRegistration(publicKey, emptyRegistration); err != nil { + response.Error = protobuf.PushNotificationRegistrationResponse_INTERNAL_ERROR + return response + } + + } else if err := p.persistence.SavePushNotificationRegistration(publicKey, registration); err != nil { + response.Error = protobuf.PushNotificationRegistrationResponse_INTERNAL_ERROR + return response + } + + response.Success = true + + return response } func decrypt(cyphertext []byte, key []byte) ([]byte, error) { @@ -169,3 +191,9 @@ func encrypt(plaintext []byte, key []byte, reader io.Reader) ([]byte, error) { return gcm.Seal(nonce, nonce, plaintext, nil), nil } + +func shake256(buf []byte) []byte { + h := make([]byte, 64) + sha3.ShakeSum256(h, buf) + return h +} diff --git a/protocol/push_notification_server/push_notification_server_persistence.go b/protocol/push_notification_server/push_notification_server_persistence.go index 9f6131d84..f23673bda 100644 --- a/protocol/push_notification_server/push_notification_server_persistence.go +++ b/protocol/push_notification_server/push_notification_server_persistence.go @@ -11,12 +11,12 @@ import ( ) type Persistence interface { - // GetPushNotificationOptions retrieve a push notification options from storage given a public key and installation id - GetPushNotificationOptions(publicKey *ecdsa.PublicKey, installationID string) (*protobuf.PushNotificationOptions, error) - // DeletePushNotificationOptions deletes a push notification options from storage given a public key and installation id - DeletePushNotificationOptions(publicKey *ecdsa.PublicKey, installationID string) error - // SavePushNotificationOptions saves a push notification option to the db - SavePushNotificationOptions(publicKey *ecdsa.PublicKey, options *protobuf.PushNotificationOptions) error + // GetPushNotificationRegistration retrieve a push notification registration from storage given a public key and installation id + GetPushNotificationRegistration(publicKey *ecdsa.PublicKey, installationID string) (*protobuf.PushNotificationRegistration, error) + // DeletePushNotificationRegistration deletes a push notification registration from storage given a public key and installation id + DeletePushNotificationRegistration(publicKey *ecdsa.PublicKey, installationID string) error + // SavePushNotificationRegistration saves a push notification option to the db + SavePushNotificationRegistration(publicKey *ecdsa.PublicKey, registration *protobuf.PushNotificationRegistration) error } type SQLitePersistence struct { @@ -27,9 +27,9 @@ func NewSQLitePersistence(db *sql.DB) Persistence { return &SQLitePersistence{db: db} } -func (p *SQLitePersistence) GetPushNotificationOptions(publicKey *ecdsa.PublicKey, installationID string) (*protobuf.PushNotificationOptions, error) { - var marshaledOptions []byte - err := p.db.QueryRow(`SELECT registration FROM push_notification_server_registrations WHERE public_key = ? AND installation_id = ?`, crypto.CompressPubkey(publicKey), installationID).Scan(&marshaledOptions) +func (p *SQLitePersistence) GetPushNotificationRegistration(publicKey *ecdsa.PublicKey, installationID string) (*protobuf.PushNotificationRegistration, error) { + var marshaledRegistration []byte + err := p.db.QueryRow(`SELECT registration FROM push_notification_server_registrations WHERE public_key = ? AND installation_id = ?`, crypto.CompressPubkey(publicKey), installationID).Scan(&marshaledRegistration) if err == sql.ErrNoRows { return nil, nil @@ -37,26 +37,26 @@ func (p *SQLitePersistence) GetPushNotificationOptions(publicKey *ecdsa.PublicKe return nil, err } - options := &protobuf.PushNotificationOptions{} + registration := &protobuf.PushNotificationRegistration{} - if err := proto.Unmarshal(marshaledOptions, options); err != nil { + if err := proto.Unmarshal(marshaledRegistration, registration); err != nil { return nil, err } - return options, nil + return registration, nil } -func (p *SQLitePersistence) SavePushNotificationOptions(publicKey *ecdsa.PublicKey, options *protobuf.PushNotificationOptions) error { +func (p *SQLitePersistence) SavePushNotificationRegistration(publicKey *ecdsa.PublicKey, registration *protobuf.PushNotificationRegistration) error { compressedPublicKey := crypto.CompressPubkey(publicKey) - marshaledOptions, err := proto.Marshal(options) + marshaledRegistration, err := proto.Marshal(registration) if err != nil { return err } - _, err = p.db.Exec(`INSERT INTO push_notification_server_registrations (public_key, installation_id, version, registration) VALUES (?, ?, ?, ?)`, compressedPublicKey, options.InstallationId, options.Version, marshaledOptions) + _, err = p.db.Exec(`INSERT INTO push_notification_server_registrations (public_key, installation_id, version, registration) VALUES (?, ?, ?, ?)`, compressedPublicKey, registration.InstallationId, registration.Version, marshaledRegistration) return err } -func (p *SQLitePersistence) DeletePushNotificationOptions(publicKey *ecdsa.PublicKey, installationID string) error { +func (p *SQLitePersistence) DeletePushNotificationRegistration(publicKey *ecdsa.PublicKey, installationID string) error { _, err := p.db.Exec(`DELETE FROM push_notification_server_registrations WHERE public_key = ? AND installation_id = ?`, crypto.CompressPubkey(publicKey), installationID) return err } diff --git a/protocol/push_notification_server/push_notification_server_persistence_test.go b/protocol/push_notification_server/push_notification_server_persistence_test.go index 1bd0fb10d..d0b94dc59 100644 --- a/protocol/push_notification_server/push_notification_server_persistence_test.go +++ b/protocol/push_notification_server/push_notification_server_persistence_test.go @@ -44,15 +44,15 @@ func (s *SQLitePersistenceSuite) TestSaveAndRetrieve() { s.Require().NoError(err) installationID := "54242d02-bb92-11ea-b3de-0242ac130004" - options := &protobuf.PushNotificationOptions{ + registration := &protobuf.PushNotificationRegistration{ InstallationId: installationID, Version: 5, } - s.Require().NoError(s.persistence.SavePushNotificationOptions(&key.PublicKey, options)) + s.Require().NoError(s.persistence.SavePushNotificationRegistration(&key.PublicKey, registration)) - retrievedOptions, err := s.persistence.GetPushNotificationOptions(&key.PublicKey, installationID) + retrievedRegistration, err := s.persistence.GetPushNotificationRegistration(&key.PublicKey, installationID) s.Require().NoError(err) - s.Require().True(proto.Equal(options, retrievedOptions)) + s.Require().True(proto.Equal(registration, retrievedRegistration)) } diff --git a/protocol/push_notification_server/push_notification_server_test.go b/protocol/push_notification_server/push_notification_server_test.go index 9f4823584..bef6ee30a 100644 --- a/protocol/push_notification_server/push_notification_server_test.go +++ b/protocol/push_notification_server/push_notification_server_test.go @@ -54,11 +54,11 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { // Empty payload _, err = server.ValidateRegistration(&key.PublicKey, nil) - s.Require().Equal(ErrEmptyPushNotificationOptionsPayload, err) + s.Require().Equal(ErrEmptyPushNotificationRegistrationPayload, err) // Empty key _, err = server.ValidateRegistration(nil, []byte("payload")) - s.Require().Equal(ErrEmptyPushNotificationOptionsPublicKey, err) + s.Require().Equal(ErrEmptyPushNotificationRegistrationPublicKey, err) // Invalid cyphertext length _, err = server.ValidateRegistration(&key.PublicKey, []byte("too short")) @@ -82,10 +82,10 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt([]byte("plaintext"), sharedKey, rand.Reader) s.Require().NoError(err) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrCouldNotUnmarshalPushNotificationOptions, err) + s.Require().Equal(ErrCouldNotUnmarshalPushNotificationRegistration, err) // Missing installationID - payload, err := proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err := proto.Marshal(&protobuf.PushNotificationRegistration{ AccessToken: accessToken, Version: 1, }) @@ -94,10 +94,10 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt(payload, sharedKey, rand.Reader) s.Require().NoError(err) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrMalformedPushNotificationOptionsInstallationID, err) + s.Require().Equal(ErrMalformedPushNotificationRegistrationInstallationID, err) // Malformed installationID - payload, err = proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ AccessToken: accessToken, InstallationId: "abc", Version: 1, @@ -105,10 +105,10 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt(payload, sharedKey, rand.Reader) s.Require().NoError(err) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrMalformedPushNotificationOptionsInstallationID, err) + s.Require().Equal(ErrMalformedPushNotificationRegistrationInstallationID, err) // Version set to 0 - payload, err = proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ AccessToken: accessToken, InstallationId: installationID, }) @@ -117,10 +117,10 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt(payload, sharedKey, rand.Reader) s.Require().NoError(err) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrInvalidPushNotificationOptionsVersion, err) + s.Require().Equal(ErrInvalidPushNotificationRegistrationVersion, err) // Version lower than previous one - payload, err = proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ AccessToken: accessToken, InstallationId: installationID, Version: 1, @@ -130,20 +130,20 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt(payload, sharedKey, rand.Reader) s.Require().NoError(err) - // Setup mock - s.Require().NoError(s.persistence.SavePushNotificationOptions(&key.PublicKey, &protobuf.PushNotificationOptions{ + // Setup persistence + s.Require().NoError(s.persistence.SavePushNotificationRegistration(&key.PublicKey, &protobuf.PushNotificationRegistration{ AccessToken: accessToken, InstallationId: installationID, Version: 2})) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrInvalidPushNotificationOptionsVersion, err) + s.Require().Equal(ErrInvalidPushNotificationRegistrationVersion, err) - // Cleanup mock - s.Require().NoError(s.persistence.DeletePushNotificationOptions(&key.PublicKey, installationID)) + // Cleanup persistence + s.Require().NoError(s.persistence.DeletePushNotificationRegistration(&key.PublicKey, installationID)) // Unregistering message - payload, err = proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ InstallationId: installationID, Unregister: true, Version: 1, @@ -156,7 +156,7 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { s.Require().Nil(err) // Missing access token - payload, err = proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ InstallationId: installationID, Version: 1, }) @@ -165,10 +165,10 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt(payload, sharedKey, rand.Reader) s.Require().NoError(err) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrMalformedPushNotificationOptionsAccessToken, err) + s.Require().Equal(ErrMalformedPushNotificationRegistrationAccessToken, err) // Invalid access token - payload, err = proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ AccessToken: "bc", InstallationId: installationID, Version: 1, @@ -178,10 +178,10 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt(payload, sharedKey, rand.Reader) s.Require().NoError(err) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrMalformedPushNotificationOptionsAccessToken, err) + s.Require().Equal(ErrMalformedPushNotificationRegistrationAccessToken, err) // Missing device token - payload, err = proto.Marshal(&protobuf.PushNotificationOptions{ + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ AccessToken: accessToken, InstallationId: installationID, Version: 1, @@ -191,5 +191,241 @@ func (s *ServerSuite) TestPushNotificationServerValidateRegistration() { cyphertext, err = encrypt(payload, sharedKey, rand.Reader) s.Require().NoError(err) _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) - s.Require().Equal(ErrMalformedPushNotificationOptionsDeviceToken, err) + s.Require().Equal(ErrMalformedPushNotificationRegistrationDeviceToken, err) + + // Successful + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + Token: "abc", + AccessToken: accessToken, + InstallationId: installationID, + Version: 1, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + _, err = server.ValidateRegistration(&key.PublicKey, cyphertext) + s.Require().NoError(err) +} + +func (s *ServerSuite) TestPushNotificationHandleRegistration() { + accessToken := "b6ae4fde-bb65-11ea-b3de-0242ac130004" + installationID := "c6ae4fde-bb65-11ea-b3de-0242ac130004" + identity, err := crypto.GenerateKey() + s.Require().NoError(err) + + config := &Config{ + Identity: identity, + } + + server := New(config, s.persistence) + + key, err := crypto.GenerateKey() + s.Require().NoError(err) + + sharedKey, err := server.generateSharedKey(&key.PublicKey) + s.Require().NoError(err) + + // Empty payload + response := server.HandlePushNotificationRegistration(&key.PublicKey, nil) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Empty key + response = server.HandlePushNotificationRegistration(nil, []byte("payload")) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Invalid cyphertext length + response = server.HandlePushNotificationRegistration(&key.PublicKey, []byte("too short")) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Invalid cyphertext length + response = server.HandlePushNotificationRegistration(&key.PublicKey, []byte("too short")) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Invalid ciphertext + response = server.HandlePushNotificationRegistration(&key.PublicKey, []byte("not too short but invalid")) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Different key ciphertext + cyphertext, err := encrypt([]byte("plaintext"), make([]byte, 32), rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Right cyphertext but non unmarshable payload + cyphertext, err = encrypt([]byte("plaintext"), sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Missing installationID + payload, err := proto.Marshal(&protobuf.PushNotificationRegistration{ + AccessToken: accessToken, + Version: 1, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Malformed installationID + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + AccessToken: accessToken, + InstallationId: "abc", + Version: 1, + }) + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Version set to 0 + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + AccessToken: accessToken, + InstallationId: installationID, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_VERSION_MISMATCH) + + // Version lower than previous one + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + AccessToken: accessToken, + InstallationId: installationID, + Version: 1, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + + // Setup persistence + s.Require().NoError(s.persistence.SavePushNotificationRegistration(&key.PublicKey, &protobuf.PushNotificationRegistration{ + AccessToken: accessToken, + InstallationId: installationID, + Version: 2})) + + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_VERSION_MISMATCH) + + // Cleanup persistence + s.Require().NoError(s.persistence.DeletePushNotificationRegistration(&key.PublicKey, installationID)) + + // Missing access token + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + InstallationId: installationID, + Version: 1, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Invalid access token + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + AccessToken: "bc", + InstallationId: installationID, + Version: 1, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Missing device token + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + AccessToken: accessToken, + InstallationId: installationID, + Version: 1, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().False(response.Success) + s.Require().Equal(response.Error, protobuf.PushNotificationRegistrationResponse_MALFORMED_MESSAGE) + + // Successful + registration := &protobuf.PushNotificationRegistration{ + Token: "abc", + AccessToken: accessToken, + InstallationId: installationID, + Version: 1, + } + payload, err = proto.Marshal(registration) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().True(response.Success) + + // Pull from the db + retrievedRegistration, err := s.persistence.GetPushNotificationRegistration(&key.PublicKey, installationID) + s.Require().NoError(err) + s.Require().NotNil(retrievedRegistration) + s.Require().True(proto.Equal(retrievedRegistration, registration)) + + // Unregistering message + payload, err = proto.Marshal(&protobuf.PushNotificationRegistration{ + Token: "token", + InstallationId: installationID, + Unregister: true, + Version: 2, + }) + s.Require().NoError(err) + + cyphertext, err = encrypt(payload, sharedKey, rand.Reader) + s.Require().NoError(err) + response = server.HandlePushNotificationRegistration(&key.PublicKey, cyphertext) + s.Require().NotNil(response) + s.Require().True(response.Success) + + // Check is gone from the db + retrievedRegistration, err = s.persistence.GetPushNotificationRegistration(&key.PublicKey, installationID) + s.Require().NoError(err) + s.Require().NotNil(retrievedRegistration) + s.Require().Empty(retrievedRegistration.AccessToken) + s.Require().Empty(retrievedRegistration.Token) + s.Require().Equal(uint64(2), retrievedRegistration.Version) + s.Require().Equal(installationID, retrievedRegistration.InstallationId) + s.Require().Equal(shake256(cyphertext), response.RequestId) }