Add protocol version to bundle

This commit is contained in:
Andrea Maria Piana 2019-05-23 09:54:28 +02:00
parent cef7f367ab
commit 78ed35d2fe
14 changed files with 305 additions and 136 deletions

View File

@ -10,6 +10,7 @@
// 1541164797_add_installations.up.sql
// 1558084410_add_topic.down.sql
// 1558084410_add_topic.up.sql
// 1558588866_add_version.up.sql
// static.go
// DO NOT EDIT!
@ -278,6 +279,26 @@ func _1558084410_add_topicUpSql() (*asset, error) {
return a, nil
}
var __1558588866_add_versionUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\xc8\xcc\x2b\x2e\x49\xcc\xc9\x49\x2c\xc9\xcc\xcf\x2b\x56\x70\x74\x71\x51\x28\x4b\x2d\x2a\xce\xcc\xcf\x53\xf0\xf4\x0b\x71\x75\x77\x0d\x52\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\xb0\xe6\x02\x04\x00\x00\xff\xff\x14\x7b\x07\xb5\x39\x00\x00\x00")
func _1558588866_add_versionUpSqlBytes() ([]byte, error) {
return bindataRead(
__1558588866_add_versionUpSql,
"1558588866_add_version.up.sql",
)
}
func _1558588866_add_versionUpSql() (*asset, error) {
bytes, err := _1558588866_add_versionUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(420), modTime: time.Unix(1558588995, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _staticGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\xcc\x41\x6a\x03\x31\x0c\x46\xe1\xbd\x4f\xf1\x2f\x5b\xe8\x58\xfb\x9e\xa0\x94\x16\x0a\xcd\x05\x64\x8f\x90\xc5\x30\xf6\x60\x29\x21\xc7\xcf\x26\x21\x64\xf9\xe0\xf1\x11\xe1\x8f\xeb\xc6\x2a\xf0\xe0\xb0\x0a\xd9\x8b\xac\xfe\xa8\xb7\xef\xff\x0f\x7c\x9d\x7e\x7f\xde\x31\xc5\xc7\x79\x56\x71\x4c\xd3\x16\xb0\x1e\x03\xd1\x04\xc5\x3a\x4f\x13\x4f\xc7\x8b\x94\x12\x91\x8e\x4f\x95\x2e\x93\x43\xa0\x63\x29\xd6\x57\x0e\xc6\x72\x6c\x8a\xdd\x74\x72\xd8\xe8\x8e\x65\x20\x67\xca\x99\x5c\xe6\xc5\xaa\x38\x79\x6b\x72\x0d\xaa\x8d\x83\xd6\x42\xcf\x97\xee\x46\xd6\x81\x9c\x6e\x01\x00\x00\xff\xff\x6c\x21\xbf\x7a\xbf\x00\x00\x00")
func staticGoBytes() ([]byte, error) {
@ -360,6 +381,7 @@ var _bindata = map[string]func() (*asset, error){
"1541164797_add_installations.up.sql": _1541164797_add_installationsUpSql,
"1558084410_add_topic.down.sql": _1558084410_add_topicDownSql,
"1558084410_add_topic.up.sql": _1558084410_add_topicUpSql,
"1558588866_add_version.up.sql": _1558588866_add_versionUpSql,
"static.go": staticGo,
}
@ -413,6 +435,7 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1541164797_add_installations.up.sql": &bintree{_1541164797_add_installationsUpSql, map[string]*bintree{}},
"1558084410_add_topic.down.sql": &bintree{_1558084410_add_topicDownSql, map[string]*bintree{}},
"1558084410_add_topic.up.sql": &bintree{_1558084410_add_topicUpSql, map[string]*bintree{}},
"1558588866_add_version.up.sql": &bintree{_1558588866_add_versionUpSql, map[string]*bintree{}},
"static.go": &bintree{staticGo, map[string]*bintree{}},
}}

View File

@ -135,14 +135,17 @@ func (s *EncryptionService) ConfirmMessagesProcessed(messageIDs [][]byte) error
func (s *EncryptionService) CreateBundle(privateKey *ecdsa.PrivateKey) (*Bundle, error) {
ourIdentityKeyC := ecrypto.CompressPubkey(&privateKey.PublicKey)
installationIDs, err := s.persistence.GetActiveInstallations(s.config.MaxInstallations-1, ourIdentityKeyC)
installations, err := s.persistence.GetActiveInstallations(s.config.MaxInstallations-1, ourIdentityKeyC)
if err != nil {
return nil, err
}
installationIDs = append(installationIDs, s.config.InstallationID)
installations = append(installations, &Installation{
ID: s.config.InstallationID,
Version: protocolCurrentVersion,
})
bundleContainer, err := s.persistence.GetAnyPrivateBundle(ourIdentityKeyC, installationIDs)
bundleContainer, err := s.persistence.GetAnyPrivateBundle(ourIdentityKeyC, installations)
if err != nil {
return nil, err
}
@ -240,21 +243,24 @@ func (s *EncryptionService) ProcessPublicBundle(myIdentityKey *ecdsa.PrivateKey,
}
signedPreKeys := b.GetSignedPreKeys()
var response []IdentityAndIDPair
var installationIDs []string
var installations []*Installation
myIdentityStr := fmt.Sprintf("0x%x", ecrypto.FromECDSAPub(&myIdentityKey.PublicKey))
// Any device from other peers will be considered enabled, ours needs to
// be explicitly enabled
fromOurIdentity := identity != myIdentityStr
for installationID := range signedPreKeys {
for installationID, signedPreKey := range signedPreKeys {
if installationID != s.config.InstallationID {
installationIDs = append(installationIDs, installationID)
installations = append(installations, &Installation{
ID: installationID,
Version: signedPreKey.GetProtocolVersion(),
})
response = append(response, IdentityAndIDPair{identity, installationID})
}
}
if err = s.persistence.AddInstallations(b.GetIdentity(), b.GetTimestamp(), installationIDs, fromOurIdentity); err != nil {
if err = s.persistence.AddInstallations(b.GetIdentity(), b.GetTimestamp(), installations, fromOurIdentity); err != nil {
return nil, err
}
@ -323,7 +329,7 @@ func (s *EncryptionService) DecryptPayload(myIdentityKey *ecdsa.PrivateKey, thei
}
// Add installations with a timestamp of 0, as we don't have bundle informations
if err = s.persistence.AddInstallations(theirIdentityKeyC, 0, []string{theirInstallationID}, true); err != nil {
if err = s.persistence.AddInstallations(theirIdentityKeyC, 0, []*Installation{{ID: theirInstallationID, Version: 0}}, true); err != nil {
return nil, err
}
@ -502,12 +508,12 @@ func (s *EncryptionService) EncryptPayloadWithDH(theirIdentityKey *ecdsa.PublicK
func (s *EncryptionService) GetPublicBundle(theirIdentityKey *ecdsa.PublicKey) (*Bundle, error) {
theirIdentityKeyC := ecrypto.CompressPubkey(theirIdentityKey)
installationIDs, err := s.persistence.GetActiveInstallations(s.config.MaxInstallations, theirIdentityKeyC)
installations, err := s.persistence.GetActiveInstallations(s.config.MaxInstallations, theirIdentityKeyC)
if err != nil {
return nil, err
}
return s.persistence.GetPublicBundle(theirIdentityKey, installationIDs)
return s.persistence.GetPublicBundle(theirIdentityKey, installations)
}
// EncryptPayload returns a new DirectMessageProtocol with a given payload encrypted, given a recipient's public key and the sender private identity key
@ -522,24 +528,25 @@ func (s *EncryptionService) EncryptPayload(theirIdentityKey *ecdsa.PublicKey, my
theirIdentityKeyC := ecrypto.CompressPubkey(theirIdentityKey)
// Get their installationIds
installationIds, err := s.persistence.GetActiveInstallations(s.config.MaxInstallations, theirIdentityKeyC)
installations, err := s.persistence.GetActiveInstallations(s.config.MaxInstallations, theirIdentityKeyC)
if err != nil {
return nil, err
}
// We don't have any, send a message with DH
if installationIds == nil && !bytes.Equal(theirIdentityKeyC, ecrypto.CompressPubkey(&myIdentityKey.PublicKey)) {
if installations == nil && !bytes.Equal(theirIdentityKeyC, ecrypto.CompressPubkey(&myIdentityKey.PublicKey)) {
return s.EncryptPayloadWithDH(theirIdentityKey, payload)
}
response := make(map[string]*DirectMessageProtocol)
for _, installationID := range installationIds {
for _, installation := range installations {
installationID := installation.ID
s.log.Debug("Processing installation", "installationID", installationID)
if s.config.InstallationID == installationID {
continue
}
bundle, err := s.persistence.GetPublicBundle(theirIdentityKey, []string{installationID})
bundle, err := s.persistence.GetPublicBundle(theirIdentityKey, []*Installation{installation})
if err != nil {
return nil, err
}

View File

@ -23,6 +23,7 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type SignedPreKey struct {
SignedPreKey []byte `protobuf:"bytes,1,opt,name=signed_pre_key,json=signedPreKey,proto3" json:"signed_pre_key,omitempty"`
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
ProtocolVersion uint32 `protobuf:"varint,3,opt,name=protocol_version,json=protocolVersion,proto3" json:"protocol_version,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -67,6 +68,13 @@ func (m *SignedPreKey) GetVersion() uint32 {
return 0
}
func (m *SignedPreKey) GetProtocolVersion() uint32 {
if m != nil {
return m.ProtocolVersion
}
return 0
}
// X3DH prekey bundle
type Bundle struct {
// Identity key
@ -416,9 +424,7 @@ type ProtocolMessage struct {
// One to one message, encrypted, indexed by installation_id
DirectMessage map[string]*DirectMessageProtocol `protobuf:"bytes,101,rep,name=direct_message,json=directMessage,proto3" json:"direct_message,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// Public chats, not encrypted
PublicMessage []byte `protobuf:"bytes,102,opt,name=public_message,json=publicMessage,proto3" json:"public_message,omitempty"`
// Version of the protocol
Version uint32 `protobuf:"varint,103,opt,name=version,proto3" json:"version,omitempty"`
PublicMessage []byte `protobuf:"bytes,102,opt,name=public_message,json=publicMessage,proto3" json:"public_message,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -484,13 +490,6 @@ func (m *ProtocolMessage) GetPublicMessage() []byte {
return nil
}
func (m *ProtocolMessage) GetVersion() uint32 {
if m != nil {
return m.Version
}
return 0
}
func init() {
proto.RegisterType((*SignedPreKey)(nil), "chat.SignedPreKey")
proto.RegisterType((*Bundle)(nil), "chat.Bundle")
@ -507,40 +506,41 @@ func init() {
func init() { proto.RegisterFile("encryption.proto", fileDescriptor_8293a649ce9418c6) }
var fileDescriptor_8293a649ce9418c6 = []byte{
// 553 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x5d, 0x8b, 0xd3, 0x40,
0x14, 0x25, 0x49, 0x77, 0xb7, 0xbd, 0x4d, 0xd3, 0x32, 0xa2, 0x84, 0xba, 0x60, 0x09, 0xab, 0x06,
0x84, 0xc2, 0xb6, 0x3e, 0x88, 0x8f, 0x5a, 0xb1, 0xae, 0xa8, 0xcb, 0xe8, 0x83, 0x2f, 0x12, 0xa6,
0xcd, 0xd8, 0x1d, 0x4c, 0x27, 0x61, 0x32, 0x2d, 0xf4, 0xcf, 0xf9, 0xbf, 0x7c, 0x52, 0x32, 0x93,
0x69, 0x27, 0xdd, 0x5d, 0xf0, 0xad, 0xf7, 0x63, 0xce, 0x3d, 0xf7, 0xdc, 0x9c, 0xc2, 0x80, 0xf2,
0xa5, 0xd8, 0x15, 0x92, 0xe5, 0x7c, 0x5c, 0x88, 0x5c, 0xe6, 0xa8, 0xb5, 0xbc, 0x21, 0x32, 0xfa,
0x0c, 0xfe, 0x57, 0xb6, 0xe2, 0x34, 0xbd, 0x16, 0xf4, 0x23, 0xdd, 0xa1, 0x0b, 0x08, 0x4a, 0x15,
0x27, 0x85, 0xa0, 0xc9, 0x2f, 0xba, 0x0b, 0x9d, 0x91, 0x13, 0xfb, 0xd8, 0x2f, 0xed, 0xae, 0x10,
0xce, 0xb6, 0x54, 0x94, 0x2c, 0xe7, 0xa1, 0x3b, 0x72, 0xe2, 0x1e, 0x36, 0x61, 0xf4, 0xd7, 0x81,
0xd3, 0x37, 0x1b, 0x9e, 0x66, 0x14, 0x0d, 0xa1, 0xcd, 0x52, 0xca, 0x25, 0x93, 0x06, 0x64, 0x1f,
0xa3, 0xf7, 0xd0, 0x6f, 0x8e, 0x29, 0x43, 0x77, 0xe4, 0xc5, 0xdd, 0xc9, 0x93, 0x71, 0x45, 0x6b,
0xac, 0x21, 0xc6, 0x36, 0xb5, 0xf2, 0x1d, 0x97, 0x62, 0x87, 0x7b, 0x36, 0x91, 0x12, 0x9d, 0x43,
0xa7, 0x4a, 0x10, 0xb9, 0x11, 0x34, 0x6c, 0xa9, 0x29, 0x87, 0x44, 0x55, 0x95, 0x6c, 0x4d, 0x4b,
0x49, 0xd6, 0x45, 0x78, 0x32, 0x72, 0x62, 0x0f, 0x1f, 0x12, 0xc3, 0x6f, 0x80, 0x6e, 0x0f, 0x40,
0x03, 0xf0, 0xcc, 0xda, 0x1d, 0x5c, 0xfd, 0x44, 0x31, 0x9c, 0x6c, 0x49, 0xb6, 0xa1, 0x6a, 0xd7,
0xee, 0x04, 0x69, 0x8a, 0xf6, 0x53, 0xac, 0x1b, 0x5e, 0xbb, 0xaf, 0x9c, 0x48, 0x40, 0x5f, 0xb3,
0x7f, 0x9b, 0x73, 0x49, 0x18, 0xa7, 0x02, 0x5d, 0xc0, 0xe9, 0x42, 0xa5, 0x14, 0x6a, 0x77, 0xe2,
0xdb, 0x4b, 0xe2, 0xba, 0x86, 0xa6, 0xf0, 0xa8, 0x10, 0x6c, 0x4b, 0x24, 0x4d, 0x8e, 0x4e, 0xe0,
0xaa, 0xbd, 0x1e, 0xd4, 0x55, 0x7b, 0xf0, 0x55, 0xab, 0xed, 0x0d, 0x5a, 0xd1, 0x15, 0xb4, 0x67,
0x78, 0x4e, 0x49, 0x4a, 0x85, 0xcd, 0xdf, 0xd7, 0xfc, 0x7d, 0x70, 0xcc, 0x9d, 0x1c, 0x8e, 0x02,
0x70, 0x0b, 0x1e, 0x7a, 0x2a, 0x74, 0x0b, 0x15, 0xb3, 0xb4, 0x96, 0xce, 0x65, 0x69, 0x74, 0x0e,
0xed, 0xd9, 0xfc, 0x3e, 0xac, 0xe8, 0x25, 0xc0, 0xf7, 0xe9, 0xfd, 0xf5, 0x63, 0xb4, 0x9a, 0xdf,
0x6f, 0x07, 0x1e, 0xce, 0x98, 0xa0, 0x4b, 0xf9, 0x89, 0x96, 0x25, 0x59, 0xd1, 0xeb, 0xea, 0x13,
0x5c, 0xe6, 0x19, 0xba, 0x84, 0x6e, 0x85, 0x97, 0xdc, 0x28, 0xc0, 0x5a, 0x9f, 0x81, 0xd6, 0xe7,
0x30, 0x08, 0xdb, 0x43, 0x5f, 0x40, 0x67, 0x86, 0xcd, 0x03, 0x7d, 0x92, 0x40, 0x3f, 0x30, 0x1a,
0xe0, 0x83, 0x1a, 0x55, 0xf3, 0x1e, 0x9d, 0x36, 0x9a, 0xe7, 0xfb, 0x66, 0x83, 0x1c, 0xc2, 0x59,
0x41, 0x76, 0x59, 0x4e, 0x52, 0xa5, 0x8f, 0x8f, 0x4d, 0x18, 0xfd, 0x71, 0xa1, 0x6f, 0x38, 0xd7,
0x2b, 0xfc, 0xe7, 0x55, 0x9f, 0x43, 0x9f, 0xf1, 0x52, 0x92, 0x2c, 0x23, 0x95, 0xf9, 0x12, 0x96,
0x2a, 0xce, 0x1d, 0x1c, 0xd8, 0xe9, 0x0f, 0x29, 0x7a, 0x06, 0x67, 0xfa, 0x49, 0x19, 0x7a, 0xca,
0x0a, 0x4d, 0x3c, 0x53, 0x44, 0x5f, 0x20, 0x48, 0x95, 0x94, 0xc9, 0x5a, 0x13, 0x09, 0xa9, 0x6a,
0x8f, 0x75, 0xfb, 0x11, 0xcb, 0x71, 0x43, 0xf6, 0xda, 0x42, 0xa9, 0x9d, 0x43, 0x4f, 0x21, 0x28,
0x36, 0x8b, 0x8c, 0x2d, 0xf7, 0x80, 0x3f, 0xd5, 0xf2, 0x3d, 0x9d, 0x35, 0x6d, 0x96, 0xe7, 0x57,
0x0d, 0xcf, 0x0f, 0x7f, 0x00, 0xba, 0x3d, 0xe5, 0x0e, 0x1f, 0x5d, 0x36, 0x7d, 0xf4, 0xb8, 0xbe,
0xc3, 0x5d, 0xdf, 0x85, 0x65, 0xa8, 0xc5, 0xa9, 0xfa, 0xbf, 0x9a, 0xfe, 0x0b, 0x00, 0x00, 0xff,
0xff, 0x53, 0xcb, 0xc9, 0xb7, 0xc3, 0x04, 0x00, 0x00,
// 562 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x61, 0x8b, 0xd3, 0x4c,
0x10, 0x26, 0x49, 0xef, 0xda, 0x4e, 0xd3, 0xb4, 0xec, 0xcb, 0x2b, 0xa1, 0x1e, 0x58, 0xc2, 0xa9,
0x11, 0xa1, 0x70, 0xad, 0x1f, 0xc4, 0x8f, 0x5a, 0xb1, 0x9e, 0x88, 0xc7, 0x2a, 0xe2, 0x17, 0x09,
0xdb, 0x66, 0xbd, 0x5b, 0x4c, 0x93, 0xb0, 0xbb, 0x2d, 0xe4, 0xcf, 0xf9, 0x57, 0xfc, 0x29, 0x4a,
0x76, 0xb3, 0xed, 0xb6, 0x77, 0x07, 0x7e, 0xeb, 0xcc, 0x3c, 0xfb, 0xcc, 0x33, 0xcf, 0x74, 0x02,
0x43, 0x9a, 0xaf, 0x78, 0x55, 0x4a, 0x56, 0xe4, 0x93, 0x92, 0x17, 0xb2, 0x40, 0xad, 0xd5, 0x0d,
0x91, 0x51, 0x05, 0xfe, 0x67, 0x76, 0x9d, 0xd3, 0xf4, 0x8a, 0xd3, 0x0f, 0xb4, 0x42, 0xe7, 0x10,
0x08, 0x15, 0x27, 0x25, 0xa7, 0xc9, 0x4f, 0x5a, 0x85, 0xce, 0xd8, 0x89, 0x7d, 0xec, 0x0b, 0x1b,
0x15, 0x42, 0x7b, 0x4b, 0xb9, 0x60, 0x45, 0x1e, 0xba, 0x63, 0x27, 0xee, 0x63, 0x13, 0xa2, 0x67,
0x30, 0x54, 0xf4, 0xab, 0x22, 0x4b, 0x0c, 0xc4, 0x53, 0x90, 0x81, 0xc9, 0x7f, 0xd5, 0xe9, 0xe8,
0x8f, 0x03, 0xa7, 0xaf, 0x37, 0x79, 0x9a, 0x51, 0x34, 0x82, 0x0e, 0x4b, 0x69, 0x2e, 0x99, 0x34,
0xfd, 0x76, 0x31, 0x7a, 0x07, 0x83, 0x43, 0x45, 0x22, 0x74, 0xc7, 0x5e, 0xdc, 0x9b, 0x3e, 0x9a,
0xd4, 0x13, 0x4c, 0x34, 0xc5, 0xc4, 0x9e, 0x42, 0xbc, 0xcd, 0x25, 0xaf, 0x70, 0xdf, 0xd6, 0x2c,
0xd0, 0x19, 0x74, 0xeb, 0x04, 0x91, 0x1b, 0x4e, 0xc3, 0x96, 0xea, 0xb2, 0x4f, 0xd4, 0x55, 0xc9,
0xd6, 0x54, 0x48, 0xb2, 0x2e, 0xc3, 0x93, 0xb1, 0x13, 0x7b, 0x78, 0x9f, 0x18, 0x7d, 0x01, 0x74,
0xbb, 0x01, 0x1a, 0x82, 0x67, 0x1c, 0xea, 0xe2, 0xfa, 0x27, 0x8a, 0xe1, 0x64, 0x4b, 0xb2, 0x0d,
0x55, 0xb6, 0xf4, 0xa6, 0x48, 0x4b, 0xb4, 0x9f, 0x62, 0x0d, 0x78, 0xe5, 0xbe, 0x74, 0x22, 0x0e,
0x03, 0xad, 0xfe, 0x4d, 0x91, 0x4b, 0xc2, 0x72, 0xca, 0xd1, 0x39, 0x9c, 0x2e, 0x55, 0x4a, 0xb1,
0xf6, 0xa6, 0xbe, 0x3d, 0x24, 0x6e, 0x6a, 0x68, 0x06, 0x0f, 0x4a, 0xce, 0xb6, 0x44, 0xd2, 0xe4,
0x68, 0x5b, 0xae, 0x9a, 0xeb, 0xbf, 0xa6, 0x6a, 0x37, 0xbe, 0x6c, 0x75, 0xbc, 0x61, 0x2b, 0xba,
0x84, 0xce, 0x1c, 0x2f, 0x28, 0x49, 0x29, 0xb7, 0xf5, 0xfb, 0x5a, 0xbf, 0x0f, 0x8e, 0x59, 0xa9,
0x93, 0xa3, 0x00, 0xdc, 0xd2, 0xac, 0xcf, 0x2d, 0x55, 0xcc, 0xd2, 0xc6, 0x3a, 0x97, 0xa5, 0xd1,
0x19, 0x74, 0xe6, 0x8b, 0xfb, 0xb8, 0xa2, 0x17, 0x00, 0xdf, 0x66, 0xf7, 0xd7, 0x8f, 0xd9, 0x1a,
0x7d, 0xbf, 0x1c, 0xf8, 0x7f, 0xce, 0x38, 0x5d, 0xc9, 0x8f, 0x54, 0x08, 0x72, 0x4d, 0xaf, 0x9a,
0xbf, 0x0d, 0xba, 0x80, 0x5e, 0xcd, 0x97, 0xdc, 0x28, 0xc2, 0xc6, 0x9f, 0xa1, 0xf6, 0x67, 0xdf,
0x08, 0xdb, 0x4d, 0x9f, 0x43, 0x77, 0x8e, 0xcd, 0x03, 0xbd, 0x92, 0x40, 0x3f, 0x30, 0x1e, 0xe0,
0xbd, 0x1b, 0x35, 0x78, 0xc7, 0x4e, 0x0f, 0xc0, 0x8b, 0x1d, 0xd8, 0x30, 0x87, 0xd0, 0x2e, 0x49,
0x95, 0x15, 0x24, 0x55, 0xfe, 0xf8, 0xd8, 0x84, 0xd1, 0x6f, 0x17, 0x06, 0x46, 0x73, 0x33, 0xc2,
0x3f, 0x6e, 0xf5, 0x29, 0x0c, 0x58, 0x2e, 0x24, 0xc9, 0x32, 0x52, 0xdf, 0x69, 0xc2, 0x52, 0xa5,
0xb9, 0x8b, 0x03, 0x3b, 0xfd, 0x3e, 0x45, 0x4f, 0xa0, 0xad, 0x9f, 0x88, 0xd0, 0x53, 0xa7, 0x70,
0xc8, 0x67, 0x8a, 0xe8, 0x13, 0x04, 0xa9, 0xb2, 0x32, 0x59, 0x6b, 0x21, 0x21, 0x55, 0xf0, 0x58,
0xc3, 0x8f, 0x54, 0x4e, 0x0e, 0x6c, 0x6f, 0x4e, 0x28, 0xb5, 0x73, 0xe8, 0x31, 0x04, 0xe5, 0x66,
0x99, 0xb1, 0xd5, 0x8e, 0xf0, 0x87, 0x1a, 0xbe, 0xaf, 0xb3, 0x0d, 0x6c, 0xf4, 0x1d, 0xd0, 0x6d,
0xae, 0x3b, 0xae, 0xe5, 0xe2, 0xf0, 0x5a, 0x1e, 0x36, 0x6e, 0xdf, 0xb5, 0x7d, 0xeb, 0x6c, 0x96,
0xa7, 0xea, 0x4b, 0x32, 0xfb, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x75, 0x6d, 0x59, 0xd4, 0x04,
0x00, 0x00,
}

View File

@ -5,6 +5,7 @@ package chat;
message SignedPreKey {
bytes signed_pre_key = 1;
uint32 version = 2;
uint32 protocol_version = 3;
}
// X3DH prekey bundle
@ -77,7 +78,4 @@ message ProtocolMessage {
// Public chats, not encrypted
bytes public_message = 102;
// Version of the protocol
uint32 version = 103;
}

View File

@ -6,6 +6,11 @@ import (
dr "github.com/status-im/doubleratchet"
)
type Installation struct {
ID string
Version uint32
}
// RatchetInfo holds the current ratchet state
type RatchetInfo struct {
ID []byte
@ -26,12 +31,12 @@ type PersistenceService interface {
GetSessionStorage() dr.SessionStorage
// GetPublicBundle retrieves an existing Bundle for the specified public key & installationIDs.
GetPublicBundle(*ecdsa.PublicKey, []string) (*Bundle, error)
GetPublicBundle(*ecdsa.PublicKey, []*Installation) (*Bundle, error)
// AddPublicBundle persists a specified Bundle
AddPublicBundle(*Bundle) error
// GetAnyPrivateBundle retrieves any bundle for our identity & installationIDs
GetAnyPrivateBundle([]byte, []string) (*BundleContainer, error)
GetAnyPrivateBundle([]byte, []*Installation) (*BundleContainer, error)
// GetPrivateKeyBundle retrieves a BundleContainer with the specified signed prekey.
GetPrivateKeyBundle([]byte) ([]byte, error)
// AddPrivateBundle persists a BundleContainer.
@ -50,9 +55,9 @@ type PersistenceService interface {
RatchetInfoConfirmed([]byte, []byte, string) error
// GetActiveInstallations returns the active installations for a given identity.
GetActiveInstallations(maxInstallations int, identity []byte) ([]string, error)
GetActiveInstallations(maxInstallations int, identity []byte) ([]*Installation, error)
// AddInstallations adds the installations for a given identity.
AddInstallations(identity []byte, timestamp int64, installationIDs []string, enabled bool) error
AddInstallations(identity []byte, timestamp int64, installations []*Installation, enabled bool) error
// EnableInstallation enables the installation.
EnableInstallation(identity []byte, installationID string) error
// DisableInstallation disable the installation.

View File

@ -58,7 +58,6 @@ func (p *ProtocolService) BuildPublicMessage(myIdentityKey *ecdsa.PrivateKey, pa
protocolMessage := &ProtocolMessage{
InstallationId: p.encryption.config.InstallationID,
PublicMessage: payload,
Version: protocolCurrentVersion,
}
return p.addBundle(myIdentityKey, protocolMessage, false)
@ -77,7 +76,6 @@ func (p *ProtocolService) BuildDirectMessage(myIdentityKey *ecdsa.PrivateKey, pu
protocolMessage := &ProtocolMessage{
InstallationId: p.encryption.config.InstallationID,
DirectMessage: encryptionResponse,
Version: protocolCurrentVersion,
}
msg, err := p.addBundle(myIdentityKey, protocolMessage, true)
@ -109,9 +107,8 @@ func (p *ProtocolService) BuildDirectMessage(myIdentityKey *ecdsa.PrivateKey, pu
if agreed {
return msg, sharedSecret.Key, nil
} else {
return msg, nil, nil
}
return msg, nil, nil
}
// BuildDHMessage builds a message with DH encryption so that it can be decrypted by any other device.
@ -127,7 +124,6 @@ func (p *ProtocolService) BuildDHMessage(myIdentityKey *ecdsa.PrivateKey, destin
protocolMessage := &ProtocolMessage{
InstallationId: p.encryption.config.InstallationID,
DirectMessage: encryptionResponse,
Version: protocolCurrentVersion,
}
msg, err := p.addBundle(myIdentityKey, protocolMessage, true)
@ -211,7 +207,8 @@ func (p *ProtocolService) HandleMessage(myIdentityKey *ecdsa.PrivateKey, theirPu
p.log.Info("Checking version")
// Handle protocol negotiation for compatible clients
if protocolMessage.Version >= topicNegotiationVersion {
version := getProtocolVersion(protocolMessage.GetBundles(), protocolMessage.GetInstallationId())
if version >= topicNegotiationVersion {
p.log.Info("Version greater than 1 negotianting")
sharedSecret, err := p.topic.Receive(myIdentityKey, theirPublicKey, protocolMessage.GetInstallationId())
if err != nil {
@ -227,3 +224,25 @@ func (p *ProtocolService) HandleMessage(myIdentityKey *ecdsa.PrivateKey, theirPu
// Return error
return nil, errors.New("no payload")
}
func getProtocolVersion(bundles []*Bundle, installationID string) uint32 {
if installationID == "" {
return 0
}
for _, bundle := range bundles {
signedPreKeys := bundle.GetSignedPreKeys()
if signedPreKeys == nil {
continue
}
signedPreKey := signedPreKeys[installationID]
if signedPreKey == nil {
return 0
}
return signedPreKey.GetProtocolVersion()
}
return 0
}

View File

@ -39,7 +39,7 @@ func (s *ProtocolServiceTestSuite) SetupTest() {
}
addedBundlesHandler := func(addedBundles []IdentityAndIDPair) {}
onNewTopicHandler := func(topic [][]byte) {}
onNewTopicHandler := func(topic []*topic.Secret) {}
s.alice = NewProtocolService(
NewEncryptionService(alicePersistence, DefaultEncryptionServiceConfig("1")),

View File

@ -203,12 +203,13 @@ func (s *SQLLitePersistence) AddPublicBundle(b *Bundle) error {
}
// GetAnyPrivateBundle retrieves any bundle from the database containing a private key
func (s *SQLLitePersistence) GetAnyPrivateBundle(myIdentityKey []byte, installationIDs []string) (*BundleContainer, error) {
func (s *SQLLitePersistence) GetAnyPrivateBundle(myIdentityKey []byte, installations []*Installation) (*BundleContainer, error) {
versions := make(map[string]uint32)
/* #nosec */
statement := `SELECT identity, private_key, signed_pre_key, installation_id, timestamp, version
FROM bundles
WHERE expired = 0 AND identity = ? AND installation_id IN (?` + strings.Repeat(",?", len(installationIDs)-1) + ")"
WHERE expired = 0 AND identity = ? AND installation_id IN (?` + strings.Repeat(",?", len(installations)-1) + ")"
stmt, err := s.db.Prepare(statement)
if err != nil {
return nil, err
@ -220,10 +221,13 @@ func (s *SQLLitePersistence) GetAnyPrivateBundle(myIdentityKey []byte, installat
var privateKey []byte
var version uint32
args := make([]interface{}, len(installationIDs)+1)
args := make([]interface{}, len(installations)+1)
args[0] = myIdentityKey
for i, installationID := range installationIDs {
args[i+1] = installationID
for i, installation := range installations {
// Lookup up map for versions
versions[installation.ID] = installation.Version
args[i+1] = installation.ID
}
rows, err := stmt.Query(args...)
@ -263,7 +267,11 @@ func (s *SQLLitePersistence) GetAnyPrivateBundle(myIdentityKey []byte, installat
bundle.Timestamp = timestamp
}
bundle.SignedPreKeys[installationID] = &SignedPreKey{SignedPreKey: signedPreKey, Version: version}
bundle.SignedPreKeys[installationID] = &SignedPreKey{
SignedPreKey: signedPreKey,
Version: version,
ProtocolVersion: versions[installationID],
}
bundle.Identity = identity
}
@ -315,18 +323,19 @@ func (s *SQLLitePersistence) MarkBundleExpired(identity []byte) error {
}
// GetPublicBundle retrieves an existing Bundle for the specified public key from the database
func (s *SQLLitePersistence) GetPublicBundle(publicKey *ecdsa.PublicKey, installationIDs []string) (*Bundle, error) {
func (s *SQLLitePersistence) GetPublicBundle(publicKey *ecdsa.PublicKey, installations []*Installation) (*Bundle, error) {
if len(installationIDs) == 0 {
if len(installations) == 0 {
return nil, nil
}
versions := make(map[string]uint32)
identity := crypto.CompressPubkey(publicKey)
/* #nosec */
statement := `SELECT signed_pre_key,installation_id, version
FROM bundles
WHERE expired = 0 AND identity = ? AND installation_id IN (?` + strings.Repeat(",?", len(installationIDs)-1) + `)
WHERE expired = 0 AND identity = ? AND installation_id IN (?` + strings.Repeat(",?", len(installations)-1) + `)
ORDER BY version DESC`
stmt, err := s.db.Prepare(statement)
if err != nil {
@ -334,10 +343,12 @@ func (s *SQLLitePersistence) GetPublicBundle(publicKey *ecdsa.PublicKey, install
}
defer stmt.Close()
args := make([]interface{}, len(installationIDs)+1)
args := make([]interface{}, len(installations)+1)
args[0] = identity
for i, installationID := range installationIDs {
args[i+1] = installationID
for i, installation := range installations {
// Lookup up map for versions
versions[installation.ID] = installation.Version
args[i+1] = installation.ID
}
rows, err := stmt.Query(args...)
@ -369,8 +380,9 @@ func (s *SQLLitePersistence) GetPublicBundle(publicKey *ecdsa.PublicKey, install
}
bundle.SignedPreKeys[installationID] = &SignedPreKey{
SignedPreKey: signedPreKey,
Version: version,
SignedPreKey: signedPreKey,
Version: version,
ProtocolVersion: versions[installationID],
}
}
@ -743,8 +755,8 @@ func (s *SQLLiteSessionStorage) Load(id []byte) (*dr.State, error) {
}
// GetActiveInstallations returns the active installations for a given identity
func (s *SQLLitePersistence) GetActiveInstallations(maxInstallations int, identity []byte) ([]string, error) {
stmt, err := s.db.Prepare(`SELECT installation_id
func (s *SQLLitePersistence) GetActiveInstallations(maxInstallations int, identity []byte) ([]*Installation, error) {
stmt, err := s.db.Prepare(`SELECT installation_id, version
FROM installations
WHERE enabled = 1 AND identity = ?
ORDER BY timestamp DESC
@ -753,7 +765,7 @@ func (s *SQLLitePersistence) GetActiveInstallations(maxInstallations int, identi
return nil, err
}
var installations []string
var installations []*Installation
rows, err := stmt.Query(identity, maxInstallations)
if err != nil {
return nil, err
@ -761,13 +773,19 @@ func (s *SQLLitePersistence) GetActiveInstallations(maxInstallations int, identi
for rows.Next() {
var installationID string
var version uint32
err = rows.Scan(
&installationID,
&version,
)
if err != nil {
return nil, err
}
installations = append(installations, installationID)
installations = append(installations, &Installation{
ID: installationID,
Version: version,
})
}
return installations, nil
@ -775,14 +793,14 @@ func (s *SQLLitePersistence) GetActiveInstallations(maxInstallations int, identi
}
// AddInstallations adds the installations for a given identity, maintaining the enabled flag
func (s *SQLLitePersistence) AddInstallations(identity []byte, timestamp int64, installationIDs []string, defaultEnabled bool) error {
func (s *SQLLitePersistence) AddInstallations(identity []byte, timestamp int64, installations []*Installation, defaultEnabled bool) error {
tx, err := s.db.Begin()
if err != nil {
return nil
}
for _, installationID := range installationIDs {
stmt, err := tx.Prepare(`SELECT enabled
for _, installation := range installations {
stmt, err := tx.Prepare(`SELECT enabled, version
FROM installations
WHERE identity = ? AND installation_id = ?
LIMIT 1`)
@ -792,16 +810,24 @@ func (s *SQLLitePersistence) AddInstallations(identity []byte, timestamp int64,
defer stmt.Close()
var oldEnabled bool
// We don't override version once we saw one
var oldVersion uint32
latestVersion := installation.Version
err = stmt.QueryRow(identity, installationID).Scan(&oldEnabled)
err = stmt.QueryRow(identity, installation.ID).Scan(&oldEnabled, &oldVersion)
if err != nil && err != sql.ErrNoRows {
return err
}
// We update timestamp if present without changing enabled, only if this is a new bundle
// and we set the version to the latest we ever saw
if err != sql.ErrNoRows {
if oldVersion > installation.Version {
latestVersion = oldVersion
}
stmt, err = tx.Prepare(`UPDATE installations
SET timestamp = ?, enabled = ?
SET timestamp = ?, enabled = ?, version = ?
WHERE identity = ?
AND installation_id = ?
AND timestamp < ?`)
@ -812,8 +838,9 @@ func (s *SQLLitePersistence) AddInstallations(identity []byte, timestamp int64,
_, err = stmt.Exec(
timestamp,
oldEnabled,
latestVersion,
identity,
installationID,
installation.ID,
timestamp,
)
if err != nil {
@ -822,17 +849,18 @@ func (s *SQLLitePersistence) AddInstallations(identity []byte, timestamp int64,
defer stmt.Close()
} else {
stmt, err = tx.Prepare(`INSERT INTO installations(identity, installation_id, timestamp, enabled)
VALUES (?, ?, ?, ?)`)
stmt, err = tx.Prepare(`INSERT INTO installations(identity, installation_id, timestamp, enabled, version)
VALUES (?, ?, ?, ?, ?)`)
if err != nil {
return err
}
_, err = stmt.Exec(
identity,
installationID,
installation.ID,
timestamp,
defaultEnabled,
latestVersion,
)
if err != nil {
return err

View File

@ -53,7 +53,7 @@ func (s *SQLLitePersistenceTestSuite) TestPrivateBundle() {
s.Require().NoError(err, "Error was not returned even though bundle is not there")
s.Nil(actualKey)
anyPrivateBundle, err := s.service.GetAnyPrivateBundle([]byte("non-existing-id"), []string{installationID})
anyPrivateBundle, err := s.service.GetAnyPrivateBundle([]byte("non-existing-id"), []*Installation{{ID: installationID, Version: 1}})
s.Require().NoError(err)
s.Nil(anyPrivateBundle)
@ -70,7 +70,7 @@ func (s *SQLLitePersistenceTestSuite) TestPrivateBundle() {
s.Equal(bundle.GetPrivateSignedPreKey(), actualKey, "It returns the same key")
identity := crypto.CompressPubkey(&key.PublicKey)
anyPrivateBundle, err = s.service.GetAnyPrivateBundle(identity, []string{installationID})
anyPrivateBundle, err = s.service.GetAnyPrivateBundle(identity, []*Installation{{ID: installationID, Version: 1}})
s.Require().NoError(err)
s.NotNil(anyPrivateBundle)
s.Equal(bundle.GetBundle().GetSignedPreKeys()[installationID].SignedPreKey, anyPrivateBundle.GetBundle().GetSignedPreKeys()[installationID].SignedPreKey, "It returns the same bundle")
@ -80,7 +80,7 @@ func (s *SQLLitePersistenceTestSuite) TestPublicBundle() {
key, err := crypto.GenerateKey()
s.Require().NoError(err)
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err, "Error was not returned even though bundle is not there")
s.Nil(actualBundle)
@ -91,7 +91,7 @@ func (s *SQLLitePersistenceTestSuite) TestPublicBundle() {
err = s.service.AddPublicBundle(bundle)
s.Require().NoError(err)
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err)
s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity")
s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the right prekeys")
@ -101,7 +101,7 @@ func (s *SQLLitePersistenceTestSuite) TestUpdatedBundle() {
key, err := crypto.GenerateKey()
s.Require().NoError(err)
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err, "Error was not returned even though bundle is not there")
s.Nil(actualBundle)
@ -123,7 +123,7 @@ func (s *SQLLitePersistenceTestSuite) TestUpdatedBundle() {
err = s.service.AddPublicBundle(bundle)
s.Require().NoError(err)
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err)
s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity")
s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the right prekeys")
@ -133,7 +133,7 @@ func (s *SQLLitePersistenceTestSuite) TestOutOfOrderBundles() {
key, err := crypto.GenerateKey()
s.Require().NoError(err)
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err, "Error was not returned even though bundle is not there")
s.Nil(actualBundle)
@ -160,7 +160,7 @@ func (s *SQLLitePersistenceTestSuite) TestOutOfOrderBundles() {
err = s.service.AddPublicBundle(bundle1)
s.Require().NoError(err)
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err)
s.Equal(bundle2.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity")
s.Equal(bundle2.GetSignedPreKeys()["1"].GetVersion(), uint32(1))
@ -171,7 +171,7 @@ func (s *SQLLitePersistenceTestSuite) TestMultiplePublicBundle() {
key, err := crypto.GenerateKey()
s.Require().NoError(err)
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err, "Error was not returned even though bundle is not there")
s.Nil(actualBundle)
@ -197,7 +197,7 @@ func (s *SQLLitePersistenceTestSuite) TestMultiplePublicBundle() {
s.Require().NoError(err)
// Returns the most recent bundle
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err)
s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the identity")
@ -209,7 +209,7 @@ func (s *SQLLitePersistenceTestSuite) TestMultiDevicePublicBundle() {
key, err := crypto.GenerateKey()
s.Require().NoError(err)
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []string{"1"})
actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*Installation{{ID: "1", Version: 1}})
s.Require().NoError(err, "Error was not returned even though bundle is not there")
s.Nil(actualBundle)
@ -233,7 +233,11 @@ func (s *SQLLitePersistenceTestSuite) TestMultiDevicePublicBundle() {
s.Require().NoError(err)
// Returns the most recent bundle
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []string{"1", "2"})
actualBundle, err = s.service.GetPublicBundle(&key.PublicKey,
[]*Installation{
{ID: "1", Version: 1},
{ID: "2", Version: 1},
})
s.Require().NoError(err)
s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the identity")
@ -345,7 +349,10 @@ func (s *SQLLitePersistenceTestSuite) TestRatchetInfoNoBundle() {
func (s *SQLLitePersistenceTestSuite) TestAddInstallations() {
identity := []byte("alice")
installations := []string{"alice-1", "alice-2"}
installations := []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-2", Version: 2},
}
err := s.service.AddInstallations(
identity,
1,
@ -361,10 +368,50 @@ func (s *SQLLitePersistenceTestSuite) TestAddInstallations() {
s.Require().Equal(installations, enabledInstallations)
}
func (s *SQLLitePersistenceTestSuite) TestAddInstallationVersions() {
identity := []byte("alice")
installations := []*Installation{
{ID: "alice-1", Version: 1},
}
err := s.service.AddInstallations(
identity,
1,
installations,
true,
)
s.Require().NoError(err)
enabledInstallations, err := s.service.GetActiveInstallations(5, identity)
s.Require().NoError(err)
s.Require().Equal(installations, enabledInstallations)
installationsWithDowngradedVersion := []*Installation{
{ID: "alice-1", Version: 0},
}
err = s.service.AddInstallations(
identity,
3,
installationsWithDowngradedVersion,
true,
)
s.Require().NoError(err)
enabledInstallations, err = s.service.GetActiveInstallations(5, identity)
s.Require().NoError(err)
s.Require().Equal(installations, enabledInstallations)
}
func (s *SQLLitePersistenceTestSuite) TestAddInstallationsLimit() {
identity := []byte("alice")
installations := []string{"alice-1", "alice-2"}
installations := []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-2", Version: 2},
}
err := s.service.AddInstallations(
identity,
1,
@ -373,7 +420,11 @@ func (s *SQLLitePersistenceTestSuite) TestAddInstallationsLimit() {
)
s.Require().NoError(err)
installations = []string{"alice-2", "alice-3"}
installations = []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-3", Version: 3},
}
err = s.service.AddInstallations(
identity,
2,
@ -382,7 +433,12 @@ func (s *SQLLitePersistenceTestSuite) TestAddInstallationsLimit() {
)
s.Require().NoError(err)
installations = []string{"alice-2", "alice-3", "alice-4"}
installations = []*Installation{
{ID: "alice-2", Version: 2},
{ID: "alice-3", Version: 3},
{ID: "alice-4", Version: 4},
}
err = s.service.AddInstallations(
identity,
3,
@ -394,13 +450,17 @@ func (s *SQLLitePersistenceTestSuite) TestAddInstallationsLimit() {
enabledInstallations, err := s.service.GetActiveInstallations(3, identity)
s.Require().NoError(err)
s.Require().Equal([]string{"alice-2", "alice-3", "alice-4"}, enabledInstallations)
s.Require().Equal(installations, enabledInstallations)
}
func (s *SQLLitePersistenceTestSuite) TestAddInstallationsDisabled() {
identity := []byte("alice")
installations := []string{"alice-1", "alice-2"}
installations := []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-2", Version: 2},
}
err := s.service.AddInstallations(
identity,
1,
@ -418,7 +478,11 @@ func (s *SQLLitePersistenceTestSuite) TestAddInstallationsDisabled() {
func (s *SQLLitePersistenceTestSuite) TestDisableInstallation() {
identity := []byte("alice")
installations := []string{"alice-1", "alice-2"}
installations := []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-2", Version: 2},
}
err := s.service.AddInstallations(
identity,
1,
@ -431,7 +495,11 @@ func (s *SQLLitePersistenceTestSuite) TestDisableInstallation() {
s.Require().NoError(err)
// We add the installations again
installations = []string{"alice-1", "alice-2"}
installations = []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-2", Version: 2},
}
err = s.service.AddInstallations(
identity,
1,
@ -443,13 +511,18 @@ func (s *SQLLitePersistenceTestSuite) TestDisableInstallation() {
actualInstallations, err := s.service.GetActiveInstallations(3, identity)
s.Require().NoError(err)
s.Require().Equal([]string{"alice-2"}, actualInstallations)
expected := []*Installation{{ID: "alice-2", Version: 2}}
s.Require().Equal(expected, actualInstallations)
}
func (s *SQLLitePersistenceTestSuite) TestEnableInstallation() {
identity := []byte("alice")
installations := []string{"alice-1", "alice-2"}
installations := []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-2", Version: 2},
}
err := s.service.AddInstallations(
identity,
1,
@ -464,7 +537,8 @@ func (s *SQLLitePersistenceTestSuite) TestEnableInstallation() {
actualInstallations, err := s.service.GetActiveInstallations(3, identity)
s.Require().NoError(err)
s.Require().Equal([]string{"alice-2"}, actualInstallations)
expected := []*Installation{{ID: "alice-2", Version: 2}}
s.Require().Equal(expected, actualInstallations)
err = s.service.EnableInstallation(identity, "alice-1")
s.Require().NoError(err)
@ -472,7 +546,11 @@ func (s *SQLLitePersistenceTestSuite) TestEnableInstallation() {
actualInstallations, err = s.service.GetActiveInstallations(3, identity)
s.Require().NoError(err)
s.Require().Equal([]string{"alice-1", "alice-2"}, actualInstallations)
expected = []*Installation{
{ID: "alice-1", Version: 1},
{ID: "alice-2", Version: 2},
}
s.Require().Equal(expected, actualInstallations)
}

View File

@ -96,7 +96,10 @@ func NewBundleContainer(identity *ecdsa.PrivateKey, installationID string) (*Bun
encodedPreKey := crypto.FromECDSA(preKey)
signedPreKeys := make(map[string]*SignedPreKey)
signedPreKeys[installationID] = &SignedPreKey{SignedPreKey: compressedPreKey}
signedPreKeys[installationID] = &SignedPreKey{
ProtocolVersion: protocolCurrentVersion,
SignedPreKey: compressedPreKey,
}
bundle := Bundle{
Timestamp: time.Now().UnixNano(),

View File

@ -37,10 +37,10 @@ func chatIDToPartitionedTopic(identity string) (string, error) {
partition.Mod(publicKey.X, nPartitions)
return fmt.Sprintf("contact-discovery-%d", partition), nil
return fmt.Sprintf("contact-discovery-%d", partition.Int64()), nil
}
type FilterAndTopic struct {
type Filter struct {
FilterID string
Topic []byte
SymKeyID string
@ -143,7 +143,9 @@ func (s *Service) Init(chats []*Chat) error {
}
for _, secret := range secrets {
s.ProcessNegotiatedSecret(secret)
if err := s.ProcessNegotiatedSecret(secret); err != nil {
return err
}
}
return nil
@ -215,7 +217,7 @@ func (s *Service) LoadOneToOne(myKey *ecdsa.PrivateKey, identity string, listen
return nil
}
func (s *Service) AddSymmetric(chatID string) (*FilterAndTopic, error) {
func (s *Service) AddSymmetric(chatID string) (*Filter, error) {
var symKey []byte
topic := toTopic(chatID)
@ -244,14 +246,14 @@ func (s *Service) AddSymmetric(chatID string) (*FilterAndTopic, error) {
return nil, err
}
return &FilterAndTopic{
return &Filter{
FilterID: id,
SymKeyID: symKeyID,
Topic: topic,
}, nil
}
func (s *Service) AddAsymmetricFilter(keyAsym *ecdsa.PrivateKey, chatID string, listen bool) (*FilterAndTopic, error) {
func (s *Service) AddAsymmetricFilter(keyAsym *ecdsa.PrivateKey, chatID string, listen bool) (*Filter, error) {
var err error
var pow float64
@ -278,7 +280,7 @@ func (s *Service) AddAsymmetricFilter(keyAsym *ecdsa.PrivateKey, chatID string,
return nil, err
}
return &FilterAndTopic{FilterID: id, Topic: topic}, nil
return &Filter{FilterID: id, Topic: topic}, nil
}
func (s *Service) LoadPublic(chat *Chat) error {

View File

@ -101,10 +101,10 @@ func (s *ServiceTestSuite) TestDiscoveryAndPartitionedTopic() {
func (s *ServiceTestSuite) TestPublicAndOneToOneChats() {
chats := []*Chat{
&Chat{
{
ChatID: "status",
},
&Chat{
{
ChatID: s.keys[1].PublicKeyString(),
Identity: s.keys[1].PublicKeyString(),
OneToOne: true,

View File

@ -308,7 +308,12 @@ func (s *Service) Stop() error {
s.requestsRegistry.Clear()
s.envelopesMonitor.Stop()
s.mailMonitor.Stop()
s.filter.Stop()
if s.filter != nil {
if err := s.filter.Stop(); err != nil {
log.Error("Failed to stop filter service with error", "err", err)
}
}
return nil
}

View File

@ -0,0 +1 @@
ALTER TABLE installations ADD version INTEGER DEFAULT 0;