Improve interface around chats and add matching messages against chats (#66)

This commit is contained in:
Adam Babik 2019-09-20 08:41:53 +02:00 committed by GitHub
parent f51fd2e639
commit dbf4c4062e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 616 additions and 252 deletions

32
chat.go
View File

@ -93,3 +93,35 @@ func (c ChatMember) PublicKey() (*ecdsa.PublicKey, error) {
}
return crypto.UnmarshalPubkey(b)
}
func oneToOneChatID(publicKey *ecdsa.PublicKey) string {
return hexutil.Encode(crypto.FromECDSAPub(publicKey))
}
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey) Chat {
return Chat{
ID: oneToOneChatID(publicKey),
Name: name,
Active: true,
ChatType: ChatTypeOneToOne,
PublicKey: publicKey,
}
}
func CreatePublicChat(name string) Chat {
return Chat{
ID: name,
Name: name,
Active: true,
ChatType: ChatTypePublic,
}
}
func findChatByID(chatID string, chats []*Chat) *Chat {
for _, c := range chats {
if c.ID == chatID {
return c
}
}
return nil
}

View File

@ -100,7 +100,7 @@ func _1536754952_initial_schemaDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x44, 0xcf, 0x76, 0x71, 0x1f, 0x5e, 0x9a, 0x43, 0xd8, 0xcd, 0xb8, 0xc3, 0x70, 0xc3, 0x7f, 0xfc, 0x90, 0xb4, 0x25, 0x1e, 0xf4, 0x66, 0x20, 0xb8, 0x33, 0x7e, 0xb0, 0x76, 0x1f, 0xc, 0xc0, 0x75}}
return a, nil
}
@ -120,7 +120,7 @@ func _1536754952_initial_schemaUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x90, 0x5a, 0x59, 0x3e, 0x3, 0xe2, 0x3c, 0x81, 0x42, 0xcd, 0x4c, 0x9a, 0xe8, 0xda, 0x93, 0x2b, 0x70, 0xa4, 0xd5, 0x29, 0x3e, 0xd5, 0xc9, 0x27, 0xb6, 0xb7, 0x65, 0xff, 0x0, 0xcb, 0xde}}
return a, nil
}
@ -140,7 +140,7 @@ func _1539249977_update_ratchet_infoDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0xa4, 0xeb, 0xa0, 0xe6, 0xa0, 0xd4, 0x48, 0xbb, 0xad, 0x6f, 0x7d, 0x67, 0x8c, 0xbd, 0x25, 0xde, 0x1f, 0x73, 0x9a, 0xbb, 0xa8, 0xc9, 0x30, 0xb7, 0xa9, 0x7c, 0xaf, 0xb5, 0x1, 0x61, 0xdd}}
return a, nil
}
@ -160,7 +160,7 @@ func _1539249977_update_ratchet_infoUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x8e, 0xbf, 0x6f, 0xa, 0xc0, 0xe1, 0x3c, 0x42, 0x28, 0x88, 0x1d, 0xdb, 0xba, 0x1c, 0x83, 0xec, 0xba, 0xd3, 0x5f, 0x5c, 0x77, 0x5e, 0xa7, 0x46, 0x36, 0xec, 0x69, 0xa, 0x4b, 0x17, 0x79}}
return a, nil
}
@ -180,7 +180,7 @@ func _1540715431_add_versionDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x9, 0x4, 0xe3, 0x76, 0x2e, 0xb8, 0x9, 0x23, 0xf0, 0x70, 0x93, 0xc4, 0x50, 0xe, 0x9d, 0x84, 0x22, 0x8c, 0x94, 0xd3, 0x24, 0x9, 0x9a, 0xc1, 0xa1, 0x48, 0x45, 0xfd, 0x40, 0x6e, 0xe6}}
return a, nil
}
@ -200,7 +200,7 @@ func _1540715431_add_versionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc7, 0x4c, 0x36, 0x96, 0xdf, 0x16, 0x10, 0xa6, 0x27, 0x1a, 0x79, 0x8b, 0x42, 0x83, 0x23, 0xc, 0x7e, 0xb6, 0x3d, 0x2, 0xda, 0xa4, 0xb4, 0xd, 0x27, 0x55, 0xba, 0xdc, 0xb2, 0x88, 0x8f, 0xa6}}
return a, nil
}
@ -220,7 +220,7 @@ func _1541164797_add_installationsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0xfd, 0xe6, 0xd8, 0xca, 0x3b, 0x38, 0x18, 0xee, 0x0, 0x5f, 0x36, 0x9e, 0x1e, 0xd, 0x19, 0x3e, 0xb4, 0x73, 0x53, 0xe9, 0xa5, 0xac, 0xdd, 0xa1, 0x2f, 0xc7, 0x6c, 0xa8, 0xd9, 0xa, 0x88}}
return a, nil
}
@ -240,7 +240,7 @@ func _1541164797_add_installationsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2d, 0x18, 0x26, 0xb8, 0x88, 0x47, 0xdb, 0x83, 0xcc, 0xb6, 0x9d, 0x1c, 0x1, 0xae, 0x2f, 0xde, 0x97, 0x82, 0x3, 0x30, 0xa8, 0x63, 0xa1, 0x78, 0x4b, 0xa5, 0x9, 0x8, 0x75, 0xa2, 0x57, 0x81}}
return a, nil
}
@ -260,7 +260,7 @@ func _1558084410_add_secretDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x49, 0xb, 0x65, 0xdf, 0x59, 0xbf, 0xe9, 0x5, 0x5b, 0x6f, 0xd5, 0x3a, 0xb7, 0x57, 0xe8, 0x78, 0x38, 0x73, 0x53, 0x57, 0xf7, 0x24, 0x4, 0xe4, 0xa2, 0x49, 0x22, 0xa2, 0xc6, 0xfd, 0x80, 0xa4}}
return a, nil
}
@ -280,7 +280,7 @@ func _1558084410_add_secretUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x32, 0x36, 0x8e, 0x47, 0xb0, 0x8f, 0xc1, 0xc6, 0xf7, 0xc6, 0x9f, 0x2d, 0x44, 0x75, 0x2b, 0x26, 0xec, 0x6, 0xa0, 0x7b, 0xa5, 0xbd, 0xc8, 0x76, 0x8a, 0x82, 0x68, 0x2, 0x42, 0xb5, 0xf4}}
return a, nil
}
@ -300,7 +300,7 @@ func _1558588866_add_versionDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558588866_add_version.down.sql", size: 47, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1558588866_add_version.down.sql", size: 47, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x52, 0x34, 0x3c, 0x46, 0x4a, 0xf0, 0x72, 0x47, 0x6f, 0x49, 0x5c, 0xc7, 0xf9, 0x32, 0xce, 0xc4, 0x3d, 0xfd, 0x61, 0xa1, 0x8b, 0x8f, 0xf2, 0x31, 0x34, 0xde, 0x15, 0x49, 0xa6, 0xde, 0xb9}}
return a, nil
}
@ -320,7 +320,7 @@ func _1558588866_add_versionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2a, 0xea, 0x64, 0x39, 0x61, 0x20, 0x83, 0x83, 0xb, 0x2e, 0x79, 0x64, 0xb, 0x53, 0xfa, 0xfe, 0xc6, 0xf7, 0x67, 0x42, 0xd3, 0x4f, 0xdc, 0x7e, 0x30, 0x32, 0xe8, 0x14, 0x41, 0xe9, 0xe7, 0x3b}}
return a, nil
}
@ -340,7 +340,7 @@ func _1559627659_add_contact_codeDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5d, 0x64, 0x6d, 0xce, 0x24, 0x42, 0x20, 0x8d, 0x4f, 0x37, 0xaa, 0x9d, 0xc, 0x57, 0x98, 0xc1, 0xd1, 0x1a, 0x34, 0xcd, 0x9f, 0x8f, 0x34, 0x86, 0xb3, 0xd3, 0xdc, 0xf1, 0x7d, 0xe5, 0x1b, 0x6e}}
return a, nil
}
@ -360,7 +360,7 @@ func _1559627659_add_contact_codeUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x16, 0xf6, 0xc2, 0x62, 0x9c, 0xd2, 0xc9, 0x1e, 0xd8, 0xea, 0xaa, 0xea, 0x95, 0x8f, 0x89, 0x6a, 0x85, 0x5d, 0x9d, 0x99, 0x78, 0x3c, 0x90, 0x66, 0x99, 0x3e, 0x4b, 0x19, 0x62, 0xfb, 0x31, 0x4d}}
return a, nil
}
@ -380,7 +380,7 @@ func _1561368210_add_installation_metadataDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0xde, 0x3f, 0xd2, 0x4a, 0x50, 0x98, 0x56, 0xe3, 0xc0, 0xcd, 0x9d, 0xb0, 0x34, 0x3b, 0xe5, 0x62, 0x18, 0xb5, 0x20, 0xc9, 0x3e, 0xdc, 0x6a, 0x40, 0x36, 0x66, 0xea, 0x51, 0x8c, 0x71, 0xf5}}
return a, nil
}
@ -400,7 +400,7 @@ func _1561368210_add_installation_metadataUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb4, 0x71, 0x8f, 0x29, 0xb1, 0xaa, 0xd6, 0xd1, 0x8c, 0x17, 0xef, 0x6c, 0xd5, 0x80, 0xb8, 0x2c, 0xc3, 0xfe, 0xec, 0x24, 0x4d, 0xc8, 0x25, 0xd3, 0xb4, 0xcd, 0xa9, 0xac, 0x63, 0x61, 0xb2, 0x9c}}
return a, nil
}
@ -420,7 +420,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xef, 0xaf, 0xdf, 0xcf, 0x65, 0xae, 0x19, 0xfc, 0x9d, 0x29, 0xc1, 0x91, 0xaf, 0xb5, 0xd5, 0xb1, 0x56, 0xf3, 0xee, 0xa8, 0xba, 0x13, 0x65, 0xdb, 0xab, 0xcf, 0x4e, 0xac, 0x92, 0xe9, 0x60, 0xf1}}
return a, nil
}

1
go.mod
View File

@ -6,6 +6,7 @@ require (
github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7 // indirect
github.com/cenkalti/backoff/v3 v3.0.0
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/ethereum/go-ethereum v1.8.27
github.com/golang/protobuf v1.3.2
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8

28
go.sum
View File

@ -26,6 +26,9 @@ github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7/go.mod h1:
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI=
@ -65,6 +68,8 @@ github.com/docker/docker v0.7.3-0.20190108045446-77df18c24acf h1:2v/98rHzs3v6X0A
github.com/docker/docker v0.7.3-0.20190108045446-77df18c24acf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@ -81,6 +86,7 @@ github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7R
github.com/gizak/termui v0.0.0-20170117222342-991cd3d38091/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.5.4/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -111,8 +117,10 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
@ -140,6 +148,8 @@ github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH04
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8 h1:mGIXW/lubQ4B+3bXTLxcTMTjUNDqoF6T/HUW9LbFx9s=
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v0.0.0-20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@ -168,6 +178,10 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mongodb/mongo-go-driver v0.3.0/go.mod h1:NK/HWDIIZkaYsnYa0hmtP443T5ELr0KDecmIioVuuyU=
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f h1:hd3r+uv9DNLScbOrnlj82rBldHQf3XWmCeXAWbw8euQ=
@ -203,14 +217,25 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/prometheus v0.0.0-20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
@ -294,6 +319,7 @@ golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -318,6 +344,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA=
golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -9,17 +9,16 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
whisper "github.com/status-im/whisper/whisperv6"
"go.uber.org/zap"
"github.com/status-im/status-protocol-go/datasync"
datasyncpeer "github.com/status-im/status-protocol-go/datasync/peer"
"github.com/status-im/status-protocol-go/encryption"
"github.com/status-im/status-protocol-go/encryption/multidevice"
transport "github.com/status-im/status-protocol-go/transport/whisper"
protocol "github.com/status-im/status-protocol-go/v1"
whisper "github.com/status-im/whisper/whisperv6"
datasyncnode "github.com/vacp2p/mvds/node"
datasyncproto "github.com/vacp2p/mvds/protobuf"
"go.uber.org/zap"
)
// Whisper message properties.
@ -47,7 +46,6 @@ func newMessageProcessor(
logger *zap.Logger,
features featureFlags,
) (*messageProcessor, error) {
dataSyncTransport := datasync.NewDataSyncNodeTransport()
dataSyncNode, err := datasyncnode.NewPersistentNode(
database,
@ -94,8 +92,10 @@ func (p *messageProcessor) SendPrivate(
data []byte,
clock int64,
) ([]byte, *protocol.Message, error) {
logger := p.logger.With(zap.String("site", "SendPrivate"))
logger.Debug("sending a private message", zap.Binary("public-key", crypto.FromECDSAPub(publicKey)))
p.logger.Debug(
"sending a private message",
zap.Binary("public-key", crypto.FromECDSAPub(publicKey)),
)
message := protocol.CreatePrivateTextMessage(data, clock, chatID)
encodedMessage, err := p.encodeMessage(message)
@ -103,16 +103,14 @@ func (p *messageProcessor) SendPrivate(
return nil, nil, errors.Wrap(err, "failed to encode message")
}
messageID, err := p.SendPrivateRaw(ctx, publicKey, encodedMessage)
messageID, err := p.sendPrivate(ctx, publicKey, encodedMessage)
if err != nil {
return nil, nil, err
}
return messageID, &message, nil
}
// SendPrivateRaw takes encoded data, encrypts it and sends through the wire.
// DEPRECATED
func (p *messageProcessor) SendPrivateRaw(
ctx context.Context,
publicKey *ecdsa.PublicKey,
@ -123,7 +121,15 @@ func (p *messageProcessor) SendPrivateRaw(
zap.Binary("public-key", crypto.FromECDSAPub(publicKey)),
zap.String("site", "SendPrivateRaw"),
)
return p.sendPrivate(ctx, publicKey, data)
}
// sendPrivate sends data to the recipient identifying with a given public key.
func (p *messageProcessor) sendPrivate(
ctx context.Context,
publicKey *ecdsa.PublicKey,
data []byte,
) ([]byte, error) {
wrappedMessage, err := p.tryWrapMessageV1(data)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
@ -135,6 +141,9 @@ func (p *messageProcessor) SendPrivateRaw(
if err := p.addToDataSync(publicKey, wrappedMessage); err != nil {
return nil, errors.Wrap(err, "failed to send message with datasync")
}
// No need to call transport tracking.
// It is done in a data sync dispatch step.
} else {
messageSpec, err := p.protocol.BuildDirectMessage(p.identity, publicKey, wrappedMessage)
if err != nil {
@ -152,11 +161,11 @@ func (p *messageProcessor) SendPrivateRaw(
return messageID, nil
}
func (p *messageProcessor) SendPublic(ctx context.Context, chatName, chatID string, data []byte, clock int64) ([]byte, error) {
func (p *messageProcessor) SendPublic(ctx context.Context, chatID string, data []byte, clock int64) ([]byte, error) {
logger := p.logger.With(zap.String("site", "SendPublic"))
logger.Debug("sending a public message", zap.String("chat-name", chatName))
logger.Debug("sending a public message", zap.String("chatID", chatID))
message := protocol.CreatePublicTextMessage(data, clock, chatName)
message := protocol.CreatePublicTextMessage(data, clock, chatID)
encodedMessage, err := p.encodeMessage(message)
if err != nil {
@ -178,10 +187,11 @@ func (p *messageProcessor) SendPublic(ctx context.Context, chatName, chatID stri
return nil, err
}
hash, err := p.transport.SendPublic(ctx, &newMessage, chatName)
hash, err := p.transport.SendPublic(ctx, &newMessage, chatID)
if err != nil {
return nil, err
}
messageID := protocol.MessageID(&p.identity.PublicKey, wrappedMessage)
p.transport.Track([][]byte{messageID}, hash, newMessage)
@ -190,7 +200,6 @@ func (p *messageProcessor) SendPublic(ctx context.Context, chatName, chatID stri
}
// SendPublicRaw takes encoded data, encrypts it and sends through the wire.
// DEPRECATED
func (p *messageProcessor) SendPublicRaw(ctx context.Context, chatName string, data []byte) ([]byte, error) {
var newMessage whisper.NewMessage
@ -218,20 +227,22 @@ func (p *messageProcessor) SendPublicRaw(ctx context.Context, chatName string, d
return messageID, nil
}
func (p *messageProcessor) Process(messages []*whisper.ReceivedMessage) ([]*protocol.Message, error) {
logger := p.logger.With(zap.String("site", "handleRetrievedMessages"))
// Process processes received Whisper messages through all the layers
// and returns decoded user messages.
// It also handled all non-user messages like PairMessage.
func (p *messageProcessor) Process(message *whisper.ReceivedMessage) ([]*protocol.Message, error) {
logger := p.logger.With(zap.String("site", "Process"))
decodedMessages := make([]*protocol.Message, 0, len(messages))
for _, item := range messages {
shhMessage := whisper.ToWhisperMessage(item)
var decodedMessages []*protocol.Message
shhMessage := whisper.ToWhisperMessage(message)
hlogger := logger.With(zap.Binary("hash", shhMessage.Hash))
hlogger.Debug("handling a received message")
statusMessages, err := p.handleMessages(shhMessage, true)
if err != nil {
hlogger.Info("failed to decode messages", zap.Error(err))
continue
return nil, err
}
for _, statusMessage := range statusMessages {
@ -247,27 +258,31 @@ func (p *messageProcessor) Process(messages []*whisper.ReceivedMessage) ([]*prot
break
}
metadata := &multidevice.InstallationMetadata{
Name: m.Name,
FCMToken: m.FCMToken,
DeviceType: m.DeviceType,
}
err := p.protocol.SetInstallationMetadata(&p.identity.PublicKey, m.InstallationID, metadata)
if err != nil {
return nil, err
if err := p.processPairMessage(m); err != nil {
hlogger.Error("failed to process PairMessage", zap.Error(err))
}
default:
hlogger.Error("skipped a public message of unsupported type")
}
}
}
return decodedMessages, nil
}
func (p *messageProcessor) processPairMessage(m protocol.PairMessage) error {
metadata := &multidevice.InstallationMetadata{
Name: m.Name,
FCMToken: m.FCMToken,
DeviceType: m.DeviceType,
}
return p.protocol.SetInstallationMetadata(&p.identity.PublicKey, m.InstallationID, metadata)
}
// handleMessages expects a whisper message as input, and it will go through
// a series of transformations until the message is parsed into an application
// layer message, or in case of Raw methods, the processing stops at the layer
// before
// before.
// It returns an error only if the processing of required steps failed.
func (p *messageProcessor) handleMessages(shhMessage *whisper.Message, applicationLayer bool) ([]*protocol.StatusMessage, error) {
logger := p.logger.With(zap.String("site", "handleMessages"))
hlogger := logger.With(zap.Binary("hash", shhMessage.Hash))
@ -391,6 +406,7 @@ func (p *messageProcessor) addToDataSync(publicKey *ecdsa.PublicKey, message []b
}
// sendDataSync sends a message scheduled by the data sync layer.
// Data Sync layer calls this method "dispatch" function.
func (p *messageProcessor) sendDataSync(ctx context.Context, publicKey *ecdsa.PublicKey, encodedMessage []byte, payload *datasyncproto.Payload) error {
messageIDs := make([][]byte, 0, len(payload.Messages))
for _, payload := range payload.Messages {
@ -412,6 +428,7 @@ func (p *messageProcessor) sendDataSync(ctx context.Context, publicKey *ecdsa.Pu
return nil
}
// sendMessageSpec analyses the spec properties and selects a proper transport method.
func (p *messageProcessor) sendMessageSpec(ctx context.Context, publicKey *ecdsa.PublicKey, messageSpec *encryption.ProtocolMessageSpec) ([]byte, *whisper.NewMessage, error) {
newMessage, err := messageSpecToWhisper(messageSpec)
if err != nil {

View File

@ -6,6 +6,7 @@ import (
"database/sql"
"time"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/pkg/errors"
whisper "github.com/status-im/whisper/whisperv6"
@ -22,6 +23,8 @@ import (
var (
ErrChatIDEmpty = errors.New("chat ID is empty")
ErrNotImplemented = errors.New("not implemented")
errChatNotFound = errors.New("chat not found")
)
// Messenger is a entity managing chats and messages.
@ -475,6 +478,19 @@ func (m *Messenger) DeleteChat(chatID string) error {
return m.persistence.DeleteChat(chatID)
}
func (m *Messenger) chatByID(id string) (*Chat, error) {
chats, err := m.persistence.Chats()
if err != nil {
return nil, err
}
for _, c := range chats {
if c.ID == id {
return c, nil
}
}
return nil, errChatNotFound
}
func (m *Messenger) SaveContact(contact Contact) error {
return m.persistence.SaveContact(contact, nil)
}
@ -487,12 +503,13 @@ func (m *Messenger) Contacts() ([]*Contact, error) {
return m.persistence.Contacts()
}
func (m *Messenger) Send(ctx context.Context, chat Chat, data []byte) ([]byte, error) {
logger := m.logger.With(zap.String("site", "Send"), zap.String("chatID", chat.ID))
func (m *Messenger) Send(ctx context.Context, chatID string, data []byte) ([]byte, error) {
logger := m.logger.With(zap.String("site", "Send"), zap.String("chatID", chatID))
chatID := chat.ID
if chatID == "" {
return nil, ErrChatIDEmpty
// A valid added chat is required.
chat, err := m.chatByID(chatID)
if err != nil {
return nil, err
}
clock, err := m.persistence.LastMessageClock(chat.ID)
@ -505,14 +522,15 @@ func (m *Messenger) Send(ctx context.Context, chat Chat, data []byte) ([]byte, e
if chat.PublicKey != nil {
logger.Debug("sending private message", zap.Binary("publicKey", crypto.FromECDSAPub(chat.PublicKey)))
hash, message, err := m.processor.SendPrivate(ctx, chat.PublicKey, chat.ID, data, clock)
id, message, err := m.processor.SendPrivate(ctx, chat.PublicKey, chat.ID, data, clock)
if err != nil {
return nil, err
}
// Save our message because it won't be received from the transport layer.
message.ID = hash // a Message need ID to be properly stored in the db
message.ID = id // a Message need ID to be properly stored in the db
message.SigPubKey = &m.identity.PublicKey
message.ChatID = chatID
if m.messagesPersistenceEnabled {
_, err = m.persistence.SaveMessages([]*protocol.Message{message})
@ -524,10 +542,10 @@ func (m *Messenger) Send(ctx context.Context, chat Chat, data []byte) ([]byte, e
// Cache it to be returned in Retrieve().
m.ownMessages = append(m.ownMessages, message)
return hash, nil
return id, nil
} else if chat.Name != "" {
logger.Debug("sending public message", zap.String("chatName", chat.Name))
return m.processor.SendPublic(ctx, chat.Name, chat.ID, data, clock)
return m.processor.SendPublic(ctx, chat.ID, data, clock)
}
return nil, errors.New("chat is neither public nor private")
}
@ -557,28 +575,18 @@ var (
// RetrieveAll retrieves all previously fetched messages
func (m *Messenger) RetrieveAll(ctx context.Context, c RetrieveConfig) ([]*protocol.Message, error) {
latest, err := m.transport.RetrieveAllMessages()
if err != nil {
return nil, errors.Wrap(err, "failed to retrieve messages")
}
logger := m.logger.With(zap.String("site", "RetrieveAll"))
logger.Debug("retrieved messages grouped by chat", zap.Int("count", len(latest)))
var result []*protocol.Message
for _, chat := range latest {
logger.Debug("processing chat", zap.String("chatID", chat.ChatID))
protoMessages, err := m.processor.Process(chat.Messages)
result, err := m.retrieveLatest(ctx)
if err != nil {
return nil, err
}
result = append(result, protoMessages...)
}
_, err = m.persistence.SaveMessages(result)
postProcess := newPostProcessor(m, postProcessorConfig{
MatchChat: true,
Persist: true,
})
result, err = postProcess.Run(result)
if err != nil {
return nil, errors.Wrap(err, "failed to save messages")
return nil, errors.Wrap(err, "failed to post process messages")
}
retrievedMessages, err := m.retrieveSaved(ctx, c)
@ -594,6 +602,26 @@ func (m *Messenger) RetrieveAll(ctx context.Context, c RetrieveConfig) ([]*proto
return result, nil
}
func (m *Messenger) retrieveLatest(ctx context.Context) ([]*protocol.Message, error) {
latest, err := m.transport.RetrieveAllMessages()
if err != nil {
return nil, errors.Wrap(err, "failed to retrieve messages")
}
logger := m.logger.With(zap.String("site", "RetrieveAll"))
logger.Debug("retrieved messages", zap.Int("count", len(latest)))
var result []*protocol.Message
for _, transpMessage := range latest {
protoMessages, err := m.processor.Process(transpMessage.Message)
if err != nil {
return nil, err
}
result = append(result, protoMessages...)
}
return result, nil
}
func (m *Messenger) retrieveSaved(ctx context.Context, c RetrieveConfig) (messages []*protocol.Message, err error) {
if !m.messagesPersistenceEnabled {
return nil, nil
@ -697,3 +725,136 @@ func (m *Messenger) MarkMessagesSeen(ids ...string) error {
func (m *Messenger) UpdateMessageOutgoingStatus(id, newOutgoingStatus string) error {
return m.persistence.UpdateMessageOutgoingStatus(id, newOutgoingStatus)
}
// postProcessor performs a set of actions on newly retrieved messages.
// If persist is true, it saves the messages into the database.
// If matchChat is true, it matches each messages against a Chat instance.
type postProcessor struct {
myPublicKey *ecdsa.PublicKey
persistence *sqlitePersistence
logger *zap.Logger
config postProcessorConfig
}
type postProcessorConfig struct {
MatchChat bool // match each messages to a chat; may result in a new chat creation
Persist bool // if true, all sent and received user messages will be persisted
}
func newPostProcessor(m *Messenger, config postProcessorConfig) *postProcessor {
return &postProcessor{
myPublicKey: &m.identity.PublicKey,
persistence: m.persistence,
logger: m.logger,
config: config,
}
}
func (p *postProcessor) Run(messages []*protocol.Message) ([]*protocol.Message, error) {
var err error
p.logger.Debug("running post processor", zap.Int("messages", len(messages)))
var fns []func([]*protocol.Message) ([]*protocol.Message, error)
// Order is important. Persisting messages should be always at the end.
if p.config.MatchChat {
fns = append(fns, p.matchMessages)
}
if p.config.Persist {
fns = append(fns, p.saveMessages)
}
for _, fn := range fns {
messages, err = fn(messages)
if err != nil {
return nil, err
}
}
return messages, nil
}
func (p *postProcessor) saveMessages(messages []*protocol.Message) ([]*protocol.Message, error) {
_, err := p.persistence.SaveMessages(messages)
if err != nil {
return nil, err
}
return messages, nil
}
func (p *postProcessor) matchMessages(messages []*protocol.Message) ([]*protocol.Message, error) {
chats, err := p.persistence.Chats()
if err != nil {
return nil, err
}
result := make([]*protocol.Message, 0, len(messages))
for _, message := range messages {
chat, err := p.matchMessage(message, chats)
if err != nil {
p.logger.Error("failed to match a chat to a message", zap.Error(err))
continue
}
message.ChatID = chat.ID
result = append(result, message)
}
return result, nil
}
func (p *postProcessor) matchMessage(message *protocol.Message, chats []*Chat) (*Chat, error) {
switch {
case message.MessageT == protocol.MessageTypePublicGroup:
// For public messages, all outgoing and incoming messages have the same chatID
// equal to a public chat name.
chatID := message.Content.ChatID
chat := findChatByID(chatID, chats)
if chat == nil {
return nil, errors.New("received a public message from non-existing chat")
}
return chat, nil
case message.MessageT == protocol.MessageTypePrivate && isPubKeyEqual(message.SigPubKey, p.myPublicKey):
// It's a private message coming from us so we rely on Message.Content.ChatID.
// If chat does not exist, it should be created to support multidevice synchronization.
chatID := message.Content.ChatID
chat := findChatByID(chatID, chats)
if chat == nil {
// TODO: this should be a three-word name used in the mobile client
newChat := CreateOneToOneChat(chatID[:8], message.SigPubKey)
if err := p.persistence.SaveChat(newChat); err != nil {
return nil, errors.Wrap(err, "failed to save newly created chat")
}
chat = &newChat
}
return chat, nil
case message.MessageT == protocol.MessageTypePrivate:
// It's an incoming private message. ChatID is calculated from the signature.
// If a chat does not exist, a new one is created and saved.
chatID := hexutil.Encode(crypto.FromECDSAPub(message.SigPubKey))
chat := findChatByID(chatID, chats)
if chat == nil {
// TODO: this should be a three-word name used in the mobile client
newChat := CreateOneToOneChat(chatID[:8], message.SigPubKey)
if err := p.persistence.SaveChat(newChat); err != nil {
return nil, errors.Wrap(err, "failed to save newly created chat")
}
chat = &newChat
}
return chat, nil
case message.MessageT == protocol.MessageTypePrivateGroup:
// In the case of a group message, ChatID is the same for all messages belonging to a group.
// It needs to be verified if the signature public key belongs to the chat.
chatID := message.Content.ChatID
chat := findChatByID(chatID, chats)
sigPubKeyHex := hexutil.Encode(crypto.FromECDSAPub(message.SigPubKey))
for _, member := range chat.Members {
if member.ID == sigPubKeyHex {
return chat, nil
}
}
return nil, errors.New("did not find a matching group chat")
default:
return nil, errors.New("can not match a chat because there is no valid case")
}
}

View File

@ -7,13 +7,17 @@ import (
"errors"
"io/ioutil"
"os"
"strconv"
"testing"
"time"
"github.com/status-im/status-protocol-go/sqlite"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
_ "github.com/mutecomm/go-sqlcipher" // require go-sqlcipher that overrides default implementation
"github.com/status-im/status-protocol-go/tt"
statusproto "github.com/status-im/status-protocol-go/v1"
protocol "github.com/status-im/status-protocol-go/v1"
whisper "github.com/status-im/whisper/whisperv6"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
@ -27,6 +31,10 @@ func TestMessengerWithDataSyncEnabledSuite(t *testing.T) {
suite.Run(t, &MessengerSuite{enableDataSync: true})
}
func TestPostProcessorSuite(t *testing.T) {
suite.Run(t, new(PostProcessorSuite))
}
type MessengerSuite struct {
suite.Suite
@ -230,21 +238,29 @@ func (s *MessengerSuite) TestInit() {
}
func (s *MessengerSuite) TestSendPublic() {
_, err := s.m.Send(context.Background(), Chat{Name: "status", ID: "status"}, []byte("test"))
chat := CreatePublicChat("test-chat")
err := s.m.SaveChat(chat)
s.NoError(err)
_, err = s.m.Send(context.Background(), chat.ID, []byte("test"))
s.NoError(err)
}
func (s *MessengerSuite) TestSendPrivate() {
recipientKey, err := crypto.GenerateKey()
s.NoError(err)
_, err = s.m.Send(context.Background(), Chat{ID: "x", PublicKey: &recipientKey.PublicKey}, []byte("test"))
chat := CreateOneToOneChat("XXX", &recipientKey.PublicKey)
err = s.m.SaveChat(chat)
s.NoError(err)
_, err = s.m.Send(context.Background(), chat.ID, []byte("test"))
s.NoError(err)
}
func (s *MessengerSuite) TestRetrieveOwnPublic() {
chat := Chat{ID: "status", Name: "status"}
chat := CreatePublicChat("status")
err := s.m.SaveChat(chat)
s.NoError(err)
_, err := s.m.Send(context.Background(), chat, []byte("test"))
_, err = s.m.Send(context.Background(), chat.ID, []byte("test"))
s.NoError(err)
// Give Whisper some time to propagate message to filters.
@ -267,11 +283,13 @@ func (s *MessengerSuite) TestRetrieveOwnPublic() {
}
func (s *MessengerSuite) TestRetrieveOwnPrivate() {
publicContact, err := crypto.GenerateKey()
recipientKey, err := crypto.GenerateKey()
s.NoError(err)
chat := CreateOneToOneChat("XXX", &recipientKey.PublicKey)
err = s.m.SaveChat(chat)
s.NoError(err)
chat := Chat{ID: "x", PublicKey: &publicContact.PublicKey}
messageID, err := s.m.Send(context.Background(), chat, []byte("test"))
messageID, err := s.m.Send(context.Background(), chat.ID, []byte("test"))
s.NoError(err)
// No need to sleep because the message is returned from own messages in the processor.
@ -294,11 +312,14 @@ func (s *MessengerSuite) TestRetrieveOwnPrivate() {
func (s *MessengerSuite) TestRetrieveTheirPrivate() {
theirMessenger := s.newMessenger()
chat := Chat{ID: "x", PublicKey: &s.privateKey.PublicKey}
messageID, err := theirMessenger.Send(context.Background(), chat, []byte("test"))
chat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey)
err := theirMessenger.SaveChat(chat)
s.NoError(err)
var messages []*statusproto.Message
messageID, err := theirMessenger.Send(context.Background(), chat.ID, []byte("test"))
s.NoError(err)
var messages []*protocol.Message
err = tt.RetryWithBackOff(func() error {
var err error
@ -763,3 +784,109 @@ func (s *MessengerSuite) TestSharedSecretHandler() {
_, err := s.m.handleSharedSecrets(nil)
s.NoError(err)
}
type PostProcessorSuite struct {
suite.Suite
postProcessor *postProcessor
logger *zap.Logger
}
func (s *PostProcessorSuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
db, err := sqlite.OpenInMemory()
s.Require().NoError(err)
s.postProcessor = &postProcessor{
myPublicKey: &privateKey.PublicKey,
persistence: &sqlitePersistence{db: db},
logger: s.logger,
config: postProcessorConfig{
MatchChat: true,
Persist: true,
},
}
}
func (s *PostProcessorSuite) TearDownTest() {
_ = s.logger.Sync()
}
func (s *PostProcessorSuite) TestRun() {
key1, err := crypto.GenerateKey()
s.Require().NoError(err)
key2, err := crypto.GenerateKey()
s.Require().NoError(err)
testCases := []struct {
Name string
Chat Chat // Chat to create
Message protocol.Message
SigPubKey *ecdsa.PublicKey
ExpectedChatID string
}{
{
Name: "Public chat",
Chat: CreatePublicChat("test-chat"),
Message: protocol.CreatePublicTextMessage([]byte("test"), 0, "test-chat"),
SigPubKey: &key1.PublicKey,
ExpectedChatID: "test-chat",
},
{
Name: "Private message from myself with existing chat",
Chat: CreateOneToOneChat("test-private-chat", &key1.PublicKey),
Message: protocol.CreatePrivateTextMessage([]byte("test"), 0, oneToOneChatID(&key1.PublicKey)),
SigPubKey: &key1.PublicKey,
ExpectedChatID: oneToOneChatID(&key1.PublicKey),
},
{
Name: "Private message from other with existing chat",
Chat: CreateOneToOneChat("test-private-chat", &key2.PublicKey),
Message: protocol.CreatePrivateTextMessage([]byte("test"), 0, oneToOneChatID(&key1.PublicKey)),
SigPubKey: &key2.PublicKey,
ExpectedChatID: oneToOneChatID(&key2.PublicKey),
},
{
Name: "Private message from myself without chat",
Message: protocol.CreatePrivateTextMessage([]byte("test"), 0, oneToOneChatID(&key1.PublicKey)),
SigPubKey: &key1.PublicKey,
ExpectedChatID: oneToOneChatID(&key1.PublicKey),
},
{
Name: "Private message from other without chat",
Message: protocol.CreatePrivateTextMessage([]byte("test"), 0, oneToOneChatID(&key1.PublicKey)),
SigPubKey: &key2.PublicKey,
ExpectedChatID: oneToOneChatID(&key2.PublicKey),
},
// TODO: add test for group messages
}
for idx, tc := range testCases {
s.Run(tc.Name, func() {
if tc.Chat.ID != "" {
err := s.postProcessor.persistence.SaveChat(tc.Chat)
s.Require().NoError(err)
defer func() {
err := s.postProcessor.persistence.DeleteChat(tc.Chat.ID)
s.Require().NoError(err)
}()
}
message := tc.Message
message.SigPubKey = tc.SigPubKey
// ChatID is not set at the beginning.
s.Empty(message.ChatID)
message.ID = []byte(strconv.Itoa(idx)) // manually set the ID because messages does not go through messageProcessor
messages, err := s.postProcessor.Run([]*protocol.Message{&message})
s.NoError(err)
s.Equal(tc.ExpectedChatID, message.ChatID)
s.Require().Len(messages, 1)
s.EqualValues(&message, messages[0])
})
}
}

View File

@ -8,6 +8,8 @@
// 000003_add_contacts.up.db.sql (251B)
// 000004_user_messages_compatibility.down.sql (33B)
// 000004_user_messages_compatibility.up.sql (928B)
// 1567112142_user_messages.down.sql (26B)
// 1567112142_user_messages.up.sql (551B)
// doc.go (377B)
package migrations
@ -92,7 +94,7 @@ func _000001_initDownDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe8, 0x5f, 0xe0, 0x6, 0xfc, 0xed, 0xb7, 0xff, 0xb5, 0xf3, 0x33, 0x45, 0x1, 0x5b, 0x84, 0x80, 0x74, 0x60, 0x81, 0xa6, 0x8b, 0xb4, 0xd4, 0xad, 0x10, 0xa8, 0xb3, 0x61, 0x6f, 0xc5, 0x2f, 0xaa}}
return a, nil
}
@ -112,7 +114,7 @@ func _000001_initUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 840, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 840, mode: os.FileMode(0644), modTime: time.Unix(1567109338, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe7, 0x27, 0x96, 0x3b, 0x72, 0x81, 0x7d, 0xba, 0xa4, 0xfb, 0xf7, 0x4, 0xd, 0x6f, 0xc8, 0x30, 0xfe, 0x47, 0xe0, 0x9, 0xf, 0x43, 0x13, 0x6, 0x55, 0xfc, 0xee, 0x15, 0x69, 0x99, 0x53, 0x3f}}
return a, nil
}
@ -132,7 +134,7 @@ func _000002_add_chatsDownDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000002_add_chats.down.db.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1565597460, 0)}
info := bindataFileInfo{name: "000002_add_chats.down.db.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1565859748, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd3, 0xa7, 0xf0, 0x94, 0x7a, 0x9, 0xdc, 0x6c, 0x7b, 0xdc, 0x12, 0x30, 0x55, 0x31, 0x17, 0xf2, 0xcc, 0x6e, 0xfd, 0xbb, 0x70, 0xb9, 0xd8, 0x9f, 0x81, 0x83, 0xdc, 0x1d, 0x1c, 0x3a, 0x8d, 0xce}}
return a, nil
}
@ -152,7 +154,7 @@ func _000002_add_chatsUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 569, mode: os.FileMode(0644), modTime: time.Unix(1567414857, 0)}
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 569, mode: os.FileMode(0644), modTime: time.Unix(1567796732, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x89, 0xb, 0x12, 0x5, 0x4b, 0xda, 0xab, 0xb2, 0x47, 0x1b, 0x66, 0xe, 0x47, 0x8a, 0xb0, 0x9c, 0xa0, 0xe4, 0x12, 0xa4, 0xf9, 0xaa, 0x72, 0xba, 0xd9, 0x17, 0x8f, 0xac, 0x7f, 0xfd, 0x85, 0xa9}}
return a, nil
}
@ -172,7 +174,7 @@ func _000003_add_contactsDownDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000003_add_contacts.down.db.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1565597570, 0)}
info := bindataFileInfo{name: "000003_add_contacts.down.db.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1565860010, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfc, 0x7e, 0xb, 0xec, 0x72, 0xcd, 0x21, 0x3e, 0xa2, 0x38, 0xe0, 0x95, 0x7e, 0xce, 0x4a, 0x17, 0xc8, 0xd0, 0x1c, 0xfa, 0xa3, 0x23, 0x5, 0xab, 0x89, 0xf9, 0xfc, 0x63, 0x7, 0x28, 0xe9, 0x93}}
return a, nil
}
@ -192,7 +194,7 @@ func _000003_add_contactsUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000003_add_contacts.up.db.sql", size: 251, mode: os.FileMode(0644), modTime: time.Unix(1565597570, 0)}
info := bindataFileInfo{name: "000003_add_contacts.up.db.sql", size: 251, mode: os.FileMode(0644), modTime: time.Unix(1565860010, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8f, 0x19, 0x9f, 0x5c, 0x9d, 0xa1, 0xe5, 0x99, 0xbe, 0x47, 0xce, 0xa5, 0xd3, 0x51, 0x2f, 0x9b, 0x1d, 0xd9, 0x3f, 0x7a, 0xbf, 0xf, 0x76, 0x6b, 0x4f, 0x82, 0xbd, 0x13, 0x9d, 0x25, 0xdd, 0x60}}
return a, nil
}
@ -212,7 +214,7 @@ func _000004_user_messages_compatibilityDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000004_user_messages_compatibility.down.sql", size: 33, mode: os.FileMode(0644), modTime: time.Unix(1565631683, 0)}
info := bindataFileInfo{name: "000004_user_messages_compatibility.down.sql", size: 33, mode: os.FileMode(0644), modTime: time.Unix(1565860010, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb9, 0xaf, 0x48, 0x80, 0x3d, 0x54, 0x5e, 0x53, 0xee, 0x98, 0x26, 0xbb, 0x99, 0x6a, 0xd8, 0x37, 0x94, 0xf2, 0xf, 0x82, 0xfa, 0xb7, 0x6a, 0x68, 0xcd, 0x8b, 0xe2, 0xc4, 0x6, 0x25, 0xdc, 0x6}}
return a, nil
}
@ -232,11 +234,51 @@ func _000004_user_messages_compatibilityUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000004_user_messages_compatibility.up.sql", size: 928, mode: os.FileMode(0644), modTime: time.Unix(1566286773, 0)}
info := bindataFileInfo{name: "000004_user_messages_compatibility.up.sql", size: 928, mode: os.FileMode(0644), modTime: time.Unix(1566366197, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdf, 0xc4, 0x5c, 0xed, 0x4, 0x26, 0xb1, 0xb2, 0x53, 0xac, 0x1, 0x20, 0xf3, 0x17, 0x37, 0xb3, 0x3d, 0x84, 0x5e, 0xd8, 0x1, 0x53, 0x88, 0x9a, 0x9c, 0xaf, 0x9, 0xdf, 0x58, 0x2e, 0xf0, 0x19}}
return a, nil
}
var __1567112142_user_messagesDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x28\x2d\x4e\x2d\x8a\xcf\x4d\x2d\x2e\x4e\x4c\x4f\x2d\xb6\xe6\x02\x04\x00\x00\xff\xff\xa9\xe2\x72\x97\x1a\x00\x00\x00")
func _1567112142_user_messagesDownSqlBytes() ([]byte, error) {
return bindataRead(
__1567112142_user_messagesDownSql,
"1567112142_user_messages.down.sql",
)
}
func _1567112142_user_messagesDownSql() (*asset, error) {
bytes, err := _1567112142_user_messagesDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1567112142_user_messages.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1568200715, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x79, 0x8e, 0xbe, 0x63, 0x64, 0x52, 0xa3, 0x13, 0x83, 0xc7, 0x47, 0xff, 0x56, 0xa9, 0xc, 0x72, 0xb4, 0x97, 0x6, 0xc7, 0xa5, 0x68, 0xb6, 0x55, 0x6a, 0xd5, 0xb0, 0x12, 0xfb, 0x4c, 0xa5, 0x27}}
return a, nil
}
var __1567112142_user_messagesUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x90\x51\x6f\x9b\x30\x14\x85\xdf\xf9\x15\xe7\xad\xad\xb4\x54\x7b\xef\x13\x01\x67\x43\x42\x64\x23\xce\xd6\xb7\xc8\xd8\xb7\xc5\x8a\xb1\x11\xbe\x2c\xe5\xdf\x4f\xa1\xb0\x2d\x53\x5f\xcf\x77\xfd\xdd\x73\xbd\xd9\x20\x1f\x42\x0f\xe5\x27\xf4\x03\xfd\xb2\x61\x8c\x6e\x82\x1e\x48\x31\x19\x8c\x91\x86\x53\x47\x31\xaa\x57\x8a\x60\xd5\x38\x7a\x4c\x36\x1b\xfc\x24\x98\xe0\xef\x18\x9e\xc8\x80\x03\x22\xab\x09\x8d\xd2\xe7\x8b\x1a\x0c\x74\xe8\x7a\xc5\xb6\x71\x84\x8b\xe5\x16\x96\xaf\x8f\x1a\xd2\x6a\x8c\x04\xcb\x77\x11\x3e\xf0\xd5\x6e\xae\x9b\x2f\x2d\x0d\x04\x7a\xd3\xd4\x33\x5e\xc2\x00\x6e\x09\x3a\xf8\x18\x1c\x41\x3b\x4b\x9e\x1f\x93\xbc\xde\x7f\x83\x4c\xb7\xa5\xb8\x6d\xf5\x94\x24\x59\x2d\x52\x29\x16\x58\xec\x50\xed\x25\xc4\x73\x71\x90\x87\xff\x0e\xb8\x4f\x00\xc0\x1a\x6c\xcb\xfd\x16\xc7\xaa\xf8\x7e\x14\xf3\x74\x75\x2c\xcb\x4f\x33\xd4\xad\xe2\x93\x35\xf8\x91\xd6\xd9\xd7\xb4\xfe\x43\x51\x8b\x9d\xa8\x45\x95\x89\xc3\x3c\x13\xef\xad\x79\xc0\xbe\x42\x2e\x4a\x21\x05\xb2\xf4\x90\xa5\xb9\x58\x24\xc1\x33\x79\x3e\xf1\xd4\xd3\x6a\x7a\x27\x4b\x95\x0f\x08\xd3\x1b\x43\x8a\x67\xb9\x28\x5c\xd0\x67\x6c\x8b\x2f\x45\xb5\x24\x6c\x3b\x8a\xac\xba\xfe\x26\x5d\x57\xad\xbd\xff\x31\xac\x25\x6e\xc5\xfd\xd8\x38\xab\x4f\x67\x9a\xe6\x5f\x78\x0f\x5f\x9c\x7a\x8d\x28\x2a\xf9\xf7\xde\x5c\xec\xd2\x63\x29\xf1\x39\x79\x78\x4a\x7e\x07\x00\x00\xff\xff\x07\x0e\xee\x5c\x27\x02\x00\x00")
func _1567112142_user_messagesUpSqlBytes() ([]byte, error) {
return bindataRead(
__1567112142_user_messagesUpSql,
"1567112142_user_messages.up.sql",
)
}
func _1567112142_user_messagesUpSql() (*asset, error) {
bytes, err := _1567112142_user_messagesUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1567112142_user_messages.up.sql", size: 551, mode: os.FileMode(0644), modTime: time.Unix(1568200715, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7a, 0x11, 0x2, 0x79, 0x3b, 0xc5, 0x37, 0xe7, 0x3f, 0xa9, 0x35, 0x99, 0xa5, 0x3f, 0x32, 0xa3, 0xbe, 0xf7, 0x53, 0xf3, 0xea, 0x72, 0xbd, 0xb, 0xfc, 0xa7, 0xdc, 0x97, 0x1c, 0x6, 0x71, 0x16}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\xbb\x6e\xc3\x30\x0c\x45\x77\x7f\xc5\x45\x96\x2c\xb5\xb4\x74\xea\xd6\xb1\x7b\x7f\x80\x91\x68\x89\x88\x1e\xae\x48\xe7\xf1\xf7\x85\xd3\x02\xcd\xd6\xf5\x00\xe7\xf0\xd2\x7b\x7c\x66\x51\x2c\x52\x18\xa2\x68\x1c\x58\x95\xc6\x1d\x27\x0e\xb4\x29\xe3\x90\xc4\xf2\x76\x72\xa1\x57\xaf\x46\xb6\xe9\x2c\xd5\x57\x49\x83\x8c\xfd\xe5\xf5\x30\x79\x8f\x40\xed\x68\xc8\xd4\x62\xe1\x47\x4b\xa1\x46\xc3\xa4\x25\x5c\xc5\x32\x08\xeb\xe0\x45\x6e\x0e\xef\x86\xc2\xa4\x06\xcb\x64\x47\x85\x65\x46\x20\xe5\x3d\xb3\xf4\x81\xd4\xe7\x93\xb4\x48\x46\x6e\x47\x1f\xcb\x13\xd9\x17\x06\x2a\x85\x23\x96\xd1\xeb\xc3\x55\xaa\x8c\x28\x83\x83\xf5\x71\x7f\x01\xa9\xb2\xa1\x51\x65\xdd\xfd\x4c\x17\x46\xeb\xbf\xe7\x41\x2d\xfe\xff\x11\xae\x7d\x9c\x15\xa4\xe0\xdb\xca\xc1\x38\xba\x69\x5a\x29\x9c\x29\x31\xf4\xab\x88\xf1\x34\x79\x9f\xfa\x5b\xe2\xc6\xbb\xf5\xbc\x71\x5e\xcf\x09\x3f\x35\xe9\x4d\x31\x77\x38\xe7\xff\x80\x4b\x1d\x6e\xfa\x0e\x00\x00\xff\xff\x9d\x60\x3d\x88\x79\x01\x00\x00")
func docGoBytes() ([]byte, error) {
@ -252,7 +294,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xef, 0xaf, 0xdf, 0xcf, 0x65, 0xae, 0x19, 0xfc, 0x9d, 0x29, 0xc1, 0x91, 0xaf, 0xb5, 0xd5, 0xb1, 0x56, 0xf3, 0xee, 0xa8, 0xba, 0x13, 0x65, 0xdb, 0xab, 0xcf, 0x4e, 0xac, 0x92, 0xe9, 0x60, 0xf1}}
return a, nil
}
@ -364,6 +406,10 @@ var _bindata = map[string]func() (*asset, error){
"000004_user_messages_compatibility.up.sql": _000004_user_messages_compatibilityUpSql,
"1567112142_user_messages.down.sql": _1567112142_user_messagesDownSql,
"1567112142_user_messages.up.sql": _1567112142_user_messagesUpSql,
"doc.go": docGo,
}
@ -416,6 +462,8 @@ var _bintree = &bintree{nil, map[string]*bintree{
"000003_add_contacts.up.db.sql": &bintree{_000003_add_contactsUpDbSql, map[string]*bintree{}},
"000004_user_messages_compatibility.down.sql": &bintree{_000004_user_messages_compatibilityDownSql, map[string]*bintree{}},
"000004_user_messages_compatibility.up.sql": &bintree{_000004_user_messages_compatibilityUpSql, map[string]*bintree{}},
"1567112142_user_messages.down.sql": &bintree{_1567112142_user_messagesDownSql, map[string]*bintree{}},
"1567112142_user_messages.up.sql": &bintree{_1567112142_user_messagesUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
}}

View File

@ -0,0 +1 @@
DROP TABLE user_messages;

View File

@ -0,0 +1,18 @@
-- Drop any previously created user_messages table.
-- We don't need to stay backward compatible with it
-- because it's not used anywhere except for the console client.
DROP TABLE user_messages;
CREATE TABLE IF NOT EXISTS user_messages (
id BLOB UNIQUE NOT NULL,
chat_id VARCHAR NOT NULL REFERENCES chats(id) ON DELETE CASCADE,
content_type VARCHAR,
message_type VARCHAR,
text TEXT,
clock BIGINT,
timestamp BIGINT,
content_chat_id TEXT,
content_text TEXT,
public_key BLOB,
flags INT NOT NULL DEFAULT 0
);

View File

@ -286,7 +286,6 @@ func (db sqlitePersistence) SaveContact(contact Contact, tx *sql.Tx) error {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
@ -343,6 +342,7 @@ func (db sqlitePersistence) SaveContact(contact Contact, tx *sql.Tx) error {
func (db sqlitePersistence) Messages(from, to time.Time) (result []*protocol.Message, err error) {
rows, err := db.db.Query(`SELECT
id,
chat_id,
content_type,
message_type,
text,
@ -370,8 +370,9 @@ func (db sqlitePersistence) Messages(from, to time.Time) (result []*protocol.Mes
}
pkey := []byte{}
err = rows.Scan(
&msg.ID, &msg.ContentT, &msg.MessageT, &msg.Text, &msg.Clock,
&msg.Timestamp, &msg.Content.ChatID, &msg.Content.Text, &pkey, &msg.Flags)
&msg.ID, &msg.ChatID, &msg.ContentT, &msg.MessageT, &msg.Text, &msg.Clock,
&msg.Timestamp, &msg.Content.ChatID, &msg.Content.Text, &pkey, &msg.Flags,
)
if err != nil {
return nil, err
}
@ -386,106 +387,12 @@ func (db sqlitePersistence) Messages(from, to time.Time) (result []*protocol.Mes
return rst, nil
}
func (db sqlitePersistence) NewMessages(chatID string, rowid int64) ([]*protocol.Message, error) {
rows, err := db.db.Query(`SELECT
id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags
FROM user_messages WHERE chat_id = ? AND rowid >= ? ORDER BY clock`,
chatID, rowid)
if err != nil {
return nil, err
}
defer rows.Close()
var (
rst = []*protocol.Message{}
)
for rows.Next() {
msg := protocol.Message{
Content: protocol.Content{},
}
pkey := []byte{}
err = rows.Scan(
&msg.ID, &msg.ContentT, &msg.MessageT, &msg.Text, &msg.Clock,
&msg.Timestamp, &msg.Content.ChatID, &msg.Content.Text, &pkey, &msg.Flags)
if err != nil {
return nil, err
}
if len(pkey) != 0 {
msg.SigPubKey, err = unmarshalECDSAPub(pkey)
if err != nil {
return nil, err
}
}
rst = append(rst, &msg)
}
return rst, nil
}
// TODO(adam): refactor all message getters in order not to
// repeat the select fields over and over.
func (db sqlitePersistence) UnreadMessages(chatID string) ([]*protocol.Message, error) {
rows, err := db.db.Query(`
SELECT
id,
content_type,
message_type,
text,
clock,
timestamp,
content_chat_id,
content_text,
public_key,
flags
FROM
user_messages
WHERE
chat_id = ? AND
flags & ? == 0
ORDER BY clock`,
chatID, protocol.MessageRead,
)
if err != nil {
return nil, err
}
defer rows.Close()
var result []*protocol.Message
for rows.Next() {
msg := protocol.Message{
Content: protocol.Content{},
}
pkey := []byte{}
err = rows.Scan(
&msg.ID, &msg.ContentT, &msg.MessageT, &msg.Text, &msg.Clock,
&msg.Timestamp, &msg.Content.ChatID, &msg.Content.Text, &pkey, &msg.Flags)
if err != nil {
return nil, err
}
if len(pkey) != 0 {
msg.SigPubKey, err = unmarshalECDSAPub(pkey)
if err != nil {
return nil, err
}
}
result = append(result, &msg)
}
return result, nil
}
func (db sqlitePersistence) SaveMessages(messages []*protocol.Message) (last int64, err error) {
var (
tx *sql.Tx
stmt *sql.Stmt
)
tx, err = db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return
}
stmt, err = tx.Prepare(`INSERT INTO user_messages(
id, chat_id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
if err != nil {
return
}
@ -493,12 +400,30 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
stmt, err = tx.Prepare(`INSERT INTO
user_messages(
id,
chat_id,
content_type,
message_type,
text,
clock,
timestamp,
content_chat_id,
content_text,
public_key,
flags
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`)
if err != nil {
return
}
var rst sql.Result
for _, msg := range messages {
@ -507,9 +432,9 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
pkey, err = marshalECDSAPub(msg.SigPubKey)
}
rst, err = stmt.Exec(
msg.ID, msg.ChatID, msg.ContentT, msg.MessageT, msg.Text,
msg.Clock, msg.Timestamp, msg.Content.ChatID, msg.Content.Text,
pkey, msg.Flags)
msg.ID, msg.ChatID, msg.ContentT, msg.MessageT, msg.Text, msg.Clock, msg.Timestamp,
msg.Content.ChatID, msg.Content.Text, pkey, msg.Flags,
)
if err != nil {
if err.Error() == uniqueIDContstraint {
// skip duplicated messages

View File

@ -198,7 +198,7 @@ func (db sqlitePersistence) MessageByChatID(chatID string, currCursor string, li
args = append(args, currCursor)
}
// Build a new column `cursor` at the query time by having a fixed-sized clock value at the beginning
// concatenated with rowid. Results are sorted using this new column.
// concatenated with message ID. Results are sorted using this new column.
// This new column values can also be returned as a cursor for subsequent requests.
rows, err := db.db.Query(
fmt.Sprintf(`

View File

@ -25,6 +25,8 @@ const defaultKdfIterationsNumber = 64000 // nolint: deadcode,varcheck,unused
// https://notes.status.im/i8Y_l7ccTiOYq09HVgoFwA
const reducedKdfIterationsNumber = 3200
const inMemoryPath = ":memory:"
// MigrationConfig is a struct that allows to define bindata migrations.
type MigrationConfig struct {
AssetNames []string
@ -37,6 +39,12 @@ func Open(path, key string) (*sql.DB, error) {
return open(path, key, reducedKdfIterationsNumber)
}
// OpenInMemory opens an in memory SQLite database.
// Number of KDF iterations is reduced to 0.
func OpenInMemory() (*sql.DB, error) {
return open(inMemoryPath, "", 0)
}
// OpenWithIter allows to open a new database with a custom number of kdf iterations.
// Higher kdf iterations number makes it slower to open the database.
func OpenWithIter(path, key string, kdfIter int) (*sql.DB, error) {
@ -44,10 +52,12 @@ func OpenWithIter(path, key string, kdfIter int) (*sql.DB, error) {
}
func open(path string, key string, kdfIter int) (*sql.DB, error) {
if path != inMemoryPath {
_, err := os.OpenFile(path, os.O_CREATE, 0644)
if err != nil {
return nil, err
}
}
db, err := sql.Open("sqlite3", path)
if err != nil {

View File

@ -86,7 +86,7 @@ func _1561059285_add_whisper_keysDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1561059285_add_whisper_keys.down.sql", size: 25, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1561059285_add_whisper_keys.down.sql", size: 25, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb9, 0x31, 0x3f, 0xce, 0xfa, 0x44, 0x36, 0x1b, 0xb0, 0xec, 0x5d, 0xb, 0x90, 0xb, 0x21, 0x4f, 0xd5, 0xe5, 0x50, 0xed, 0xc7, 0x43, 0xdf, 0x83, 0xb4, 0x3a, 0xc1, 0x55, 0x2e, 0x53, 0x7c, 0x67}}
return a, nil
}
@ -106,7 +106,7 @@ func _1561059285_add_whisper_keysUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1561059285_add_whisper_keys.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "1561059285_add_whisper_keys.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x25, 0x41, 0xc, 0x92, 0xdd, 0x9e, 0xff, 0x5d, 0xd0, 0x93, 0xe4, 0x24, 0x50, 0x29, 0xcf, 0xc6, 0xf7, 0x49, 0x3c, 0x73, 0xd9, 0x8c, 0xfa, 0xf2, 0xcf, 0xf6, 0x6f, 0xbc, 0x31, 0xe6, 0xf7, 0xe2}}
return a, nil
}
@ -126,7 +126,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1564484687, 0)}
info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1564235168, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x23, 0x6a, 0xc1, 0xce, 0x94, 0xf6, 0xef, 0xf1, 0x97, 0x95, 0xb, 0x35, 0xaf, 0x5f, 0xe7, 0x5f, 0xac, 0x6e, 0xb8, 0xab, 0xba, 0xb5, 0x35, 0x97, 0x22, 0x36, 0x11, 0xce, 0x44, 0xfc, 0xfa, 0xac}}
return a, nil
}

View File

@ -180,14 +180,13 @@ func (a *WhisperServiceTransport) LeavePrivate(publicKey *ecdsa.PublicKey) error
return a.filters.Remove(filters...)
}
type ChatMessages struct {
Messages []*whisper.ReceivedMessage
type Message struct {
Message *whisper.ReceivedMessage // TODO: should it be whisper.Message?
Public bool
ChatID string
}
func (a *WhisperServiceTransport) RetrieveAllMessages() ([]ChatMessages, error) {
chatMessages := make(map[string]ChatMessages)
func (a *WhisperServiceTransport) RetrieveAllMessages() ([]Message, error) {
var messages []Message
for _, filter := range a.filters.Filters() {
f := a.shh.GetFilter(filter.FilterID)
@ -195,18 +194,15 @@ func (a *WhisperServiceTransport) RetrieveAllMessages() ([]ChatMessages, error)
return nil, errors.New("failed to return a filter")
}
ch := chatMessages[filter.ChatID]
ch.ChatID = filter.ChatID
ch.Public = filter.IsPublic()
ch.Messages = append(ch.Messages, f.Retrieve()...)
chatMessages[filter.ChatID] = ch
for _, m := range f.Retrieve() {
messages = append(messages, Message{
Message: m,
Public: filter.IsPublic(),
})
}
}
var result []ChatMessages
for _, messages := range chatMessages {
result = append(result, messages)
}
return result, nil
return messages, nil
}
func (a *WhisperServiceTransport) RetrievePublicMessages(chatID string) ([]*whisper.ReceivedMessage, error) {
@ -245,6 +241,7 @@ func (a *WhisperServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.Publi
}
// DEPRECATED
// Use RetrieveAllMessages instead.
func (a *WhisperServiceTransport) RetrieveRawAll() (map[Filter][]*whisper.ReceivedMessage, error) {
result := make(map[Filter][]*whisper.ReceivedMessage)

View File

@ -78,8 +78,7 @@ type Message struct {
Flags Flags `json:"-"`
ID []byte `json:"-"`
SigPubKey *ecdsa.PublicKey `json:"-"`
ChatID string `json:"-"`
Public bool `json:"-"`
ChatID string `json:"-"` // reference to Chat.ID; not connected to Content.ChatID which is set by sender
}
func (m *Message) MarshalJSON() ([]byte, error) {
@ -113,7 +112,8 @@ func createTextMessage(data []byte, lastClock int64, chatID, messageType string)
// CreatePublicTextMessage creates a public text Message.
func CreatePublicTextMessage(data []byte, lastClock int64, chatID string) Message {
return createTextMessage(data, lastClock, chatID, MessageTypePublicGroup)
m := createTextMessage(data, lastClock, chatID, MessageTypePublicGroup)
return m
}
// CreatePrivateTextMessage creates a public text Message.

View File

@ -4,12 +4,11 @@ import (
"crypto/ecdsa"
"log"
"github.com/pkg/errors"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/golang/protobuf/proto"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/status-im/status-protocol-go/applicationmetadata"
"github.com/status-im/status-protocol-go/datasync"
"github.com/status-im/status-protocol-go/encryption"
@ -18,7 +17,7 @@ import (
// StatusMessage is any Status Protocol message.
type StatusMessage struct {
// TransportMessage is the parsed message received from the trasport layer, i.e the input
// TransportMessage is the parsed message received from the transport layer, i.e the input
TransportMessage *whisper.Message
// ParsedMessage is the parsed message by the application layer, i.e the output
ParsedMessage interface{}