Handle membership update message

This commit does a few things:

1) Handle membership updates using protobuf and adds the relevant
endpoints.
2) Store in memory a map of chats + contacts for faster lookups, which
are then flushed to disk on each update
3) Validate incoming messages

Sorry for the large pr, but you know, v1 :)
This commit is contained in:
Andrea Maria Piana 2019-12-02 16:34:05 +01:00
parent e249f35a8d
commit baa0767c26
No known key found for this signature in database
GPG key ID: AA6CCA6DE0E06424
90 changed files with 5689 additions and 3769 deletions

View file

@ -1 +1 @@
0.37.3
0.38.0

11
go.mod
View file

@ -8,7 +8,7 @@ replace github.com/Sirupsen/logrus v1.4.2 => github.com/sirupsen/logrus v1.4.2
replace github.com/docker/docker => github.com/docker/engine v1.4.2-0.20190717161051-705d9623b7c1
replace github.com/gomarkdown/markdown => github.com/status-im/markdown v0.0.0-20191113114344-af599402d015
replace github.com/gomarkdown/markdown => github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba
replace github.com/status-im/status-go/protocol => ./protocol
@ -20,16 +20,12 @@ replace github.com/status-im/status-go/whisper/v6 => ./whisper
require (
github.com/beevik/ntp v0.2.0
github.com/elastic/gosigar v0.10.5 // indirect
github.com/ethereum/go-ethereum v1.9.5
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/golang-migrate/migrate/v4 v4.7.0 // indirect
github.com/golang/mock v1.3.1
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/lib/pq v1.2.0
github.com/libp2p/go-libp2p v0.4.0 // indirect
github.com/libp2p/go-libp2p v0.4.0 // indirect; indirect
github.com/libp2p/go-libp2p-core v0.2.3
github.com/multiformats/go-multiaddr v0.1.1
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
@ -40,7 +36,6 @@ require (
github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315 // indirect
github.com/russolsen/same v0.0.0-20160222130632-f089df61f51d // indirect
github.com/russolsen/transit v0.0.0-20180705123435-0794b4c4505a
github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0 // indirect
github.com/status-im/migrate/v4 v4.6.2-status.2
github.com/status-im/rendezvous v1.3.0
github.com/status-im/status-go/eth-node v1.0.0
@ -52,8 +47,6 @@ require (
github.com/syndtr/goleveldb v1.0.0
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/go-playground/validator.v9 v9.29.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0

19
go.sum
View file

@ -128,9 +128,8 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa h1:o8OuEkracbk3qH6GvlI6XpEN1HTSxkzOG42xZpfDv/s=
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo=
github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo=
github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/ethereum/go-ethereum v1.8.20/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
@ -144,8 +143,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gizak/termui v0.0.0-20170117222342-991cd3d38091/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@ -172,8 +169,6 @@ github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k=
github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0=
github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs=
github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -282,8 +277,6 @@ github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2vi
github.com/karalabe/hid v0.0.0-20181128192157-d815e0c1a2e2/go.mod h1:YvbcH+3Wo6XPs9nkgTY3u19KXLauXW+J5nB7hEHuX0A=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 h1:VhnqxaTIudc9IWKx8uXRLnpdSb9noCEj+vHacjmhp68=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 h1:ZHuwnjpP8LsVsUYqTqeVAI+GfDfJ6UNPrExZF+vX/DQ=
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@ -601,10 +594,8 @@ github.com/status-im/go-multiaddr-ethv4 v1.2.0 h1:OT84UsUzTCwguqCpJqkrCMiL4VZ1Sv
github.com/status-im/go-multiaddr-ethv4 v1.2.0/go.mod h1:2VQ3C+9zEurcceasz12gPAtmEzCeyLUGPeKLSXYQKHo=
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0 h1:5UdlDkkBoPrJfh7zkfoR3X5utJhNs/MCQysK3x0ycgg=
github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/markdown v0.0.0-20191113114344-af599402d015 h1:ijC73VP0hucsy/MRn4cmtoQVB1mKdLcvurMYPvmPc4Y=
github.com/status-im/markdown v0.0.0-20191113114344-af599402d015/go.mod h1:tmG2bxyvZ2EItDO5JewbdFvV45j13IYQgvnMJ3+qAaE=
github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba h1:Ut2CKuG+L9eWFL7dTEPuLE+RKecUYBkDNhqXSIgY92U=
github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba/go.mod h1:tmG2bxyvZ2EItDO5JewbdFvV45j13IYQgvnMJ3+qAaE=
github.com/status-im/migrate/v4 v4.6.2-status.2 h1:SdC+sMDl/aI7vUlwD2qj2p7KsK4T60IS9z4/rYCCbI8=
github.com/status-im/migrate/v4 v4.6.2-status.2/go.mod h1:c/kc90n47GZu/58nnz1OMLTf7uE4Da4gZP5qmU+A/v8=
github.com/status-im/rendezvous v1.3.0 h1:7RK/MXXW+tlm0asKm1u7Qp7Yni6AO29a7j8+E4Lbjg4=
@ -727,8 +718,6 @@ golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -739,8 +728,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View file

@ -86,7 +86,7 @@ func _0001_accountsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1573216280, 0)}
info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0x61, 0x4c, 0x18, 0xfc, 0xc, 0xdf, 0x5c, 0x1f, 0x5e, 0xd3, 0xbd, 0xfa, 0x12, 0x5e, 0x8d, 0x8d, 0x8b, 0xb9, 0x5f, 0x99, 0x46, 0x63, 0xa5, 0xe3, 0xa6, 0x8a, 0x4, 0xf1, 0x73, 0x8a, 0xe9}}
return a, nil
}
@ -106,7 +106,7 @@ func _0001_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1575565817, 0)}
info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1575903446, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf2, 0xfa, 0x99, 0x8e, 0x96, 0xb3, 0x13, 0x6c, 0x1f, 0x6, 0x27, 0xc5, 0xd2, 0xd4, 0xe0, 0xa5, 0x26, 0x82, 0xa7, 0x26, 0xf2, 0x68, 0x9d, 0xed, 0x9c, 0x3d, 0xbb, 0xdc, 0x37, 0x28, 0xbc, 0x1}}
return a, nil
}
@ -126,7 +126,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1573216280, 0)}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x7c, 0x28, 0xcd, 0x47, 0xf2, 0xfa, 0x7c, 0x51, 0x2d, 0xd8, 0x38, 0xb, 0xb0, 0x34, 0x9d, 0x4c, 0x62, 0xa, 0x9e, 0x28, 0xc3, 0x31, 0x23, 0xd9, 0xbb, 0x89, 0x9f, 0xa0, 0x89, 0x1f, 0xe8}}
return a, nil
}

View file

@ -5,12 +5,23 @@ import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
"math/rand"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
var chatColors = []string{
"#fa6565", // red
"#887af9", // blue
"#FE8F59", // orange
"#7cda00", // green
"#51d0f0", // light-blue
"#d37ef4", // purple
}
type ChatType int
const (
@ -31,9 +42,6 @@ type Chat struct {
ChatType ChatType `json:"chatType"`
// Only filled for one to one chats
PublicKey *ecdsa.PublicKey `json:"-"`
// Timestamp indicates the last time this chat has received/sent a message
Timestamp int64 `json:"timestamp"`
// LastClockValue indicates the last clock value to be used when sending messages
@ -50,7 +58,21 @@ type Chat struct {
// Members are the members who have been invited to the group chat
Members []ChatMember `json:"members"`
// MembershipUpdates is all the membership events in the chat
MembershipUpdates []ChatMembershipUpdate `json:"membershipUpdates"`
MembershipUpdates []v1protocol.MembershipUpdateEvent `json:"membershipUpdateEvents"`
}
func (c *Chat) PublicKey() (*ecdsa.PublicKey, error) {
// For one to one chatID is an encoded public key
if c.ChatType != ChatTypeOneToOne {
return nil, nil
}
pkey, err := hex.DecodeString(c.ID[2:])
if err != nil {
return nil, err
}
// Safety check, make sure is well formed
return crypto.UnmarshalPubkey(pkey)
}
func (c *Chat) MarshalJSON() ([]byte, error) {
@ -131,30 +153,15 @@ func (c *Chat) updateChatFromProtocolGroup(g *v1protocol.Group) {
c.Members = chatMembers
// MembershipUpdates
updates := g.Updates()
membershipUpdates := make([]ChatMembershipUpdate, 0, len(updates))
for _, update := range updates {
membershipUpdate := ChatMembershipUpdate{
Type: update.Type,
Name: update.Name,
ClockValue: uint64(update.ClockValue), // TODO: get rid of type casting
Signature: update.Signature,
From: update.From,
Member: update.Member,
Members: update.Members,
}
membershipUpdate.setID()
membershipUpdates = append(membershipUpdates, membershipUpdate)
}
c.MembershipUpdates = membershipUpdates
c.MembershipUpdates = g.Events()
}
// ChatMembershipUpdate represent an event on membership of the chat
type ChatMembershipUpdate struct {
// Unique identifier for the event
ID string `json:"id"`
// Type indicates the kind of event (i.e changed-name, added-member, etc)
Type string `json:"type"`
// Type indicates the kind of event
Type protobuf.MembershipUpdateEvent_EventType `json:"type"`
// Name represents the name in the event of changing name events
Name string `json:"name,omitempty"`
// Clock value of the event
@ -198,11 +205,10 @@ func oneToOneChatID(publicKey *ecdsa.PublicKey) string {
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey) Chat {
return Chat{
ID: oneToOneChatID(publicKey),
Name: name,
Active: true,
ChatType: ChatTypeOneToOne,
PublicKey: publicKey,
ID: oneToOneChatID(publicKey),
Name: name,
Active: true,
ChatType: ChatTypeOneToOne,
}
}
@ -211,14 +217,17 @@ func CreatePublicChat(name string) Chat {
ID: name,
Name: name,
Active: true,
Color: chatColors[rand.Intn(len(chatColors))],
ChatType: ChatTypePublic,
}
}
func createGroupChat() Chat {
return Chat{
Active: true,
ChatType: ChatTypePrivateGroupChat,
Active: true,
Color: chatColors[rand.Intn(len(chatColors))],
Timestamp: int64(timestampInMs()),
ChatType: ChatTypePrivateGroupChat,
}
}

View file

@ -5,24 +5,5 @@ import (
)
func newProtocolGroupFromChat(chat *Chat) (*v1protocol.Group, error) {
return v1protocol.NewGroup(chat.ID, chatToFlattenMembershipUpdate(chat))
}
func chatToFlattenMembershipUpdate(chat *Chat) []v1protocol.MembershipUpdateFlat {
result := make([]v1protocol.MembershipUpdateFlat, len(chat.MembershipUpdates))
for idx, update := range chat.MembershipUpdates {
result[idx] = v1protocol.MembershipUpdateFlat{
ChatID: chat.ID,
From: update.From,
Signature: update.Signature,
MembershipUpdateEvent: v1protocol.MembershipUpdateEvent{
Name: update.Name,
Type: update.Type,
ClockValue: int64(update.ClockValue), // TODO: remove type difference
Member: update.Member,
Members: update.Members,
},
}
}
return result
return v1protocol.NewGroup(chat.ID, chat.MembershipUpdates)
}

View file

@ -4,7 +4,7 @@ go 1.13
replace github.com/ethereum/go-ethereum v1.9.5 => github.com/status-im/go-ethereum v1.9.5-status.7
replace github.com/gomarkdown/markdown => github.com/status-im/markdown v0.0.0-20191113114344-af599402d015
replace github.com/gomarkdown/markdown => github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba
replace github.com/status-im/status-go/eth-node => ../eth-node
@ -14,11 +14,10 @@ require (
github.com/cenkalti/backoff/v3 v3.0.0
github.com/ethereum/go-ethereum v1.9.5
github.com/golang/protobuf v1.3.2
github.com/gomarkdown/markdown v0.0.0-20191113114344-af599402d015
github.com/gomarkdown/markdown v0.0.0-20191209105822-e3ba6c6109ba
github.com/google/uuid v1.1.1
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
github.com/lucasb-eyer/go-colorful v1.0.2
github.com/mattn/go-pointer v0.0.0-20190911064623-a0a44394634f
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
github.com/pkg/errors v0.8.1
github.com/russolsen/transit v0.0.0-20180705123435-0794b4c4505a
@ -29,5 +28,4 @@ require (
github.com/stretchr/testify v1.4.0
github.com/vacp2p/mvds v0.0.23
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba
)

View file

@ -34,9 +34,8 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:
github.com/aristanetworks/goarista v0.0.0-20181002214814-33151c4543a7/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0=
github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708 h1:tS7jSmwRqSxTnonTRlDD1oHo6Q9YOK4xHS9/v4L56eg=
github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7 h1:fKnuvQ/O22ZpD7HaJjGQXn/GxOdDJOQFL8bpM8Xe3X8=
github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
@ -49,6 +48,8 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR
github.com/btcsuite/btcd v0.0.0-20181013004428-67e573d211ac/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.0.0-20190418232430-6867ff32788a/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
@ -124,6 +125,8 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo=
github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo=
github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/ethereum/go-ethereum v1.8.20/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
@ -136,6 +139,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gizak/termui v0.0.0-20170117222342-991cd3d38091/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
@ -145,10 +150,10 @@ github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2i
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-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
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=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
@ -160,6 +165,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k=
github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0=
github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs=
github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@ -254,6 +261,8 @@ github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2vi
github.com/karalabe/hid v0.0.0-20181128192157-d815e0c1a2e2/go.mod h1:YvbcH+3Wo6XPs9nkgTY3u19KXLauXW+J5nB7hEHuX0A=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 h1:VhnqxaTIudc9IWKx8uXRLnpdSb9noCEj+vHacjmhp68=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 h1:ZHuwnjpP8LsVsUYqTqeVAI+GfDfJ6UNPrExZF+vX/DQ=
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@ -270,8 +279,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -359,8 +368,14 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex
github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg=
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -373,8 +388,26 @@ github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVq
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
github.com/multiformats/go-multiaddr-dns v0.1.0/go.mod h1:01k2RAqtoXIuPa3DCavAE9/6jc6nM0H3EgZyfUhN2oY=
github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=
github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik=
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg=
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f h1:hd3r+uv9DNLScbOrnlj82rBldHQf3XWmCeXAWbw8euQ=
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f/go.mod h1:MyUWrZlB1aI5bs7j9/pJ8ckLLZ4QcCYcNiSbsAW32D4=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@ -480,21 +513,27 @@ github.com/status-im/doubleratchet v3.0.0+incompatible h1:aJ1ejcSERpSzmWZBgtfYti
github.com/status-im/doubleratchet v3.0.0+incompatible/go.mod h1:1sqR0+yhiM/bd+wrdX79AOt2csZuJOni0nUDzKNuqOU=
github.com/status-im/go-ethereum v1.9.5-status.6 h1:ytuTO1yBIAuTVRtRQoc2mrdyngtP+XOQ9IHIibbz7/I=
github.com/status-im/go-ethereum v1.9.5-status.6/go.mod h1:08JvQWE+IOnAFSe4UD4ACLNe2fDd9XmWMCq5Yzy9mk0=
github.com/status-im/go-ethereum v1.9.5-status.7 h1:DKH1GiF52LwaZaw6YDBliFEgm/JDsbIT+hn7ph6X94Q=
github.com/status-im/go-ethereum v1.9.5-status.7/go.mod h1:YyH5DKB6+z+Vaya7eIm67pnuPZ1oiUMbbsZW41ktN0g=
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/markdown v0.0.0-20191113114344-af599402d015 h1:ijC73VP0hucsy/MRn4cmtoQVB1mKdLcvurMYPvmPc4Y=
github.com/status-im/markdown v0.0.0-20191113114344-af599402d015/go.mod h1:tmG2bxyvZ2EItDO5JewbdFvV45j13IYQgvnMJ3+qAaE=
github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0 h1:5UdlDkkBoPrJfh7zkfoR3X5utJhNs/MCQysK3x0ycgg=
github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba h1:Ut2CKuG+L9eWFL7dTEPuLE+RKecUYBkDNhqXSIgY92U=
github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba/go.mod h1:tmG2bxyvZ2EItDO5JewbdFvV45j13IYQgvnMJ3+qAaE=
github.com/status-im/migrate/v4 v4.6.2-status.2 h1:SdC+sMDl/aI7vUlwD2qj2p7KsK4T60IS9z4/rYCCbI8=
github.com/status-im/migrate/v4 v4.6.2-status.2/go.mod h1:c/kc90n47GZu/58nnz1OMLTf7uE4Da4gZP5qmU+A/v8=
github.com/status-im/rendezvous v1.3.0/go.mod h1:+hzjuP+j/XzLPeF6E50b88pWOTLdTcwjvNYt+Gh1W1s=
github.com/status-im/status-go v0.36.0 h1:91qDMJjHv+T3Li9FwxsWQ2JBVcYtvVDT0nGFSMnmM+8=
github.com/status-im/status-go v0.36.1 h1:nb9eTq0UQJ57YyTZSl5U05emFT+R4AW8/Bga6ocgOks=
github.com/status-im/status-go v0.37.3 h1:94/bOA8qrEIgWd23mSLN39SwUJwCu2TPQFV2HzSI2ZE=
github.com/status-im/status-go v0.37.3/go.mod h1:9qHQ2+8NS6ivPJS5YbsI3gWkr0t6DWmJzKnr4M7vudw=
github.com/status-im/status-go/extkeys v1.0.0 h1:Qyirsoi5Ye5UFfisgPtCjPb/RkBxyK+UsSiEcr2PVlM=
github.com/status-im/status-go/extkeys v1.0.0/go.mod h1:GdqJbrcpkNm5ZsSCpp+PdMxnXx+OcRBdm3PI0rs1FpU=
github.com/status-im/status-go/protocol v1.0.1/go.mod h1:LpA7BsaNmj6EOdq7BwuqncewjPqIRHCletZOb2wlWrY=
github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501/go.mod h1:RYo/itke1oU5k/6sj9DNM3QAwtE5rZSgg5JnkOv83hk=
github.com/status-im/whisper v1.5.2 h1:26NgiKusmPic38eQdtXnaY+iaQ/LuQ3Dh0kCGYT/Uxs=
github.com/status-im/whisper v1.5.2/go.mod h1:emrOxzJme0k66QtbbQ2bdd3P8RCdLZ8sTD7SkwH1s2s=
github.com/status-im/whisper v1.6.1 h1:C/T1HQHZfUI2jbccf3yIe8yfkl435I3BILIKeNASJDc=
github.com/status-im/whisper v1.6.1/go.mod h1:lygchT4p9Y1/hR451OhNNqfinvy9EYEDxtXU2T/U30Q=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
@ -503,6 +542,7 @@ github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9C
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@ -604,8 +644,11 @@ golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/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-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -616,6 +659,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -629,8 +674,15 @@ golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=

View file

@ -0,0 +1,88 @@
package protocol
import (
"fmt"
"strings"
"time"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
var defaultSystemMessagesTranslations = map[protobuf.MembershipUpdateEvent_EventType]string{
protobuf.MembershipUpdateEvent_CHAT_CREATED: "{{from}} created the group {{name}}",
protobuf.MembershipUpdateEvent_NAME_CHANGED: "{{from}} changed the group's name to {{name}}",
protobuf.MembershipUpdateEvent_MEMBERS_ADDED: "{{from}} has invited {{members}}",
protobuf.MembershipUpdateEvent_MEMBER_JOINED: "{{from}} joined the group",
protobuf.MembershipUpdateEvent_ADMINS_ADDED: "{{from}} has made {{members}} admin",
protobuf.MembershipUpdateEvent_MEMBER_REMOVED: "{{member}} left the group",
protobuf.MembershipUpdateEvent_ADMIN_REMOVED: "{{member}} is not admin anymore",
}
func tsprintf(format string, params map[string]string) string {
for key, val := range params {
format = strings.Replace(format, "{{"+key+"}}", fmt.Sprintf("%s", val), -1)
}
return fmt.Sprintf(format)
}
func eventToSystemMessage(e v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) *Message {
var text string
switch e.Type {
case protobuf.MembershipUpdateEvent_CHAT_CREATED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_CHAT_CREATED], map[string]string{"from": "@" + e.From, "name": e.Name})
case protobuf.MembershipUpdateEvent_NAME_CHANGED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_NAME_CHANGED], map[string]string{"from": "@" + e.From, "name": e.Name})
case protobuf.MembershipUpdateEvent_MEMBERS_ADDED:
var memberMentions []string
for _, s := range e.Members {
memberMentions = append(memberMentions, "@"+s)
}
text = tsprintf(translations[protobuf.MembershipUpdateEvent_MEMBERS_ADDED], map[string]string{"from": "@" + e.From, "members": strings.Join(memberMentions, ", ")})
case protobuf.MembershipUpdateEvent_MEMBER_JOINED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_MEMBER_JOINED], map[string]string{"from": "@" + e.From})
case protobuf.MembershipUpdateEvent_ADMINS_ADDED:
var memberMentions []string
for _, s := range e.Members {
memberMentions = append(memberMentions, "@"+s)
}
text = tsprintf(translations[protobuf.MembershipUpdateEvent_ADMINS_ADDED], map[string]string{"from": "@" + e.From, "members": strings.Join(memberMentions, ", ")})
case protobuf.MembershipUpdateEvent_MEMBER_REMOVED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_MEMBER_REMOVED], map[string]string{"member": "@" + e.Members[0]})
case protobuf.MembershipUpdateEvent_ADMIN_REMOVED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_ADMIN_REMOVED], map[string]string{"member": "@" + e.Members[0]})
}
timestamp := v1protocol.TimestampInMsFromTime(time.Now())
message := &Message{
ChatMessage: protobuf.ChatMessage{
ChatId: e.ChatID,
Text: text,
MessageType: protobuf.ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
Clock: e.ClockValue,
Timestamp: timestamp,
},
From: e.From,
WhisperTimestamp: timestamp,
LocalChatID: e.ChatID,
Seen: true,
ID: types.EncodeHex(crypto.Keccak256(e.Signature)),
}
message.PrepareContent()
return message
}
func buildSystemMessages(events []v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) []*Message {
var messages []*Message
for _, e := range events {
messages = append(messages, eventToSystemMessage(e, translations))
}
return messages
}

View file

@ -3,66 +3,44 @@ package protocol
import (
"github.com/pkg/errors"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
type persistentMessageHandler struct {
persistence *sqlitePersistence
}
func newPersistentMessageHandler(persistence *sqlitePersistence) *persistentMessageHandler {
return &persistentMessageHandler{persistence: persistence}
}
// HandleMembershipUpdate updates a Chat instance according to the membership updates.
// It retrieves chat, if exists, and merges membership updates from the message.
// Finally, the Chat is updated with the new group events.
func (h *persistentMessageHandler) HandleMembershipUpdate(m v1protocol.MembershipUpdateMessage) error {
chat, err := h.chatID(m.ChatID)
switch err {
case errChatNotFound:
group, err := v1protocol.NewGroupWithMembershipUpdates(m.ChatID, m.Updates)
func HandleMembershipUpdate(chat *Chat, m *v1protocol.MembershipUpdateMessage, myIdentity string, translations map[protobuf.MembershipUpdateEvent_EventType]string) (*Chat, []*Message, error) {
if chat == nil {
if len(m.Events) == 0 {
return nil, nil, errors.New("can't create new group chat without events")
}
group, err := v1protocol.NewGroupWithEvents(m.ChatID, m.Events)
if err != nil {
return err
return nil, nil, err
}
// A new chat must contain us
if !group.IsMember(myIdentity) {
return nil, nil, errors.New("can't create a new group chat without us being a member")
}
newChat := createGroupChat()
newChat.updateChatFromProtocolGroup(group)
chat = &newChat
case nil:
existingGroup, err := newProtocolGroupFromChat(chat)
if err != nil {
return errors.Wrap(err, "failed to create a Group from Chat")
}
updateGroup, err := v1protocol.NewGroupWithMembershipUpdates(m.ChatID, m.Updates)
if err != nil {
return errors.Wrap(err, "invalid membership update")
}
merged := v1protocol.MergeFlatMembershipUpdates(existingGroup.Updates(), updateGroup.Updates())
newGroup, err := v1protocol.NewGroup(chat.ID, merged)
if err != nil {
return errors.Wrap(err, "failed to create a group with new membership updates")
}
chat.updateChatFromProtocolGroup(newGroup)
default:
return err
return &newChat, buildSystemMessages(m.Events, translations), nil
}
return h.persistence.SaveChat(*chat)
}
func (h *persistentMessageHandler) chatID(chatID string) (*Chat, error) {
var chat *Chat
chats, err := h.persistence.Chats()
existingGroup, err := newProtocolGroupFromChat(chat)
if err != nil {
return nil, err
return nil, nil, errors.Wrap(err, "failed to create a Group from Chat")
}
for _, ch := range chats {
if ch.ID == chatID {
chat = ch
break
}
updateGroup, err := v1protocol.NewGroupWithEvents(m.ChatID, m.Events)
if err != nil {
return nil, nil, errors.Wrap(err, "invalid membership update")
}
if chat == nil {
return nil, errChatNotFound
merged := v1protocol.MergeMembershipUpdateEvents(existingGroup.Events(), updateGroup.Events())
newGroup, err := v1protocol.NewGroup(chat.ID, merged)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create a group with new membership updates")
}
return chat, nil
chat.updateChatFromProtocolGroup(newGroup)
return chat, buildSystemMessages(m.Events, translations), nil
}

View file

@ -0,0 +1,78 @@
package protocol
import (
v1protocol "github.com/status-im/status-go/protocol/v1"
"github.com/stretchr/testify/suite"
"testing"
)
func TestEventToSystemMessageSuite(t *testing.T) {
suite.Run(t, new(EventToSystemMessageSuite))
}
type EventToSystemMessageSuite struct {
suite.Suite
}
func (s *EventToSystemMessageSuite) TestRun() {
testCases := []struct {
Name string
Event v1protocol.MembershipUpdateEvent
Expected string
From string
}{
{
Name: "chat created event",
Event: v1protocol.NewChatCreatedEvent("chat-name", 12),
From: "admin",
Expected: "@admin created the group chat-name",
},
{
Name: "chat name changed event",
Event: v1protocol.NewNameChangedEvent("chat-name-2", 12),
From: "admin",
Expected: "@admin changed the group's name to chat-name-2",
},
{
Name: "members added event",
Event: v1protocol.NewMembersAddedEvent([]string{"a", "b", "c"}, 12),
From: "admin",
Expected: "@admin has invited @a, @b, @c",
},
{
Name: "member joined event",
Event: v1protocol.NewMemberJoinedEvent(12),
From: "admin",
Expected: "@admin joined the group",
},
{
Name: "admins added event",
Event: v1protocol.NewAdminsAddedEvent([]string{"a", "b", "c"}, 12),
From: "admin",
Expected: "@admin has made @a, @b, @c admin",
},
{
Name: "member removed event",
Event: v1protocol.NewMemberRemovedEvent("a", 12),
From: "admin",
Expected: "@a left the group",
},
{
Name: "admin removed event",
Event: v1protocol.NewAdminRemovedEvent("a", 12),
From: "admin",
Expected: "@a is not admin anymore",
},
}
for _, tc := range testCases {
s.Run(tc.Name, func() {
tc.Event.From = tc.From
systemMessage := eventToSystemMessage(tc.Event, defaultSystemMessagesTranslations)
s.Equal(systemMessage.Text, tc.Expected)
})
}
}

View file

@ -14,6 +14,7 @@ import (
datasyncpeer "github.com/status-im/status-go/protocol/datasync/peer"
"github.com/status-im/status-go/protocol/encryption"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/protobuf"
transport "github.com/status-im/status-go/protocol/transport/whisper"
v1protocol "github.com/status-im/status-go/protocol/v1"
datasyncnode "github.com/vacp2p/mvds/node"
@ -28,16 +29,11 @@ const (
whisperPoWTime = 5
)
type messageHandler interface {
HandleMembershipUpdate(m v1protocol.MembershipUpdateMessage) error
}
type messageProcessor struct {
identity *ecdsa.PrivateKey
datasync *datasync.DataSync
protocol *encryption.Protocol
transport *transport.WhisperServiceTransport
handler messageHandler
logger *zap.Logger
featureFlags featureFlags
@ -48,7 +44,6 @@ func newMessageProcessor(
database *sql.DB,
enc *encryption.Protocol,
transport *transport.WhisperServiceTransport,
handler messageHandler,
logger *zap.Logger,
features featureFlags,
) (*messageProcessor, error) {
@ -71,7 +66,6 @@ func newMessageProcessor(
datasync: ds,
protocol: enc,
transport: transport,
handler: handler,
logger: logger,
featureFlags: features,
}
@ -97,13 +91,14 @@ func (p *messageProcessor) SendPrivateRaw(
ctx context.Context,
recipient *ecdsa.PublicKey,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
p.logger.Debug(
"sending a private message",
zap.Binary("public-key", crypto.FromECDSAPub(recipient)),
zap.String("site", "SendPrivateRaw"),
)
return p.sendPrivate(ctx, recipient, data)
return p.sendPrivate(ctx, recipient, data, messageType)
}
// SendGroupRaw takes encoded data, encrypts it and sends through the wire,
@ -112,13 +107,14 @@ func (p *messageProcessor) SendGroupRaw(
ctx context.Context,
recipients []*ecdsa.PublicKey,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
p.logger.Debug(
"sending a private group message",
zap.String("site", "SendGroupRaw"),
)
// Calculate messageID first
wrappedMessage, err := p.wrapMessageV1(data)
wrappedMessage, err := p.wrapMessageV1(data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
@ -126,7 +122,7 @@ func (p *messageProcessor) SendGroupRaw(
messageID := v1protocol.MessageID(&p.identity.PublicKey, wrappedMessage)
for _, recipient := range recipients {
_, err = p.sendPrivate(ctx, recipient, data)
_, err = p.sendPrivate(ctx, recipient, data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to send message")
}
@ -139,10 +135,11 @@ func (p *messageProcessor) sendPrivate(
ctx context.Context,
recipient *ecdsa.PublicKey,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
p.logger.Debug("sending private message", zap.Binary("recipient", crypto.FromECDSAPub(recipient)))
wrappedMessage, err := p.wrapMessageV1(data)
wrappedMessage, err := p.wrapMessageV1(data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
@ -176,37 +173,34 @@ func (p *messageProcessor) sendPrivate(
func (p *messageProcessor) SendMembershipUpdate(
ctx context.Context,
recipients []*ecdsa.PublicKey,
chatID string,
updates []v1protocol.MembershipUpdate,
clock int64,
) ([][]byte, error) {
group *v1protocol.Group,
chatMessage *protobuf.ChatMessage,
) ([]byte, error) {
p.logger.Debug("sending a membership update", zap.Int("membersCount", len(recipients)))
message := v1protocol.MembershipUpdateMessage{
ChatID: chatID,
Updates: updates,
ChatID: group.ChatID(),
Events: group.Events(),
Message: chatMessage,
}
encodedMessage, err := v1protocol.EncodeMembershipUpdateMessage(message)
if err != nil {
return nil, errors.Wrap(err, "failed to encode membership update message")
}
var resultIDs [][]byte
for _, recipient := range recipients {
messageID, err := p.sendPrivate(ctx, recipient, encodedMessage)
if err != nil {
return nil, err
}
resultIDs = append(resultIDs, messageID)
}
return resultIDs, nil
return p.SendGroupRaw(ctx, recipients, encodedMessage, protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE)
}
// SendPublicRaw takes encoded data, encrypts it and sends through the wire.
func (p *messageProcessor) SendPublicRaw(ctx context.Context, chatName string, data []byte) ([]byte, error) {
func (p *messageProcessor) SendPublicRaw(
ctx context.Context,
chatName string,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
var newMessage *types.NewMessage
wrappedMessage, err := p.wrapMessageV1(data)
wrappedMessage, err := p.wrapMessageV1(data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
@ -230,16 +224,6 @@ func (p *messageProcessor) SendPublicRaw(ctx context.Context, chatName string, d
return messageID, nil
}
func (p *messageProcessor) processMembershipUpdate(m v1protocol.MembershipUpdateMessage) error {
if err := m.Verify(); err != nil {
return err
}
if p.handler != nil {
return p.handler.HandleMembershipUpdate(m)
}
return errors.New("missing handler")
}
func (p *messageProcessor) processPairMessage(m v1protocol.PairMessage) error {
metadata := &multidevice.InstallationMetadata{
Name: m.Name,
@ -336,8 +320,8 @@ func (p *messageProcessor) handleErrDeviceNotFound(ctx context.Context, publicKe
return nil
}
func (p *messageProcessor) wrapMessageV1(encodedMessage []byte) ([]byte, error) {
wrappedMessage, err := v1protocol.WrapMessageV1(encodedMessage, p.identity)
func (p *messageProcessor) wrapMessageV1(encodedMessage []byte, messageType protobuf.ApplicationMetadataMessage_Type) ([]byte, error) {
wrappedMessage, err := v1protocol.WrapMessageV1(encodedMessage, messageType, p.identity)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}

View file

@ -98,7 +98,6 @@ func (s *MessageProcessorSuite) SetupTest() {
database,
encryptionProtocol,
whisperTransport,
nil,
s.logger,
featureFlags{},
)
@ -120,7 +119,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesWrapped() {
encodedPayload, err := proto.Marshal(&s.testMessage)
s.Require().NoError(err)
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, authorKey)
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey)
s.Require().NoError(err)
message := &types.Message{}
@ -136,7 +135,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesWrapped() {
parsedMessage := decodedMessages[0].ParsedMessage.(protobuf.ChatMessage)
s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload)
s.Require().True(proto.Equal(&s.testMessage.ChatMessage, &parsedMessage))
s.Require().Equal(v1protocol.MessageT, decodedMessages[0].MessageType)
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type)
}
func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasync() {
@ -149,7 +148,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasync() {
encodedPayload, err := proto.Marshal(&s.testMessage)
s.Require().NoError(err)
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, authorKey)
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey)
s.Require().NoError(err)
dataSyncMessage := datasyncproto.Payload{
@ -173,7 +172,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasync() {
s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload)
parsedMessage := decodedMessages[0].ParsedMessage.(protobuf.ChatMessage)
s.Require().True(proto.Equal(&s.testMessage.ChatMessage, &parsedMessage))
s.Require().Equal(v1protocol.MessageT, decodedMessages[0].MessageType)
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type)
}
func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasyncEncrypted() {
@ -186,7 +185,7 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasyncEncrypted() {
encodedPayload, err := proto.Marshal(&s.testMessage)
s.Require().NoError(err)
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, authorKey)
wrappedPayload, err := v1protocol.WrapMessageV1(encodedPayload, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, authorKey)
s.Require().NoError(err)
dataSyncMessage := datasyncproto.Payload{
@ -234,5 +233,5 @@ func (s *MessageProcessorSuite) TestHandleDecodedMessagesDatasyncEncrypted() {
s.Require().Equal(encodedPayload, decodedMessages[0].DecryptedPayload)
parsedMessage := decodedMessages[0].ParsedMessage.(protobuf.ChatMessage)
s.Require().True(proto.Equal(&s.testMessage.ChatMessage, &parsedMessage))
s.Require().Equal(v1protocol.MessageT, decodedMessages[0].MessageType)
s.Require().Equal(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE, decodedMessages[0].Type)
}

View file

@ -0,0 +1,51 @@
package protocol
import (
"errors"
"github.com/status-im/status-go/protocol/protobuf"
"strings"
)
func ValidateReceivedChatMessage(message *protobuf.ChatMessage) error {
if message.Clock == 0 {
return errors.New("Clock can't be 0")
}
if message.Timestamp == 0 {
return errors.New("Timestamp can't be 0")
}
if len(strings.TrimSpace(message.Text)) == 0 {
return errors.New("Text can't be empty")
}
if len(message.ChatId) == 0 {
return errors.New("ChatId can't be empty")
}
if message.ContentType == protobuf.ChatMessage_UNKNOWN_CONTENT_TYPE {
return errors.New("Unknown content type")
}
if message.MessageType == protobuf.ChatMessage_UNKNOWN_MESSAGE_TYPE || message.MessageType == protobuf.ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP {
return errors.New("Unknown message type")
}
if message.ContentType == protobuf.ChatMessage_STICKER {
if message.Payload == nil {
return errors.New("No sticker content")
}
sticker := message.GetSticker()
if sticker == nil {
return errors.New("No sticker content")
}
if sticker.Pack == 0 {
return errors.New("Sticker pack not set")
}
if len(sticker.Hash) == 0 {
return errors.New("Sticker hash not set")
}
}
return nil
}

View file

@ -0,0 +1,260 @@
package protocol
import (
"testing"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/stretchr/testify/suite"
)
type MessageValidatorSuite struct {
suite.Suite
}
func TestMessageValidatorSuite(t *testing.T) {
suite.Run(t, new(MessageValidatorSuite))
}
func (s *MessageValidatorSuite) TestValidatePlainTextMessage() {
testCases := []struct {
Name string
Valid bool
Message protobuf.ChatMessage
}{
{
Name: "A valid message",
Valid: true,
Message: protobuf.ChatMessage{
ChatId: "a",
Clock: 1,
Timestamp: 2,
Text: "some-text",
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Missing chatId",
Valid: false,
Message: protobuf.ChatMessage{
Clock: 1,
Timestamp: 2,
Text: "some-text",
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Missing clock",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Timestamp: 2,
Text: "some-text",
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Missing timestamp",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Clock: 2,
Text: "some-text",
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Missing text",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Blank text",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: " \n \t \n ",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Unknown MessageType",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: "valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_UNKNOWN_MESSAGE_TYPE,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Unknown ContentType",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: "valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_UNKNOWN_CONTENT_TYPE,
},
},
{
Name: "System message MessageType",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: "valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
},
},
{
Name: "Valid emoji only emssage",
Valid: true,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: ":+1:",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_EMOJI,
},
},
// TODO: FIX ME
/* {
Name: "Invalid emoji only emssage",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: ":+1: not valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_EMOJI,
},
}
,*/
{
Name: "Valid sticker message",
Valid: true,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: "valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
Payload: &protobuf.ChatMessage_Sticker{
Sticker: &protobuf.StickerMessage{
Pack: 1,
Hash: "some-hash",
},
},
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_STICKER,
},
},
{
Name: "Invalid sticker message without Pack",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: "valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
Payload: &protobuf.ChatMessage_Sticker{
Sticker: &protobuf.StickerMessage{
Hash: "some-hash",
},
},
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_STICKER,
},
},
{
Name: "Invalid sticker message without Hash",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: "valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
Payload: &protobuf.ChatMessage_Sticker{
Sticker: &protobuf.StickerMessage{
Pack: 1,
},
},
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_STICKER,
},
},
{
Name: "Invalid sticker message without any content",
Valid: false,
Message: protobuf.ChatMessage{
ChatId: "a",
Text: "valid",
Clock: 2,
Timestamp: 3,
ResponseTo: "",
EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_STICKER,
},
},
}
for _, tc := range testCases {
s.Run(tc.Name, func() {
err := ValidateReceivedChatMessage(&tc.Message)
if tc.Valid {
s.Nil(err)
} else {
s.NotNil(err)
}
})
}
}

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@ import (
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/sqlite"
"github.com/status-im/status-go/protocol/tt"
v1protocol "github.com/status-im/status-go/protocol/v1"
"github.com/status-im/status-go/whisper/v6"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
@ -139,7 +140,7 @@ func (s *MessengerSuite) TestInit() {
ID: "some-public-chat",
Active: true,
}
err := s.m.SaveChat(publicChat)
err := s.m.SaveChat(&publicChat)
s.Require().NoError(err)
},
AddedFilters: 1,
@ -150,12 +151,11 @@ func (s *MessengerSuite) TestInit() {
key, err := crypto.GenerateKey()
s.Require().NoError(err)
privateChat := Chat{
ID: types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)),
ChatType: ChatTypeOneToOne,
PublicKey: &key.PublicKey,
Active: true,
ID: types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)),
ChatType: ChatTypeOneToOne,
Active: true,
}
err = s.m.SaveChat(privateChat)
err = s.m.SaveChat(&privateChat)
s.Require().NoError(err)
},
AddedFilters: 1,
@ -179,7 +179,7 @@ func (s *MessengerSuite) TestInit() {
},
},
}
err = s.m.SaveChat(groupChat)
err = s.m.SaveChat(&groupChat)
s.Require().NoError(err)
},
AddedFilters: 2,
@ -192,7 +192,7 @@ func (s *MessengerSuite) TestInit() {
ID: "some-public-chat-2",
Active: false,
}
err := s.m.SaveChat(publicChat)
err := s.m.SaveChat(&publicChat)
s.Require().NoError(err)
},
AddedFilters: 0,
@ -207,7 +207,7 @@ func (s *MessengerSuite) TestInit() {
Name: "Some Contact",
SystemTags: []string{contactAdded},
}
err = s.m.SaveContact(contact)
err = s.m.SaveContact(&contact)
s.Require().NoError(err)
},
AddedFilters: 1,
@ -222,7 +222,7 @@ func (s *MessengerSuite) TestInit() {
Name: "Some Contact",
SystemTags: []string{contactAdded, contactBlocked},
}
err = s.m.SaveContact(contact)
err = s.m.SaveContact(&contact)
s.Require().NoError(err)
},
AddedFilters: 0,
@ -237,7 +237,7 @@ func (s *MessengerSuite) TestInit() {
Name: "Some Contact",
SystemTags: []string{contactRequestReceived},
}
err = s.m.SaveContact(contact)
err = s.m.SaveContact(&contact)
s.Require().NoError(err)
},
AddedFilters: 0,
@ -262,7 +262,10 @@ func buildTestMessage(chat Chat) *Message {
message := &Message{}
message.Text = "text-input-message"
message.ChatId = chat.ID
message.Clock = 2
message.WhisperTimestamp = 10
message.LocalChatID = chat.ID
message.ContentType = protobuf.ChatMessage_TEXT_PLAIN
switch chat.ChatType {
case ChatTypePublic:
message.MessageType = protobuf.ChatMessage_PUBLIC_GROUP
@ -278,7 +281,7 @@ func buildTestMessage(chat Chat) *Message {
func (s *MessengerSuite) TestMarkMessagesSeen() {
chat := CreatePublicChat("test-chat")
chat.UnviewedMessagesCount = 2
err := s.m.SaveChat(chat)
err := s.m.SaveChat(&chat)
s.Require().NoError(err)
inputMessage1 := buildTestMessage(chat)
inputMessage1.ID = "1"
@ -293,8 +296,7 @@ func (s *MessengerSuite) TestMarkMessagesSeen() {
err = s.m.MarkMessagesSeen(chat.ID, []string{inputMessage1.ID})
s.Require().NoError(err)
chats, err := s.m.Chats()
s.Require().NoError(err)
chats := s.m.Chats()
s.Require().Len(chats, 1)
s.Require().Equal(uint(1), chats[0].UnviewedMessagesCount)
}
@ -302,7 +304,7 @@ func (s *MessengerSuite) TestMarkMessagesSeen() {
func (s *MessengerSuite) TestSendPublic() {
chat := CreatePublicChat("test-chat")
chat.LastClockValue = uint64(100000000000000)
err := s.m.SaveChat(chat)
err := s.m.SaveChat(&chat)
s.NoError(err)
inputMessage := buildTestMessage(chat)
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
@ -311,7 +313,8 @@ func (s *MessengerSuite) TestSendPublic() {
s.Require().Equal(1, len(response.Messages), "it returns the message")
outputMessage := response.Messages[0]
s.Require().Equal(chat.LastClockValue+1, outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), chat.LastClockValue, "it correctly sets the last-clock-value")
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
s.Require().True(outputMessage.Seen, "it marks the message as seen")
@ -333,14 +336,16 @@ func (s *MessengerSuite) TestSendPrivateOneToOne() {
inputMessage := &Message{}
inputMessage.ChatId = chat.ID
chat.LastClockValue = uint64(100000000000000)
err = s.m.SaveChat(chat)
err = s.m.SaveChat(&chat)
s.NoError(err)
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
s.NoError(err)
s.Require().Equal(1, len(response.Messages), "it returns the message")
outputMessage := response.Messages[0]
s.Require().Equal(chat.LastClockValue+1, outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), chat.LastClockValue, "it correctly sets the last-clock-value")
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
s.Require().True(outputMessage.Seen, "it marks the message as seen")
@ -349,50 +354,31 @@ func (s *MessengerSuite) TestSendPrivateOneToOne() {
s.Require().Equal(protobuf.ChatMessage_ONE_TO_ONE, outputMessage.MessageType)
}
func (s *MessengerSuite) TestAddSystemMessages() {
chat, err := s.m.CreateGroupChat("test")
s.NoError(err)
inputMessage := buildTestMessage(*chat)
inputMessage.Clock = 20
inputMessage.From = "0x" + hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey))
messages, err := s.m.AddSystemMessages([]*Message{inputMessage})
s.Require().NoError(err)
s.Require().Len(messages, 1)
actualMessage := messages[0]
s.Require().NotEmpty(actualMessage.ID)
s.Require().True(actualMessage.Seen)
s.Require().Empty(actualMessage.OutgoingStatus)
s.Require().NotEmpty(actualMessage.Timestamp)
s.Require().NotEmpty(actualMessage.WhisperTimestamp)
s.Require().Equal(chat.ID, actualMessage.LocalChatID)
s.Require().NotEmpty(actualMessage.Identicon)
s.Require().NotEmpty(actualMessage.Alias)
s.Require().Equal(protobuf.ChatMessage_STATUS, actualMessage.ContentType)
s.Require().Equal(protobuf.ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP, actualMessage.MessageType)
s.Require().NotEmpty(actualMessage.ParsedText)
}
func (s *MessengerSuite) TestSendPrivateGroup() {
chat, err := s.m.CreateGroupChat("test")
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
s.NoError(err)
s.Require().Len(response.Chats, 1)
chat := response.Chats[0]
key, err := crypto.GenerateKey()
s.NoError(err)
err = s.m.AddMembersToChat(context.Background(), chat, []*ecdsa.PublicKey{&key.PublicKey})
members := []string{"0x" + hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey))}
_, err = s.m.AddMembersToGroupChat(context.Background(), chat.ID, members)
s.NoError(err)
inputMessage := &Message{}
inputMessage.ChatId = chat.ID
chat.LastClockValue = uint64(100000000000000)
err = s.m.SaveChat(*chat)
err = s.m.SaveChat(chat)
s.NoError(err)
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
response, err = s.m.SendChatMessage(context.Background(), inputMessage)
s.NoError(err)
s.Require().Equal(1, len(response.Messages), "it returns the message")
outputMessage := response.Messages[0]
s.Require().Equal(chat.LastClockValue+1, outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), chat.LastClockValue, "it correctly sets the last-clock-value")
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
s.Require().True(outputMessage.Seen, "it marks the message as seen")
@ -402,20 +388,25 @@ func (s *MessengerSuite) TestSendPrivateGroup() {
}
func (s *MessengerSuite) TestSendPrivateEmptyGroup() {
chat, err := s.m.CreateGroupChat("test")
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
s.NoError(err)
s.Require().Len(response.Chats, 1)
chat := response.Chats[0]
inputMessage := &Message{}
inputMessage.ChatId = chat.ID
chat.LastClockValue = uint64(100000000000000)
err = s.m.SaveChat(*chat)
err = s.m.SaveChat(chat)
s.NoError(err)
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
response, err = s.m.SendChatMessage(context.Background(), inputMessage)
s.NoError(err)
s.Require().Equal(1, len(response.Messages), "it returns the message")
outputMessage := response.Messages[0]
s.Require().Equal(chat.LastClockValue+1, outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), outputMessage.Clock, "it correctly sets the clock")
s.Require().Equal(uint64(100000000000001), chat.LastClockValue, "it correctly sets the last-clock-value")
s.Require().NotEqual(uint64(0), chat.Timestamp, "it sets the timestamp")
s.Require().Equal("0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), outputMessage.From, "it sets the From field")
s.Require().True(outputMessage.Seen, "it marks the message as seen")
@ -427,7 +418,7 @@ func (s *MessengerSuite) TestSendPrivateEmptyGroup() {
// Make sure public messages sent by us are not
func (s *MessengerSuite) TestRetrieveOwnPublic() {
chat := CreatePublicChat("status")
err := s.m.SaveChat(chat)
err := s.m.SaveChat(&chat)
s.NoError(err)
// Right-to-left text
text := "پيل اندر خانه يي تاريک بود عرضه را آورده بودندش هنود i\nاز براي ديدنش مردم بسي اندر آن ظلمت همي شد هر کسي"
@ -462,11 +453,11 @@ func (s *MessengerSuite) TestRetrieveOwnPublic() {
func (s *MessengerSuite) TestRetrieveTheirPublic() {
theirMessenger := s.newMessenger(s.shh)
theirChat := CreatePublicChat("status")
err := theirMessenger.SaveChat(theirChat)
err := theirMessenger.SaveChat(&theirChat)
s.Require().NoError(err)
chat := CreatePublicChat("status")
err = s.m.SaveChat(chat)
err = s.m.SaveChat(&chat)
s.Require().NoError(err)
err = s.m.Join(chat)
@ -505,11 +496,11 @@ func (s *MessengerSuite) TestRetrieveTheirPublic() {
func (s *MessengerSuite) TestDeletedAtClockValue() {
theirMessenger := s.newMessenger(s.shh)
theirChat := CreatePublicChat("status")
err := theirMessenger.SaveChat(theirChat)
err := theirMessenger.SaveChat(&theirChat)
s.Require().NoError(err)
chat := CreatePublicChat("status")
err = s.m.SaveChat(chat)
err = s.m.SaveChat(&chat)
s.Require().NoError(err)
err = s.m.Join(chat)
@ -521,7 +512,7 @@ func (s *MessengerSuite) TestDeletedAtClockValue() {
s.NoError(err)
chat.DeletedAtClockValue = sentResponse.Messages[0].Clock
err = s.m.SaveChat(chat)
err = s.m.SaveChat(&chat)
s.Require().NoError(err)
// Wait for the message to reach its destination
@ -534,11 +525,11 @@ func (s *MessengerSuite) TestDeletedAtClockValue() {
func (s *MessengerSuite) TestRetrieveBlockedContact() {
theirMessenger := s.newMessenger(s.shh)
theirChat := CreatePublicChat("status")
err := theirMessenger.SaveChat(theirChat)
err := theirMessenger.SaveChat(&theirChat)
s.Require().NoError(err)
chat := CreatePublicChat("status")
err = s.m.SaveChat(chat)
err = s.m.SaveChat(&chat)
s.Require().NoError(err)
err = s.m.Join(chat)
@ -555,7 +546,7 @@ func (s *MessengerSuite) TestRetrieveBlockedContact() {
TributeToTalk: "talk",
}
s.Require().NoError(s.m.SaveContact(blockedContact))
s.Require().NoError(s.m.SaveContact(&blockedContact))
inputMessage := buildTestMessage(chat)
@ -573,11 +564,11 @@ func (s *MessengerSuite) TestRetrieveBlockedContact() {
func (s *MessengerSuite) TestResendPublicMessage() {
theirMessenger := s.newMessenger(s.shh)
theirChat := CreatePublicChat("status")
err := theirMessenger.SaveChat(theirChat)
err := theirMessenger.SaveChat(&theirChat)
s.Require().NoError(err)
chat := CreatePublicChat("status")
err = s.m.SaveChat(chat)
err = s.m.SaveChat(&chat)
s.Require().NoError(err)
err = s.m.Join(chat)
@ -632,14 +623,14 @@ func (s *MessengerSuite) TestResendPublicMessage() {
func (s *MessengerSuite) TestRetrieveTheirPrivateChatExisting() {
theirMessenger := s.newMessenger(s.shh)
theirChat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey)
err := theirMessenger.SaveChat(theirChat)
err := theirMessenger.SaveChat(&theirChat)
s.Require().NoError(err)
ourChat := CreateOneToOneChat("our-chat", &theirMessenger.identity.PublicKey)
ourChat.UnviewedMessagesCount = 1
// Make chat inactive
ourChat.Active = false
err = s.m.SaveChat(ourChat)
err = s.m.SaveChat(&ourChat)
s.Require().NoError(err)
inputMessage := buildTestMessage(theirChat)
@ -676,7 +667,7 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateChatExisting() {
func (s *MessengerSuite) TestRetrieveTheirPrivateChatNonExisting() {
theirMessenger := s.newMessenger(s.shh)
chat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey)
err := theirMessenger.SaveChat(chat)
err := theirMessenger.SaveChat(&chat)
s.NoError(err)
inputMessage := buildTestMessage(chat)
@ -715,7 +706,7 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateChatNonExisting() {
func (s *MessengerSuite) TestRetrieveOurPairedMessage() {
pairedMessenger := s.newMessengerWithKey(s.shh, s.privateKey)
chat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey)
err := pairedMessenger.SaveChat(chat)
err := pairedMessenger.SaveChat(&chat)
s.NoError(err)
inputMessage := buildTestMessage(chat)
@ -765,7 +756,7 @@ func (s *MessengerSuite) TestRetrieveOurPairedMessage() {
key, err := crypto.GenerateKey()
s.Require().NoError(err)
chat = CreateOneToOneChat("new-chat", &key.PublicKey)
err = s.m.SaveChat(chat)
err = s.m.SaveChat(&chat)
s.NoError(err)
inputMessage = buildTestMessage(chat)
@ -799,7 +790,7 @@ func (s *MessengerSuite) TestRetrieveOurPairedMessage() {
func (s *MessengerSuite) TestRetrieveTheirPublicChatNonExisting() {
theirMessenger := s.newMessenger(s.shh)
chat := CreatePublicChat("test-chat")
err := theirMessenger.SaveChat(chat)
err := theirMessenger.SaveChat(&chat)
s.NoError(err)
inputMessage := buildTestMessage(chat)
@ -817,13 +808,16 @@ func (s *MessengerSuite) TestRetrieveTheirPublicChatNonExisting() {
s.Require().Equal(len(response.Chats), 0)
}
// Test receiving a message on an non-existing public chat
// Test receiving a message on an non-existing private public chat
func (s *MessengerSuite) TestRetrieveTheirGroupChatNonExisting() {
theirMessenger := s.newMessenger(s.shh)
chat, err := theirMessenger.CreateGroupChat("test")
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
s.NoError(err)
s.Require().Len(response.Chats, 1)
err = theirMessenger.SaveChat(*chat)
chat := response.Chats[0]
err = theirMessenger.SaveChat(chat)
s.NoError(err)
inputMessage := buildTestMessage(*chat)
@ -832,31 +826,62 @@ func (s *MessengerSuite) TestRetrieveTheirGroupChatNonExisting() {
s.NoError(err)
s.Require().Len(sendResponse.Messages, 1)
// Wait for the message to reach its destination
time.Sleep(100 * time.Millisecond)
response, err := s.m.RetrieveAll()
s.NoError(err)
// Retrieve their messages so that the chat is created
err = tt.RetryWithBackOff(func() error {
var err error
response, err = s.m.RetrieveAll()
if err == nil && len(response.Chats) == 1 {
err = errors.New("chat membership update not received")
}
return err
})
s.Require().NoError(err)
s.Require().Equal(len(response.Messages), 0)
s.Require().Equal(len(response.Chats), 0)
// The message is discarded
s.Require().Equal(0, len(response.Messages))
s.Require().Equal(0, len(response.Chats))
}
// Test receiving a message on an existing private group chat
// Disable for now
func (s *MessengerSuite) testRetrieveTheirPrivateGroupChat() {
func (s *MessengerSuite) TestRetrieveTheirPrivateGroupChat() {
var response *MessengerResponse
theirMessenger := s.newMessenger(s.shh)
ourChat, err := s.m.CreateGroupChat("id")
err = s.m.SaveChat(*ourChat)
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "id", []string{})
s.NoError(err)
s.Require().Len(response.Chats, 1)
ourChat := response.Chats[0]
err = s.m.SaveChat(ourChat)
s.NoError(err)
err = s.m.AddMembersToChat(context.Background(), ourChat, []*ecdsa.PublicKey{&theirMessenger.identity.PublicKey})
members := []string{"0x" + hex.EncodeToString(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))}
_, err = s.m.AddMembersToGroupChat(context.Background(), ourChat.ID, members)
s.NoError(err)
err = theirMessenger.SaveChat(*ourChat)
// Retrieve their messages so that the chat is created
err = tt.RetryWithBackOff(func() error {
var err error
response, err = theirMessenger.RetrieveAll()
if err == nil && len(response.Chats) == 0 {
err = errors.New("chat invitation not received")
}
return err
})
s.Require().NoError(err)
_, err = theirMessenger.ConfirmJoiningGroup(context.Background(), ourChat.ID)
s.NoError(err)
err = theirMessenger.Join(*ourChat)
s.NoError(err)
err = tt.RetryWithBackOff(func() error {
var err error
response, err = s.m.RetrieveAll()
if err == nil && len(response.Chats) == 0 {
err = errors.New("no joining group event received")
}
return err
})
s.Require().NoError(err)
inputMessage := buildTestMessage(*ourChat)
@ -866,7 +891,6 @@ func (s *MessengerSuite) testRetrieveTheirPrivateGroupChat() {
sentMessage := sendResponse.Messages[0]
var response *MessengerResponse
err = tt.RetryWithBackOff(func() error {
var err error
response, err = s.m.RetrieveAll()
@ -887,14 +911,65 @@ func (s *MessengerSuite) testRetrieveTheirPrivateGroupChat() {
s.Require().NotNil(actualChat.LastMessage)
}
// Test it does not update the last message if clock value less then
// Test it does not return messages from blocked contacts
// Test it saves the messages
// Test it does not return the message for public if no chat is there
// Test returns contacts
// Test it does not return raw messages if all processed
// Test duplicate messages, don't update unviewed messages count, they are
// not passed back
// Test receiving a message on an existing private group chat, if messages
// are not wrapped this will fail as they'll likely come out of order
func (s *MessengerSuite) TestRetrieveTheirPrivateGroupWrappedMessageChat() {
var response *MessengerResponse
theirMessenger := s.newMessenger(s.shh)
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "id", []string{})
s.NoError(err)
s.Require().Len(response.Chats, 1)
ourChat := response.Chats[0]
err = s.m.SaveChat(ourChat)
s.NoError(err)
members := []string{"0x" + hex.EncodeToString(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))}
_, err = s.m.AddMembersToGroupChat(context.Background(), ourChat.ID, members)
s.NoError(err)
// Retrieve their messages so that the chat is created
err = tt.RetryWithBackOff(func() error {
var err error
response, err = theirMessenger.RetrieveAll()
if err == nil && len(response.Chats) == 0 {
err = errors.New("chat invitation not received")
}
return err
})
s.Require().NoError(err)
_, err = theirMessenger.ConfirmJoiningGroup(context.Background(), ourChat.ID)
s.NoError(err)
inputMessage := buildTestMessage(*ourChat)
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
s.NoError(err)
s.Require().Len(sendResponse.Messages, 1)
sentMessage := sendResponse.Messages[0]
err = tt.RetryWithBackOff(func() error {
var err error
response, err = s.m.RetrieveAll()
if err == nil && len(response.Messages) == 0 {
err = errors.New("no messages")
}
return err
})
s.Require().NoError(err)
s.Require().Len(response.Chats, 1)
actualChat := response.Chats[0]
// It updates the unviewed messages count
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
// It updates the last message clock value
s.Require().Equal(sentMessage.Clock, actualChat.LastClockValue)
// It sets the last message
s.Require().NotNil(actualChat.LastMessage)
}
func (s *MessengerSuite) TestChatPersistencePublic() {
chat := Chat{
@ -910,9 +985,8 @@ func (s *MessengerSuite) TestChatPersistencePublic() {
LastMessage: []byte("test"),
}
s.Require().NoError(s.m.SaveChat(chat))
savedChats, err := s.m.Chats()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveChat(&chat))
savedChats := s.m.Chats()
s.Require().Equal(1, len(savedChats))
actualChat := savedChats[0]
@ -936,14 +1010,12 @@ func (s *MessengerSuite) TestDeleteChat() {
LastMessage: []byte("test"),
}
s.Require().NoError(s.m.SaveChat(chat))
savedChats, err := s.m.Chats()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveChat(&chat))
savedChats := s.m.Chats()
s.Require().Equal(1, len(savedChats))
s.Require().NoError(s.m.DeleteChat(chatID))
savedChats, err = s.m.Chats()
s.Require().NoError(err)
savedChats = s.m.Chats()
s.Require().Equal(0, len(savedChats))
}
@ -961,9 +1033,8 @@ func (s *MessengerSuite) TestChatPersistenceUpdate() {
LastMessage: []byte("test"),
}
s.Require().NoError(s.m.SaveChat(chat))
savedChats, err := s.m.Chats()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveChat(&chat))
savedChats := s.m.Chats()
s.Require().Equal(1, len(savedChats))
actualChat := savedChats[0]
@ -972,9 +1043,8 @@ func (s *MessengerSuite) TestChatPersistenceUpdate() {
s.Require().Equal(expectedChat, actualChat)
chat.Name = "updated-name"
s.Require().NoError(s.m.SaveChat(chat))
updatedChats, err := s.m.Chats()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveChat(&chat))
updatedChats := s.m.Chats()
s.Require().Equal(1, len(updatedChats))
actualUpdatedChat := updatedChats[0]
@ -1003,14 +1073,17 @@ func (s *MessengerSuite) TestChatPersistenceOneToOne() {
pk, err := crypto.UnmarshalPubkey(publicKeyBytes)
s.Require().NoError(err)
s.Require().NoError(s.m.SaveChat(chat))
savedChats, err := s.m.Chats()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveChat(&chat))
savedChats := s.m.Chats()
s.Require().Equal(1, len(savedChats))
actualChat := savedChats[0]
expectedChat := &chat
expectedChat.PublicKey = pk
actualPk, err := actualChat.PublicKey()
s.Require().NoError(err)
s.Require().Equal(pk, actualPk)
s.Require().Equal(expectedChat, actualChat)
}
@ -1040,25 +1113,21 @@ func (s *MessengerSuite) TestChatPersistencePrivateGroupChat() {
Joined: true,
},
},
MembershipUpdates: []ChatMembershipUpdate{
ChatMembershipUpdate{
ID: "1",
Type: "type-1",
MembershipUpdates: []v1protocol.MembershipUpdateEvent{
{
Type: protobuf.MembershipUpdateEvent_CHAT_CREATED,
Name: "name-1",
ClockValue: 1,
Signature: "signature-1",
Signature: []byte("signature-1"),
From: "from-1",
Member: "member-1",
Members: []string{"member-1", "member-2"},
},
ChatMembershipUpdate{
ID: "2",
Type: "type-2",
{
Type: protobuf.MembershipUpdateEvent_MEMBERS_ADDED,
Name: "name-2",
ClockValue: 2,
Signature: "signature-2",
Signature: []byte("signature-2"),
From: "from-2",
Member: "member-2",
Members: []string{"member-2", "member-3"},
},
},
@ -1067,9 +1136,8 @@ func (s *MessengerSuite) TestChatPersistencePrivateGroupChat() {
UnviewedMessagesCount: 40,
LastMessage: []byte("test"),
}
s.Require().NoError(s.m.SaveChat(chat))
savedChats, err := s.m.Chats()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveChat(&chat))
savedChats := s.m.Chats()
s.Require().Equal(1, len(savedChats))
actualChat := savedChats[0]
@ -1139,11 +1207,11 @@ func (s *MessengerSuite) TestBlockContact() {
UnviewedMessagesCount: 40,
}
s.Require().NoError(s.m.SaveChat(chat1))
s.Require().NoError(s.m.SaveChat(chat2))
s.Require().NoError(s.m.SaveChat(chat3))
s.Require().NoError(s.m.SaveChat(&chat1))
s.Require().NoError(s.m.SaveChat(&chat2))
s.Require().NoError(s.m.SaveChat(&chat3))
s.Require().NoError(s.m.SaveContact(contact))
s.Require().NoError(s.m.SaveContact(&contact))
contact.Name = "blocked"
@ -1228,7 +1296,7 @@ func (s *MessengerSuite) TestBlockContact() {
err := s.m.SaveMessages(messages)
s.Require().NoError(err)
response, err := s.m.BlockContact(contact)
response, err := s.m.BlockContact(&contact)
s.Require().NoError(err)
// The new unviewed count is updated
@ -1249,14 +1317,12 @@ func (s *MessengerSuite) TestBlockContact() {
s.Require().Equal("test-5", decodedMessage.ID)
// The contact is updated
savedContacts, err := s.m.Contacts()
s.Require().NoError(err)
savedContacts := s.m.Contacts()
s.Require().Equal(1, len(savedContacts))
s.Require().Equal("blocked", savedContacts[0].Name)
// The chat is deleted
actualChats, err := s.m.Chats()
s.Require().NoError(err)
actualChats := s.m.Chats()
s.Require().Equal(2, len(actualChats))
// The messages have been deleted
@ -1294,9 +1360,8 @@ func (s *MessengerSuite) TestContactPersistence() {
TributeToTalk: "talk",
}
s.Require().NoError(s.m.SaveContact(contact))
savedContacts, err := s.m.Contacts()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveContact(&contact))
savedContacts := s.m.Contacts()
s.Require().Equal(1, len(savedContacts))
actualContact := savedContacts[0]
@ -1354,8 +1419,7 @@ func (s *MessengerSuite) TestVerifyENSNames() {
s.Require().False(response[pk4].Verified)
// The contacts are updated
savedContacts, err := s.m.Contacts()
s.Require().NoError(err)
savedContacts := s.m.Contacts()
s.Require().Equal(2, len(savedContacts))
@ -1404,9 +1468,8 @@ func (s *MessengerSuite) TestContactPersistenceUpdate() {
TributeToTalk: "talk",
}
s.Require().NoError(s.m.SaveContact(contact))
savedContacts, err := s.m.Contacts()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveContact(&contact))
savedContacts := s.m.Contacts()
s.Require().Equal(1, len(savedContacts))
actualContact := savedContacts[0]
@ -1418,9 +1481,8 @@ func (s *MessengerSuite) TestContactPersistenceUpdate() {
s.Require().Equal(expectedContact, actualContact)
contact.Name = "updated-name"
s.Require().NoError(s.m.SaveContact(contact))
updatedContact, err := s.m.Contacts()
s.Require().NoError(err)
s.Require().NoError(s.m.SaveContact(&contact))
updatedContact := s.m.Contacts()
s.Require().Equal(1, len(updatedContact))
actualUpdatedContact := updatedContact[0]
@ -1434,22 +1496,39 @@ func (s *MessengerSuite) TestSharedSecretHandler() {
s.NoError(err)
}
func (s *MessengerSuite) TestCreateGroupChat() {
chat, err := s.m.CreateGroupChat("test")
s.Require().NoError(err)
func (s *MessengerSuite) TestCreateGroupChatWithMembers() {
members := []string{"0x0424a68f89ba5fcd5e0640c1e1f591d561fa4125ca4e2a43592bc4123eca10ce064e522c254bb83079ba404327f6eafc01ec90a1444331fe769d3f3a7f90b0dde1"}
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", members)
s.NoError(err)
s.Require().Len(response.Chats, 1)
chat := response.Chats[0]
s.Require().Equal("test", chat.Name)
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
s.Require().Contains(chat.ID, publicKeyHex)
s.EqualValues([]string{publicKeyHex}, []string{chat.Members[0].ID})
s.Equal(members[0], chat.Members[1].ID)
}
func (s *MessengerSuite) TestAddMembersToChat() {
chat, err := s.m.CreateGroupChat("test")
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
s.Require().NoError(err)
s.Require().Len(response.Chats, 1)
chat := response.Chats[0]
key, err := crypto.GenerateKey()
s.Require().NoError(err)
err = s.m.AddMembersToChat(context.Background(), chat, []*ecdsa.PublicKey{&key.PublicKey})
members := []string{"0x" + hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey))}
response, err = s.m.AddMembersToGroupChat(context.Background(), chat.ID, members)
s.Require().NoError(err)
s.Require().Len(response.Chats, 1)
s.Require().Len(response.Messages, 1)
chat = response.Chats[0]
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
keyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey))
s.EqualValues([]string{publicKeyHex, keyHex}, []string{chat.Members[0].ID, chat.Members[1].ID})
@ -1550,11 +1629,12 @@ func (s *PostProcessorSuite) TestRun() {
s.Require().NoError(err)
testCases := []struct {
Name string
Chat Chat // Chat to create
Message Message
SigPubKey *ecdsa.PublicKey
ExpectedChatIDs []string
Name string
Error bool
Chat Chat // Chat to create
Message Message
SigPubKey *ecdsa.PublicKey
ExpectedChatID string
}{
{
Name: "Public chat",
@ -1565,8 +1645,8 @@ func (s *PostProcessorSuite) TestRun() {
MessageType: protobuf.ChatMessage_PUBLIC_GROUP,
Text: "test-text"},
},
SigPubKey: &key1.PublicKey,
ExpectedChatIDs: []string{"test-chat"},
SigPubKey: &key1.PublicKey,
ExpectedChatID: "test-chat",
},
{
Name: "Private message from myself with existing chat",
@ -1577,8 +1657,8 @@ func (s *PostProcessorSuite) TestRun() {
MessageType: protobuf.ChatMessage_ONE_TO_ONE,
Text: "test-text"},
},
SigPubKey: &key1.PublicKey,
ExpectedChatIDs: []string{oneToOneChatID(&key1.PublicKey)},
SigPubKey: &key1.PublicKey,
ExpectedChatID: oneToOneChatID(&key1.PublicKey),
},
{
Name: "Private message from other with existing chat",
@ -1590,8 +1670,8 @@ func (s *PostProcessorSuite) TestRun() {
Text: "test-text"},
},
SigPubKey: &key2.PublicKey,
ExpectedChatIDs: []string{oneToOneChatID(&key2.PublicKey)},
SigPubKey: &key2.PublicKey,
ExpectedChatID: oneToOneChatID(&key2.PublicKey),
},
{
Name: "Private message from myself without chat",
@ -1602,8 +1682,8 @@ func (s *PostProcessorSuite) TestRun() {
Text: "test-text"},
},
SigPubKey: &key1.PublicKey,
ExpectedChatIDs: []string{oneToOneChatID(&key1.PublicKey)},
SigPubKey: &key1.PublicKey,
ExpectedChatID: oneToOneChatID(&key1.PublicKey),
},
{
Name: "Private message from other without chat",
@ -1614,12 +1694,13 @@ func (s *PostProcessorSuite) TestRun() {
Text: "test-text"},
},
SigPubKey: &key2.PublicKey,
ExpectedChatIDs: []string{oneToOneChatID(&key2.PublicKey)},
SigPubKey: &key2.PublicKey,
ExpectedChatID: oneToOneChatID(&key2.PublicKey),
},
{
Name: "Private message without public key",
SigPubKey: nil,
Error: true,
},
{
Name: "Private group message",
@ -1629,15 +1710,16 @@ func (s *PostProcessorSuite) TestRun() {
MessageType: protobuf.ChatMessage_PRIVATE_GROUP,
Text: "test-text"},
},
Error: true,
SigPubKey: &key2.PublicKey,
},
// TODO: add test for group messages
}
for idx, tc := range testCases {
s.Run(tc.Name, func() {
chatsMap := make(map[string]*Chat)
if tc.Chat.ID != "" {
chatsMap[tc.Chat.ID] = &tc.Chat
err := s.postProcessor.persistence.SaveChat(tc.Chat)
s.Require().NoError(err)
defer func() {
@ -1652,12 +1734,16 @@ func (s *PostProcessorSuite) TestRun() {
s.Empty(message.LocalChatID)
message.ID = strconv.Itoa(idx) // manually set the ID because messages does not go through messageProcessor
messages, err := s.postProcessor.matchMessages([]*Message{&message})
s.NoError(err)
s.Require().Len(messages, len(tc.ExpectedChatIDs))
if len(tc.ExpectedChatIDs) != 0 {
s.Equal(tc.ExpectedChatIDs[0], message.LocalChatID)
s.EqualValues(&message, messages[0])
chat, err := s.postProcessor.matchMessage(&message, chatsMap)
if tc.Error {
s.Require().Error(err)
} else {
s.Require().NoError(err)
if tc.ExpectedChatID != "" {
s.Require().NotNil(chat)
s.Require().Equal(tc.ExpectedChatID, chat.ID)
}
}
})
}

View file

@ -114,7 +114,7 @@ func _000001_initUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 832, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 832, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1c, 0xa4, 0xac, 0x0, 0xd3, 0x19, 0x53, 0x35, 0x91, 0x1c, 0x94, 0xea, 0xde, 0xa7, 0x75, 0xb6, 0x73, 0x1d, 0x42, 0x14, 0xca, 0x84, 0x5b, 0xdb, 0x10, 0x94, 0x28, 0xc0, 0x33, 0x95, 0x7f, 0xf}}
return a, nil
}
@ -154,7 +154,7 @@ func _000002_add_chatsUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 495, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 495, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6e, 0xca, 0x2b, 0xf7, 0xca, 0x21, 0xda, 0x17, 0x1f, 0x97, 0xa8, 0x12, 0xb5, 0x6c, 0xad, 0x92, 0xe7, 0x2, 0xaf, 0x1, 0xcb, 0x5e, 0xe9, 0x71, 0xc4, 0x81, 0xa7, 0x3, 0x93, 0x5b, 0x73, 0x73}}
return a, nil
}
@ -234,7 +234,7 @@ func _000004_user_messages_compatibilityUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000004_user_messages_compatibility.up.sql", size: 980, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "000004_user_messages_compatibility.up.sql", size: 980, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x7a, 0xba, 0xae, 0x6d, 0xef, 0x69, 0x12, 0x6b, 0x48, 0xe3, 0xa7, 0xad, 0x21, 0x4a, 0xcf, 0x4f, 0xbc, 0x14, 0xc1, 0x19, 0x69, 0x1c, 0xc, 0xa2, 0x3d, 0xbc, 0x12, 0x32, 0x71, 0x76, 0x15}}
return a, nil
}
@ -274,7 +274,7 @@ func _1567112142_user_messagesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1567112142_user_messages.up.sql", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "1567112142_user_messages.up.sql", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xff, 0xc0, 0x47, 0x32, 0xa9, 0xa4, 0x6, 0x63, 0x6b, 0xe7, 0x79, 0x2b, 0x80, 0x52, 0x2b, 0x6f, 0xf9, 0x9d, 0x9a, 0xc2, 0xa9, 0x7a, 0xf7, 0x4d, 0x14, 0x12, 0x21, 0x10, 0xc4, 0x30, 0x42, 0xaa}}
return a, nil
}

View file

@ -5,10 +5,8 @@ import (
"context"
"database/sql"
"encoding/gob"
"encoding/hex"
"github.com/pkg/errors"
"github.com/status-im/status-go/eth-node/crypto"
)
var (
@ -45,6 +43,26 @@ func (db sqlitePersistence) SaveChats(chats []*Chat) error {
return nil
}
func (db sqlitePersistence) SaveContacts(contacts []*Contact) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
for _, contact := range contacts {
err := db.SaveContact(contact, tx)
if err != nil {
return err
}
}
return nil
}
func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
var err error
if tx == nil {
@ -62,21 +80,6 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
}()
}
pkey := []byte{}
// For one to one chatID is an encoded public key
if chat.ChatType == ChatTypeOneToOne {
pkey, err = hex.DecodeString(chat.ID[2:])
if err != nil {
return err
}
// Safety check, make sure is well formed
_, err := crypto.UnmarshalPubkey(pkey)
if err != nil {
return err
}
}
// Encode members
var encodedMembers bytes.Buffer
memberEncoder := gob.NewEncoder(&encodedMembers)
@ -94,8 +97,8 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
}
// Insert record
stmt, err := tx.Prepare(`INSERT INTO chats(id, name, color, active, type, timestamp, deleted_at_clock_value, public_key, unviewed_message_count, last_clock_value, last_message, members, membership_updates)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
stmt, err := tx.Prepare(`INSERT INTO chats(id, name, color, active, type, timestamp, deleted_at_clock_value, unviewed_message_count, last_clock_value, last_message, members, membership_updates)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
if err != nil {
return err
}
@ -109,7 +112,6 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
chat.ChatType,
chat.Timestamp,
chat.DeletedAtClockValue,
pkey,
chat.UnviewedMessagesCount,
chat.LastClockValue,
chat.LastMessage,
@ -157,7 +159,6 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
type,
timestamp,
deleted_at_clock_value,
public_key,
unviewed_message_count,
last_clock_value,
last_message,
@ -176,7 +177,6 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
chat Chat
encodedMembers []byte
encodedMembershipUpdates []byte
pkey []byte
)
err = rows.Scan(
&chat.ID,
@ -186,7 +186,6 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
&chat.ChatType,
&chat.Timestamp,
&chat.DeletedAtClockValue,
&pkey,
&chat.UnviewedMessagesCount,
&chat.LastClockValue,
&chat.LastMessage,
@ -211,18 +210,73 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
return
}
if len(pkey) != 0 {
chat.PublicKey, err = crypto.UnmarshalPubkey(pkey)
if err != nil {
return
}
}
chats = append(chats, &chat)
}
return
}
func (db sqlitePersistence) Chat(chatID string) (*Chat, error) {
var (
chat Chat
encodedMembers []byte
encodedMembershipUpdates []byte
)
err := db.db.QueryRow(`
SELECT
id,
name,
color,
active,
type,
timestamp,
deleted_at_clock_value,
unviewed_message_count,
last_clock_value,
last_message,
members,
membership_updates
FROM chats
WHERE id = ?
`, chatID).Scan(&chat.ID,
&chat.Name,
&chat.Color,
&chat.Active,
&chat.ChatType,
&chat.Timestamp,
&chat.DeletedAtClockValue,
&chat.UnviewedMessagesCount,
&chat.LastClockValue,
&chat.LastMessage,
&encodedMembers,
&encodedMembershipUpdates,
)
switch err {
case sql.ErrNoRows:
return nil, nil
case nil:
// Restore members
membersDecoder := gob.NewDecoder(bytes.NewBuffer(encodedMembers))
err = membersDecoder.Decode(&chat.Members)
if err != nil {
return nil, err
}
// Restore membership updates
membershipUpdatesDecoder := gob.NewDecoder(bytes.NewBuffer(encodedMembershipUpdates))
err = membershipUpdatesDecoder.Decode(&chat.MembershipUpdates)
if err != nil {
return nil, err
}
return &chat, nil
}
return nil, err
}
func (db sqlitePersistence) Contacts() ([]*Contact, error) {
rows, err := db.db.Query(`
SELECT
@ -293,83 +347,7 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
return response, nil
}
func (db sqlitePersistence) SetContactsENSData(contacts []*Contact) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
// Ensure contacts exists
err = db.SetContactsGeneratedData(contacts, tx)
if err != nil {
return err
}
// Update ens data
for _, contact := range contacts {
_, err := tx.Exec(`UPDATE contacts SET name = ?, ens_verified = ? , ens_verified_at = ? WHERE id = ?`, contact.Name, contact.ENSVerified, contact.ENSVerifiedAt, contact.ID)
if err != nil {
return err
}
}
return nil
}
// SetContactsGeneratedData sets a contact generated data if not existing already
// in the database
func (db sqlitePersistence) SetContactsGeneratedData(contacts []*Contact, tx *sql.Tx) (err error) {
if tx == nil {
tx, err = db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
}
for _, contact := range contacts {
_, err = tx.Exec(`
INSERT OR IGNORE INTO contacts(
id,
address,
name,
alias,
identicon,
photo,
last_updated,
tribute_to_talk
) VALUES (?, ?, "", ?, ?, "", 0, "")`,
contact.ID,
contact.Address,
contact.Alias,
contact.Identicon,
)
if err != nil {
return
}
}
return
}
func (db sqlitePersistence) SaveContact(contact Contact, tx *sql.Tx) (err error) {
func (db sqlitePersistence) SaveContact(contact *Contact, tx *sql.Tx) (err error) {
if tx == nil {
tx, err = db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {

View file

@ -406,7 +406,7 @@ func (db sqlitePersistence) UpdateMessageOutgoingStatus(id string, newOutgoingSt
}
// BlockContact updates a contact, deletes all the messages and 1-to-1 chat, updates the unread messages count and returns a map with the new count
func (db sqlitePersistence) BlockContact(contact Contact) ([]*Chat, error) {
func (db sqlitePersistence) BlockContact(contact *Contact) ([]*Chat, error) {
var chats []*Chat
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {

View file

@ -355,62 +355,6 @@ func TestUpdateMessageOutgoingStatus(t *testing.T) {
require.Equal(t, "new-status", m.OutgoingStatus)
}
func TestSetContactGeneratedData(t *testing.T) {
db, err := openTestDB()
require.NoError(t, err)
p := sqlitePersistence{db: db}
existingContact := Contact{
ID: "contact-one",
Address: "contact-address",
Name: "contact-name",
Photo: "contact-photo",
LastUpdated: 20,
SystemTags: []string{"1", "2"},
DeviceInfo: []ContactDeviceInfo{
ContactDeviceInfo{
InstallationID: "1",
Timestamp: 2,
FCMToken: "token",
},
ContactDeviceInfo{
InstallationID: "2",
Timestamp: 3,
FCMToken: "token-2",
},
},
TributeToTalk: "talk",
}
existingContactUpdate := Contact{
ID: "contact-one",
Address: "contact-address",
Alias: "generated-name-one",
}
nonExistingContactUpdate := Contact{
ID: "contact-two",
Address: "contact-address",
Alias: "generated-name-two",
}
err = p.SaveContact(existingContact, nil)
require.NoError(t, err)
err = p.SetContactsGeneratedData([]*Contact{&existingContactUpdate, &nonExistingContactUpdate}, nil)
require.NoError(t, err)
allContacts, err := p.Contacts()
require.NoError(t, err)
require.Equal(t, 2, len(allContacts))
// Make sure it has not been modified
require.Equal(t, int64(20), allContacts[0].LastUpdated)
// Ensure new contact has been saved
require.Equal(t, "contact-two", allContacts[1].ID)
}
func openTestDB() (*sql.DB, error) {
dbPath, err := ioutil.TempFile("", "")
if err != nil {

View file

@ -0,0 +1,144 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: application_metadata_message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ApplicationMetadataMessage_Type int32
const (
ApplicationMetadataMessage_UNKNOWN ApplicationMetadataMessage_Type = 0
ApplicationMetadataMessage_CHAT_MESSAGE ApplicationMetadataMessage_Type = 1
ApplicationMetadataMessage_CONTACT_REQUEST ApplicationMetadataMessage_Type = 2
ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ApplicationMetadataMessage_Type = 3
ApplicationMetadataMessage_PAIR_INSTALLATION ApplicationMetadataMessage_Type = 4
ApplicationMetadataMessage_SYNC_INSTALLATION ApplicationMetadataMessage_Type = 5
)
var ApplicationMetadataMessage_Type_name = map[int32]string{
0: "UNKNOWN",
1: "CHAT_MESSAGE",
2: "CONTACT_REQUEST",
3: "MEMBERSHIP_UPDATE_MESSAGE",
4: "PAIR_INSTALLATION",
5: "SYNC_INSTALLATION",
}
var ApplicationMetadataMessage_Type_value = map[string]int32{
"UNKNOWN": 0,
"CHAT_MESSAGE": 1,
"CONTACT_REQUEST": 2,
"MEMBERSHIP_UPDATE_MESSAGE": 3,
"PAIR_INSTALLATION": 4,
"SYNC_INSTALLATION": 5,
}
func (x ApplicationMetadataMessage_Type) String() string {
return proto.EnumName(ApplicationMetadataMessage_Type_name, int32(x))
}
func (ApplicationMetadataMessage_Type) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_ad09a6406fcf24c7, []int{0, 0}
}
type ApplicationMetadataMessage struct {
// Signature of the payload field
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
// This is the encoded protobuf of the application level message, i.e ChatMessage
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
// The type of protobuf message sent
Type ApplicationMetadataMessage_Type `protobuf:"varint,3,opt,name=type,proto3,enum=protobuf.ApplicationMetadataMessage_Type" json:"type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ApplicationMetadataMessage) Reset() { *m = ApplicationMetadataMessage{} }
func (m *ApplicationMetadataMessage) String() string { return proto.CompactTextString(m) }
func (*ApplicationMetadataMessage) ProtoMessage() {}
func (*ApplicationMetadataMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_ad09a6406fcf24c7, []int{0}
}
func (m *ApplicationMetadataMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplicationMetadataMessage.Unmarshal(m, b)
}
func (m *ApplicationMetadataMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplicationMetadataMessage.Marshal(b, m, deterministic)
}
func (m *ApplicationMetadataMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplicationMetadataMessage.Merge(m, src)
}
func (m *ApplicationMetadataMessage) XXX_Size() int {
return xxx_messageInfo_ApplicationMetadataMessage.Size(m)
}
func (m *ApplicationMetadataMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ApplicationMetadataMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ApplicationMetadataMessage proto.InternalMessageInfo
func (m *ApplicationMetadataMessage) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func (m *ApplicationMetadataMessage) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
func (m *ApplicationMetadataMessage) GetType() ApplicationMetadataMessage_Type {
if m != nil {
return m.Type
}
return ApplicationMetadataMessage_UNKNOWN
}
func init() {
proto.RegisterEnum("protobuf.ApplicationMetadataMessage_Type", ApplicationMetadataMessage_Type_name, ApplicationMetadataMessage_Type_value)
proto.RegisterType((*ApplicationMetadataMessage)(nil), "protobuf.ApplicationMetadataMessage")
}
func init() { proto.RegisterFile("application_metadata_message.proto", fileDescriptor_ad09a6406fcf24c7) }
var fileDescriptor_ad09a6406fcf24c7 = []byte{
// 269 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x8e, 0x41, 0x4b, 0xc3, 0x30,
0x18, 0x86, 0x6d, 0x57, 0x9d, 0x7e, 0x0e, 0xad, 0x11, 0xa1, 0x8a, 0xc2, 0xe8, 0x69, 0x5e, 0x7a,
0xd0, 0xb3, 0x87, 0x58, 0x83, 0x2b, 0xae, 0x69, 0x4d, 0x52, 0xc4, 0x53, 0xc8, 0x5c, 0x1c, 0x85,
0x6d, 0x0d, 0x6b, 0x76, 0xe8, 0x2f, 0xf0, 0x57, 0xf8, 0x5f, 0x65, 0xd5, 0x39, 0x3c, 0x78, 0x0a,
0xef, 0x93, 0xf7, 0xe1, 0xfd, 0x20, 0x54, 0xc6, 0xcc, 0xca, 0x37, 0x65, 0xcb, 0x6a, 0x21, 0xe7,
0xda, 0xaa, 0x89, 0xb2, 0x4a, 0xce, 0x75, 0x5d, 0xab, 0xa9, 0x8e, 0xcc, 0xb2, 0xb2, 0x15, 0xda,
0x6f, 0x9f, 0xf1, 0xea, 0x3d, 0xfc, 0x74, 0xe1, 0x02, 0x6f, 0x85, 0xf4, 0xa7, 0x9f, 0x7e, 0xd7,
0xd1, 0x25, 0x1c, 0xd4, 0xe5, 0x74, 0xa1, 0xec, 0x6a, 0xa9, 0x03, 0xa7, 0xef, 0x0c, 0x7a, 0x6c,
0x0b, 0x50, 0x00, 0x5d, 0xa3, 0x9a, 0x59, 0xa5, 0x26, 0x81, 0xdb, 0xfe, 0x6d, 0x22, 0xba, 0x03,
0xcf, 0x36, 0x46, 0x07, 0x9d, 0xbe, 0x33, 0x38, 0xba, 0xb9, 0x8e, 0x36, 0x7b, 0xd1, 0xff, 0x5b,
0x91, 0x68, 0x8c, 0x66, 0xad, 0x16, 0x7e, 0x38, 0xe0, 0xad, 0x23, 0x3a, 0x84, 0x6e, 0x41, 0x9f,
0x68, 0xf6, 0x42, 0xfd, 0x1d, 0xe4, 0x43, 0x2f, 0x1e, 0x62, 0x21, 0x53, 0xc2, 0x39, 0x7e, 0x24,
0xbe, 0x83, 0x4e, 0xe1, 0x38, 0xce, 0xa8, 0xc0, 0xb1, 0x90, 0x8c, 0x3c, 0x17, 0x84, 0x0b, 0xdf,
0x45, 0x57, 0x70, 0x9e, 0x92, 0xf4, 0x9e, 0x30, 0x3e, 0x4c, 0x72, 0x59, 0xe4, 0x0f, 0x58, 0x90,
0x5f, 0xa7, 0x83, 0xce, 0xe0, 0x24, 0xc7, 0x09, 0x93, 0x09, 0xe5, 0x02, 0x8f, 0x46, 0x58, 0x24,
0x19, 0xf5, 0xbd, 0x35, 0xe6, 0xaf, 0x34, 0xfe, 0x8b, 0x77, 0xc7, 0x7b, 0xed, 0xe5, 0xb7, 0x5f,
0x01, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xdb, 0x0d, 0x56, 0x56, 0x01, 0x00, 0x00,
}

View file

@ -0,0 +1,22 @@
syntax = "proto3";
package protobuf;
message ApplicationMetadataMessage {
// Signature of the payload field
bytes signature = 1;
// This is the encoded protobuf of the application level message, i.e ChatMessage
bytes payload = 2;
// The type of protobuf message sent
Type type = 3;
enum Type {
UNKNOWN = 0;
CHAT_MESSAGE = 1;
CONTACT_REQUEST = 2;
MEMBERSHIP_UPDATE_MESSAGE = 3;
PAIR_INSTALLATION = 4;
SYNC_INSTALLATION = 5;
}
}

View file

@ -0,0 +1,326 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: chat_message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ChatMessage_MessageType int32
const (
ChatMessage_UNKNOWN_MESSAGE_TYPE ChatMessage_MessageType = 0
ChatMessage_ONE_TO_ONE ChatMessage_MessageType = 1
ChatMessage_PUBLIC_GROUP ChatMessage_MessageType = 2
ChatMessage_PRIVATE_GROUP ChatMessage_MessageType = 3
// Only local
ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP ChatMessage_MessageType = 4
)
var ChatMessage_MessageType_name = map[int32]string{
0: "UNKNOWN_MESSAGE_TYPE",
1: "ONE_TO_ONE",
2: "PUBLIC_GROUP",
3: "PRIVATE_GROUP",
4: "SYSTEM_MESSAGE_PRIVATE_GROUP",
}
var ChatMessage_MessageType_value = map[string]int32{
"UNKNOWN_MESSAGE_TYPE": 0,
"ONE_TO_ONE": 1,
"PUBLIC_GROUP": 2,
"PRIVATE_GROUP": 3,
"SYSTEM_MESSAGE_PRIVATE_GROUP": 4,
}
func (x ChatMessage_MessageType) String() string {
return proto.EnumName(ChatMessage_MessageType_name, int32(x))
}
func (ChatMessage_MessageType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{1, 0}
}
type ChatMessage_ContentType int32
const (
ChatMessage_UNKNOWN_CONTENT_TYPE ChatMessage_ContentType = 0
ChatMessage_TEXT_PLAIN ChatMessage_ContentType = 1
ChatMessage_STICKER ChatMessage_ContentType = 2
ChatMessage_STATUS ChatMessage_ContentType = 3
ChatMessage_EMOJI ChatMessage_ContentType = 4
ChatMessage_COMMAND ChatMessage_ContentType = 5
ChatMessage_COMMAND_REQUEST ChatMessage_ContentType = 6
)
var ChatMessage_ContentType_name = map[int32]string{
0: "UNKNOWN_CONTENT_TYPE",
1: "TEXT_PLAIN",
2: "STICKER",
3: "STATUS",
4: "EMOJI",
5: "COMMAND",
6: "COMMAND_REQUEST",
}
var ChatMessage_ContentType_value = map[string]int32{
"UNKNOWN_CONTENT_TYPE": 0,
"TEXT_PLAIN": 1,
"STICKER": 2,
"STATUS": 3,
"EMOJI": 4,
"COMMAND": 5,
"COMMAND_REQUEST": 6,
}
func (x ChatMessage_ContentType) String() string {
return proto.EnumName(ChatMessage_ContentType_name, int32(x))
}
func (ChatMessage_ContentType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{1, 1}
}
type StickerMessage struct {
Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
Pack int32 `protobuf:"varint,2,opt,name=pack,proto3" json:"pack,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *StickerMessage) Reset() { *m = StickerMessage{} }
func (m *StickerMessage) String() string { return proto.CompactTextString(m) }
func (*StickerMessage) ProtoMessage() {}
func (*StickerMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{0}
}
func (m *StickerMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StickerMessage.Unmarshal(m, b)
}
func (m *StickerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_StickerMessage.Marshal(b, m, deterministic)
}
func (m *StickerMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_StickerMessage.Merge(m, src)
}
func (m *StickerMessage) XXX_Size() int {
return xxx_messageInfo_StickerMessage.Size(m)
}
func (m *StickerMessage) XXX_DiscardUnknown() {
xxx_messageInfo_StickerMessage.DiscardUnknown(m)
}
var xxx_messageInfo_StickerMessage proto.InternalMessageInfo
func (m *StickerMessage) GetHash() string {
if m != nil {
return m.Hash
}
return ""
}
func (m *StickerMessage) GetPack() int32 {
if m != nil {
return m.Pack
}
return 0
}
type ChatMessage struct {
// Lamport timestamp of the chat message
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
// Unix timestamps in milliseconds, currently not used as we use whisper as more reliable, but here
// so that we don't rely on it
Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// Text of the message
Text string `protobuf:"bytes,3,opt,name=text,proto3" json:"text,omitempty"`
// Id of the message that we are replying to
ResponseTo string `protobuf:"bytes,4,opt,name=response_to,json=responseTo,proto3" json:"response_to,omitempty"`
// Ens name of the sender
EnsName string `protobuf:"bytes,5,opt,name=ens_name,json=ensName,proto3" json:"ens_name,omitempty"`
// Chat id, this field is symmetric for public-chats and private group chats,
// but asymmetric in case of one-to-ones, as the sender will use the chat-id
// of the received, while the receiver will use the chat-id of the sender.
// Probably should be the concatenation of sender-pk & receiver-pk in alphabetical order
ChatId string `protobuf:"bytes,6,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
// The type of message (public/one-to-one/private-group-chat)
MessageType ChatMessage_MessageType `protobuf:"varint,7,opt,name=message_type,json=messageType,proto3,enum=protobuf.ChatMessage_MessageType" json:"message_type,omitempty"`
// The type of the content of the message
ContentType ChatMessage_ContentType `protobuf:"varint,8,opt,name=content_type,json=contentType,proto3,enum=protobuf.ChatMessage_ContentType" json:"content_type,omitempty"`
// Types that are valid to be assigned to Payload:
// *ChatMessage_Sticker
Payload isChatMessage_Payload `protobuf_oneof:"payload"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ChatMessage) Reset() { *m = ChatMessage{} }
func (m *ChatMessage) String() string { return proto.CompactTextString(m) }
func (*ChatMessage) ProtoMessage() {}
func (*ChatMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{1}
}
func (m *ChatMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChatMessage.Unmarshal(m, b)
}
func (m *ChatMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ChatMessage.Marshal(b, m, deterministic)
}
func (m *ChatMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ChatMessage.Merge(m, src)
}
func (m *ChatMessage) XXX_Size() int {
return xxx_messageInfo_ChatMessage.Size(m)
}
func (m *ChatMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ChatMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ChatMessage proto.InternalMessageInfo
func (m *ChatMessage) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
func (m *ChatMessage) GetTimestamp() uint64 {
if m != nil {
return m.Timestamp
}
return 0
}
func (m *ChatMessage) GetText() string {
if m != nil {
return m.Text
}
return ""
}
func (m *ChatMessage) GetResponseTo() string {
if m != nil {
return m.ResponseTo
}
return ""
}
func (m *ChatMessage) GetEnsName() string {
if m != nil {
return m.EnsName
}
return ""
}
func (m *ChatMessage) GetChatId() string {
if m != nil {
return m.ChatId
}
return ""
}
func (m *ChatMessage) GetMessageType() ChatMessage_MessageType {
if m != nil {
return m.MessageType
}
return ChatMessage_UNKNOWN_MESSAGE_TYPE
}
func (m *ChatMessage) GetContentType() ChatMessage_ContentType {
if m != nil {
return m.ContentType
}
return ChatMessage_UNKNOWN_CONTENT_TYPE
}
type isChatMessage_Payload interface {
isChatMessage_Payload()
}
type ChatMessage_Sticker struct {
Sticker *StickerMessage `protobuf:"bytes,9,opt,name=sticker,proto3,oneof"`
}
func (*ChatMessage_Sticker) isChatMessage_Payload() {}
func (m *ChatMessage) GetPayload() isChatMessage_Payload {
if m != nil {
return m.Payload
}
return nil
}
func (m *ChatMessage) GetSticker() *StickerMessage {
if x, ok := m.GetPayload().(*ChatMessage_Sticker); ok {
return x.Sticker
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*ChatMessage) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*ChatMessage_Sticker)(nil),
}
}
func init() {
proto.RegisterEnum("protobuf.ChatMessage_MessageType", ChatMessage_MessageType_name, ChatMessage_MessageType_value)
proto.RegisterEnum("protobuf.ChatMessage_ContentType", ChatMessage_ContentType_name, ChatMessage_ContentType_value)
proto.RegisterType((*StickerMessage)(nil), "protobuf.StickerMessage")
proto.RegisterType((*ChatMessage)(nil), "protobuf.ChatMessage")
}
func init() { proto.RegisterFile("chat_message.proto", fileDescriptor_263952f55fd35689) }
var fileDescriptor_263952f55fd35689 = []byte{
// 462 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xcf, 0x6f, 0xd3, 0x30,
0x14, 0x5e, 0xda, 0xb4, 0x69, 0x5f, 0x46, 0x31, 0x66, 0x12, 0x46, 0x9a, 0x44, 0xe9, 0xa9, 0xa7,
0x1e, 0x06, 0x07, 0xae, 0x5d, 0x66, 0x8d, 0xb0, 0xc5, 0x29, 0x8e, 0x0b, 0xec, 0x64, 0x79, 0xa9,
0xa1, 0x55, 0x97, 0x1f, 0x6a, 0x8c, 0x44, 0x0f, 0xf0, 0x67, 0x73, 0x46, 0x71, 0x5a, 0xda, 0x5d,
0x76, 0xf2, 0xfb, 0xbe, 0xf7, 0xbd, 0xef, 0xe5, 0x7d, 0x01, 0x9c, 0x2e, 0x95, 0x91, 0x99, 0xae,
0x2a, 0xf5, 0x43, 0x4f, 0xca, 0x4d, 0x61, 0x0a, 0xdc, 0xb3, 0xcf, 0xfd, 0xcf, 0xef, 0xa3, 0x0f,
0x30, 0x48, 0xcc, 0x2a, 0x5d, 0xeb, 0x4d, 0xd4, 0x28, 0x30, 0x06, 0x77, 0xa9, 0xaa, 0x25, 0x71,
0x86, 0xce, 0xb8, 0xcf, 0x6d, 0x5d, 0x73, 0xa5, 0x4a, 0xd7, 0xa4, 0x35, 0x74, 0xc6, 0x1d, 0x6e,
0xeb, 0xd1, 0x5f, 0x17, 0xfc, 0x60, 0xa9, 0xcc, 0x7e, 0xee, 0x0c, 0x3a, 0xe9, 0x43, 0x91, 0xae,
0xed, 0xa0, 0xcb, 0x1b, 0x80, 0xcf, 0xa1, 0x6f, 0x56, 0x99, 0xae, 0x8c, 0xca, 0x4a, 0x3b, 0xee,
0xf2, 0x03, 0x51, 0xfb, 0x1a, 0xfd, 0xcb, 0x90, 0x76, 0xb3, 0xab, 0xae, 0xf1, 0x1b, 0xf0, 0x37,
0xba, 0x2a, 0x8b, 0xbc, 0xd2, 0xd2, 0x14, 0xc4, 0xb5, 0x2d, 0xd8, 0x53, 0xa2, 0xc0, 0xaf, 0xa1,
0xa7, 0xf3, 0x4a, 0xe6, 0x2a, 0xd3, 0xa4, 0x63, 0xbb, 0x9e, 0xce, 0x2b, 0xa6, 0x32, 0x8d, 0x5f,
0x81, 0x67, 0xaf, 0x5d, 0x2d, 0x48, 0xd7, 0x76, 0xba, 0x35, 0x0c, 0x17, 0xf8, 0x0a, 0x4e, 0x77,
0x09, 0x48, 0xb3, 0x2d, 0x35, 0xf1, 0x86, 0xce, 0x78, 0x70, 0xf1, 0x76, 0xb2, 0xcf, 0x61, 0x72,
0x74, 0xc9, 0x64, 0xf7, 0x8a, 0x6d, 0xa9, 0xb9, 0x9f, 0x1d, 0x40, 0xed, 0x92, 0x16, 0xb9, 0xd1,
0xb9, 0x69, 0x5c, 0x7a, 0x4f, 0xb9, 0x04, 0x8d, 0xb2, 0x71, 0x49, 0x0f, 0x00, 0xbf, 0x07, 0xaf,
0x6a, 0x22, 0x27, 0xfd, 0xa1, 0x33, 0xf6, 0x2f, 0xc8, 0xc1, 0xe0, 0xf1, 0xbf, 0xf8, 0x78, 0xc2,
0xf7, 0xd2, 0xd1, 0x1f, 0xf0, 0x8f, 0xbe, 0x0b, 0x13, 0x38, 0x9b, 0xb3, 0x1b, 0x16, 0x7f, 0x65,
0x32, 0xa2, 0x49, 0x32, 0xbd, 0xa6, 0x52, 0xdc, 0xcd, 0x28, 0x3a, 0xc1, 0x03, 0x80, 0x98, 0x51,
0x29, 0x62, 0x19, 0x33, 0x8a, 0x1c, 0x8c, 0xe0, 0x74, 0x36, 0xbf, 0xbc, 0x0d, 0x03, 0x79, 0xcd,
0xe3, 0xf9, 0x0c, 0xb5, 0xf0, 0x0b, 0x78, 0x36, 0xe3, 0xe1, 0x97, 0xa9, 0xa0, 0x3b, 0xaa, 0x8d,
0x87, 0x70, 0x9e, 0xdc, 0x25, 0x82, 0x46, 0xff, 0xdd, 0x1e, 0x2b, 0xdc, 0xd1, 0x6f, 0xf0, 0x8f,
0x2e, 0x3a, 0xde, 0x1f, 0xc4, 0x4c, 0x50, 0x26, 0x8e, 0xf6, 0x0b, 0xfa, 0x4d, 0xc8, 0xd9, 0xed,
0x34, 0x64, 0xc8, 0xc1, 0x3e, 0x78, 0x89, 0x08, 0x83, 0x1b, 0xca, 0x51, 0x0b, 0x03, 0x74, 0x13,
0x31, 0x15, 0xf3, 0x04, 0xb5, 0x71, 0x1f, 0x3a, 0x34, 0x8a, 0x3f, 0x85, 0xc8, 0xad, 0x35, 0x41,
0x1c, 0x45, 0x53, 0x76, 0x85, 0x3a, 0xf8, 0x25, 0x3c, 0xdf, 0x01, 0xc9, 0xe9, 0xe7, 0x39, 0x4d,
0x04, 0xea, 0x5e, 0xf6, 0xc1, 0x2b, 0xd5, 0xf6, 0xa1, 0x50, 0x8b, 0xfb, 0xae, 0x4d, 0xeb, 0xdd,
0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x19, 0x70, 0x9c, 0xd9, 0x02, 0x00, 0x00,
}

View file

@ -35,36 +35,20 @@ message ChatMessage {
}
enum MessageType {
ONE_TO_ONE = 0;
PUBLIC_GROUP = 1;
PRIVATE_GROUP = 2;
UNKNOWN_MESSAGE_TYPE = 0;
ONE_TO_ONE = 1;
PUBLIC_GROUP = 2;
PRIVATE_GROUP = 3;
// Only local
SYSTEM_MESSAGE_PRIVATE_GROUP = 3;
SYSTEM_MESSAGE_PRIVATE_GROUP = 4;
}
enum ContentType {
TEXT_PLAIN = 0;
STICKER = 1;
STATUS = 2;
EMOJI = 3;
COMMAND = 4;
COMMAND_REQUEST = 5;
}
}
message ApplicationMetadataMessage {
// Signature of the payload field
bytes signature = 1;
// This is the encoded protobuf of the application level message, i.e ChatMessage
bytes payload = 2;
// The type of protobuf message sent
MessageType message_type = 3;
enum MessageType {
TEXT_MESSAGE = 0;
CONTACT_REQUEST = 1;
MEMBERSHIP_UPDATE = 2;
PAIR_INSTALLATION = 3;
SYNC_INSTALLATION = 4;
UNKNOWN_CONTENT_TYPE = 0;
TEXT_PLAIN = 1;
STICKER = 2;
STATUS = 3;
EMOJI = 4;
COMMAND = 5;
COMMAND_REQUEST = 6;
}
}

View file

@ -0,0 +1,227 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: membership_update_message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type MembershipUpdateEvent_EventType int32
const (
MembershipUpdateEvent_UNKNOWN MembershipUpdateEvent_EventType = 0
MembershipUpdateEvent_CHAT_CREATED MembershipUpdateEvent_EventType = 1
MembershipUpdateEvent_NAME_CHANGED MembershipUpdateEvent_EventType = 2
MembershipUpdateEvent_MEMBERS_ADDED MembershipUpdateEvent_EventType = 3
MembershipUpdateEvent_MEMBER_JOINED MembershipUpdateEvent_EventType = 4
MembershipUpdateEvent_MEMBER_REMOVED MembershipUpdateEvent_EventType = 5
MembershipUpdateEvent_ADMINS_ADDED MembershipUpdateEvent_EventType = 6
MembershipUpdateEvent_ADMIN_REMOVED MembershipUpdateEvent_EventType = 7
)
var MembershipUpdateEvent_EventType_name = map[int32]string{
0: "UNKNOWN",
1: "CHAT_CREATED",
2: "NAME_CHANGED",
3: "MEMBERS_ADDED",
4: "MEMBER_JOINED",
5: "MEMBER_REMOVED",
6: "ADMINS_ADDED",
7: "ADMIN_REMOVED",
}
var MembershipUpdateEvent_EventType_value = map[string]int32{
"UNKNOWN": 0,
"CHAT_CREATED": 1,
"NAME_CHANGED": 2,
"MEMBERS_ADDED": 3,
"MEMBER_JOINED": 4,
"MEMBER_REMOVED": 5,
"ADMINS_ADDED": 6,
"ADMIN_REMOVED": 7,
}
func (x MembershipUpdateEvent_EventType) String() string {
return proto.EnumName(MembershipUpdateEvent_EventType_name, int32(x))
}
func (MembershipUpdateEvent_EventType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_8d37dd0dc857a6be, []int{0, 0}
}
type MembershipUpdateEvent struct {
// Lamport timestamp of the event
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
// List of public keys of objects of the action
Members []string `protobuf:"bytes,2,rep,name=members,proto3" json:"members,omitempty"`
// Name of the chat for the CHAT_CREATED/NAME_CHANGED event types
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
// The type of the event
Type MembershipUpdateEvent_EventType `protobuf:"varint,4,opt,name=type,proto3,enum=protobuf.MembershipUpdateEvent_EventType" json:"type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *MembershipUpdateEvent) Reset() { *m = MembershipUpdateEvent{} }
func (m *MembershipUpdateEvent) String() string { return proto.CompactTextString(m) }
func (*MembershipUpdateEvent) ProtoMessage() {}
func (*MembershipUpdateEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_8d37dd0dc857a6be, []int{0}
}
func (m *MembershipUpdateEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MembershipUpdateEvent.Unmarshal(m, b)
}
func (m *MembershipUpdateEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MembershipUpdateEvent.Marshal(b, m, deterministic)
}
func (m *MembershipUpdateEvent) XXX_Merge(src proto.Message) {
xxx_messageInfo_MembershipUpdateEvent.Merge(m, src)
}
func (m *MembershipUpdateEvent) XXX_Size() int {
return xxx_messageInfo_MembershipUpdateEvent.Size(m)
}
func (m *MembershipUpdateEvent) XXX_DiscardUnknown() {
xxx_messageInfo_MembershipUpdateEvent.DiscardUnknown(m)
}
var xxx_messageInfo_MembershipUpdateEvent proto.InternalMessageInfo
func (m *MembershipUpdateEvent) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
func (m *MembershipUpdateEvent) GetMembers() []string {
if m != nil {
return m.Members
}
return nil
}
func (m *MembershipUpdateEvent) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *MembershipUpdateEvent) GetType() MembershipUpdateEvent_EventType {
if m != nil {
return m.Type
}
return MembershipUpdateEvent_UNKNOWN
}
// MembershipUpdateMessage is a message used to propagate information
// about group membership changes.
// For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
type MembershipUpdateMessage struct {
// The chat id of the private group chat
ChatId string `protobuf:"bytes,1,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
// A list of events for this group chat, first x bytes are the signature, then is a
// protobuf encoded MembershipUpdateEvent
Events [][]byte `protobuf:"bytes,2,rep,name=events,proto3" json:"events,omitempty"`
// An optional chat message
Message *ChatMessage `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *MembershipUpdateMessage) Reset() { *m = MembershipUpdateMessage{} }
func (m *MembershipUpdateMessage) String() string { return proto.CompactTextString(m) }
func (*MembershipUpdateMessage) ProtoMessage() {}
func (*MembershipUpdateMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_8d37dd0dc857a6be, []int{1}
}
func (m *MembershipUpdateMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MembershipUpdateMessage.Unmarshal(m, b)
}
func (m *MembershipUpdateMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MembershipUpdateMessage.Marshal(b, m, deterministic)
}
func (m *MembershipUpdateMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_MembershipUpdateMessage.Merge(m, src)
}
func (m *MembershipUpdateMessage) XXX_Size() int {
return xxx_messageInfo_MembershipUpdateMessage.Size(m)
}
func (m *MembershipUpdateMessage) XXX_DiscardUnknown() {
xxx_messageInfo_MembershipUpdateMessage.DiscardUnknown(m)
}
var xxx_messageInfo_MembershipUpdateMessage proto.InternalMessageInfo
func (m *MembershipUpdateMessage) GetChatId() string {
if m != nil {
return m.ChatId
}
return ""
}
func (m *MembershipUpdateMessage) GetEvents() [][]byte {
if m != nil {
return m.Events
}
return nil
}
func (m *MembershipUpdateMessage) GetMessage() *ChatMessage {
if m != nil {
return m.Message
}
return nil
}
func init() {
proto.RegisterEnum("protobuf.MembershipUpdateEvent_EventType", MembershipUpdateEvent_EventType_name, MembershipUpdateEvent_EventType_value)
proto.RegisterType((*MembershipUpdateEvent)(nil), "protobuf.MembershipUpdateEvent")
proto.RegisterType((*MembershipUpdateMessage)(nil), "protobuf.MembershipUpdateMessage")
}
func init() { proto.RegisterFile("membership_update_message.proto", fileDescriptor_8d37dd0dc857a6be) }
var fileDescriptor_8d37dd0dc857a6be = []byte{
// 340 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x50, 0x41, 0x4f, 0xf2, 0x40,
0x10, 0xfd, 0x0a, 0xa5, 0xfd, 0x3a, 0x20, 0xa9, 0x13, 0x91, 0xc6, 0x8b, 0x0d, 0xa7, 0x7a, 0xa9,
0x09, 0x9e, 0x3d, 0xd4, 0xee, 0x46, 0xd0, 0xec, 0x92, 0xac, 0xa0, 0xc7, 0xa6, 0xc0, 0x2a, 0x44,
0x0b, 0x0d, 0x14, 0x13, 0xe2, 0x4f, 0xf1, 0x8f, 0xf8, 0xf3, 0x4c, 0x97, 0x16, 0xa2, 0xf1, 0xb2,
0xbb, 0xef, 0xcd, 0xbc, 0x37, 0x3b, 0x0f, 0xce, 0x13, 0x99, 0x8c, 0xe5, 0x6a, 0x3d, 0x9b, 0xa7,
0xd1, 0x26, 0x9d, 0xc6, 0x99, 0x8c, 0x12, 0xb9, 0x5e, 0xc7, 0x2f, 0xd2, 0x4f, 0x57, 0xcb, 0x6c,
0x89, 0xff, 0xd5, 0x35, 0xde, 0x3c, 0x9f, 0xe1, 0x64, 0x16, 0x67, 0x3f, 0xab, 0x9d, 0xaf, 0x0a,
0xb4, 0xd8, 0xde, 0x61, 0xa4, 0x0c, 0xe8, 0xbb, 0x5c, 0x64, 0x78, 0x02, 0xb5, 0xc9, 0xdb, 0x72,
0xf2, 0xea, 0x68, 0xae, 0xe6, 0xe9, 0x62, 0x07, 0xd0, 0x01, 0xb3, 0x18, 0xe8, 0x54, 0xdc, 0xaa,
0x67, 0x89, 0x12, 0x22, 0x82, 0xbe, 0x88, 0x13, 0xe9, 0x54, 0x5d, 0xcd, 0xb3, 0x84, 0x7a, 0xe3,
0x35, 0xe8, 0xd9, 0x36, 0x95, 0x8e, 0xee, 0x6a, 0x5e, 0xb3, 0x7b, 0xe1, 0x97, 0x5f, 0xf1, 0xff,
0x1c, 0xe9, 0xab, 0x73, 0xb8, 0x4d, 0xa5, 0x50, 0xb2, 0xce, 0xa7, 0x06, 0xd6, 0x9e, 0xc3, 0x3a,
0x98, 0x23, 0x7e, 0xcf, 0x07, 0x4f, 0xdc, 0xfe, 0x87, 0x36, 0x34, 0xc2, 0x5e, 0x30, 0x8c, 0x42,
0x41, 0x83, 0x21, 0x25, 0xb6, 0x96, 0x33, 0x3c, 0x60, 0x34, 0x0a, 0x7b, 0x01, 0xbf, 0xa5, 0xc4,
0xae, 0xe0, 0x31, 0x1c, 0x31, 0xca, 0x6e, 0xa8, 0x78, 0x88, 0x02, 0x42, 0x28, 0xb1, 0xab, 0x07,
0x2a, 0xba, 0x1b, 0xf4, 0x39, 0x25, 0xb6, 0x8e, 0x08, 0xcd, 0x82, 0x12, 0x94, 0x0d, 0x1e, 0x29,
0xb1, 0x6b, 0xb9, 0x57, 0x40, 0x58, 0x9f, 0x97, 0x42, 0x23, 0x17, 0x2a, 0x66, 0xdf, 0x64, 0x76,
0x3e, 0xa0, 0xfd, 0x7b, 0x0d, 0xb6, 0xcb, 0x16, 0xdb, 0x60, 0xaa, 0xac, 0xe7, 0x53, 0x95, 0x9e,
0x25, 0x8c, 0x1c, 0xf6, 0xa7, 0x78, 0x0a, 0x86, 0xcc, 0x17, 0xda, 0xa5, 0xd7, 0x10, 0x05, 0xc2,
0xcb, 0x3c, 0x56, 0xa5, 0x55, 0xf9, 0xd5, 0xbb, 0xad, 0x43, 0x56, 0xe1, 0x2c, 0xce, 0x0a, 0x63,
0x51, 0x76, 0x8d, 0x0d, 0x55, 0xbe, 0xfa, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x7f, 0xb8, 0xe8, 0x9e,
0xff, 0x01, 0x00, 0x00,
}

View file

@ -0,0 +1,40 @@
syntax = "proto3";
package protobuf;
import "chat_message.proto";
message MembershipUpdateEvent {
// Lamport timestamp of the event
uint64 clock = 1;
// List of public keys of objects of the action
repeated string members = 2;
// Name of the chat for the CHAT_CREATED/NAME_CHANGED event types
string name = 3;
// The type of the event
EventType type = 4;
enum EventType {
UNKNOWN = 0;
CHAT_CREATED = 1;
NAME_CHANGED = 2;
MEMBERS_ADDED = 3;
MEMBER_JOINED = 4;
MEMBER_REMOVED = 5;
ADMINS_ADDED = 6;
ADMIN_REMOVED = 7;
}
}
// MembershipUpdateMessage is a message used to propagate information
// about group membership changes.
// For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
message MembershipUpdateMessage {
// The chat id of the private group chat
string chat_id = 1;
// A list of events for this group chat, first x bytes are the signature, then is a
// protobuf encoded MembershipUpdateEvent
repeated bytes events = 2;
// An optional chat message
ChatMessage message = 3;
}

View file

@ -1,421 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ChatMessage_MessageType int32
const (
ChatMessage_ONE_TO_ONE ChatMessage_MessageType = 0
ChatMessage_PUBLIC_GROUP ChatMessage_MessageType = 1
ChatMessage_PRIVATE_GROUP ChatMessage_MessageType = 2
// Only local
ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP ChatMessage_MessageType = 3
)
var ChatMessage_MessageType_name = map[int32]string{
0: "ONE_TO_ONE",
1: "PUBLIC_GROUP",
2: "PRIVATE_GROUP",
3: "SYSTEM_MESSAGE_PRIVATE_GROUP",
}
var ChatMessage_MessageType_value = map[string]int32{
"ONE_TO_ONE": 0,
"PUBLIC_GROUP": 1,
"PRIVATE_GROUP": 2,
"SYSTEM_MESSAGE_PRIVATE_GROUP": 3,
}
func (x ChatMessage_MessageType) String() string {
return proto.EnumName(ChatMessage_MessageType_name, int32(x))
}
func (ChatMessage_MessageType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{1, 0}
}
type ChatMessage_ContentType int32
const (
ChatMessage_TEXT_PLAIN ChatMessage_ContentType = 0
ChatMessage_STICKER ChatMessage_ContentType = 1
ChatMessage_STATUS ChatMessage_ContentType = 2
ChatMessage_EMOJI ChatMessage_ContentType = 3
ChatMessage_COMMAND ChatMessage_ContentType = 4
ChatMessage_COMMAND_REQUEST ChatMessage_ContentType = 5
)
var ChatMessage_ContentType_name = map[int32]string{
0: "TEXT_PLAIN",
1: "STICKER",
2: "STATUS",
3: "EMOJI",
4: "COMMAND",
5: "COMMAND_REQUEST",
}
var ChatMessage_ContentType_value = map[string]int32{
"TEXT_PLAIN": 0,
"STICKER": 1,
"STATUS": 2,
"EMOJI": 3,
"COMMAND": 4,
"COMMAND_REQUEST": 5,
}
func (x ChatMessage_ContentType) String() string {
return proto.EnumName(ChatMessage_ContentType_name, int32(x))
}
func (ChatMessage_ContentType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{1, 1}
}
type ApplicationMetadataMessage_MessageType int32
const (
ApplicationMetadataMessage_TEXT_MESSAGE ApplicationMetadataMessage_MessageType = 0
ApplicationMetadataMessage_CONTACT_REQUEST ApplicationMetadataMessage_MessageType = 1
ApplicationMetadataMessage_MEMBERSHIP_UPDATE ApplicationMetadataMessage_MessageType = 2
ApplicationMetadataMessage_PAIR_INSTALLATION ApplicationMetadataMessage_MessageType = 3
ApplicationMetadataMessage_SYNC_INSTALLATION ApplicationMetadataMessage_MessageType = 4
)
var ApplicationMetadataMessage_MessageType_name = map[int32]string{
0: "TEXT_MESSAGE",
1: "CONTACT_REQUEST",
2: "MEMBERSHIP_UPDATE",
3: "PAIR_INSTALLATION",
4: "SYNC_INSTALLATION",
}
var ApplicationMetadataMessage_MessageType_value = map[string]int32{
"TEXT_MESSAGE": 0,
"CONTACT_REQUEST": 1,
"MEMBERSHIP_UPDATE": 2,
"PAIR_INSTALLATION": 3,
"SYNC_INSTALLATION": 4,
}
func (x ApplicationMetadataMessage_MessageType) String() string {
return proto.EnumName(ApplicationMetadataMessage_MessageType_name, int32(x))
}
func (ApplicationMetadataMessage_MessageType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{2, 0}
}
type StickerMessage struct {
Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
Pack int32 `protobuf:"varint,2,opt,name=pack,proto3" json:"pack,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *StickerMessage) Reset() { *m = StickerMessage{} }
func (m *StickerMessage) String() string { return proto.CompactTextString(m) }
func (*StickerMessage) ProtoMessage() {}
func (*StickerMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{0}
}
func (m *StickerMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StickerMessage.Unmarshal(m, b)
}
func (m *StickerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_StickerMessage.Marshal(b, m, deterministic)
}
func (m *StickerMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_StickerMessage.Merge(m, src)
}
func (m *StickerMessage) XXX_Size() int {
return xxx_messageInfo_StickerMessage.Size(m)
}
func (m *StickerMessage) XXX_DiscardUnknown() {
xxx_messageInfo_StickerMessage.DiscardUnknown(m)
}
var xxx_messageInfo_StickerMessage proto.InternalMessageInfo
func (m *StickerMessage) GetHash() string {
if m != nil {
return m.Hash
}
return ""
}
func (m *StickerMessage) GetPack() int32 {
if m != nil {
return m.Pack
}
return 0
}
type ChatMessage struct {
// Lamport timestamp of the chat message
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
// Unix timestamps in milliseconds, currently not used as we use whisper as more reliable, but here
// so that we don't rely on it
Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// Text of the message
Text string `protobuf:"bytes,3,opt,name=text,proto3" json:"text,omitempty"`
// Id of the message that we are replying to
ResponseTo string `protobuf:"bytes,4,opt,name=response_to,json=responseTo,proto3" json:"response_to,omitempty"`
// Ens name of the sender
EnsName string `protobuf:"bytes,5,opt,name=ens_name,json=ensName,proto3" json:"ens_name,omitempty"`
// Chat id, this field is symmetric for public-chats and private group chats,
// but asymmetric in case of one-to-ones, as the sender will use the chat-id
// of the received, while the receiver will use the chat-id of the sender.
// Probably should be the concatenation of sender-pk & receiver-pk in alphabetical order
ChatId string `protobuf:"bytes,6,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
// The type of message (public/one-to-one/private-group-chat)
MessageType ChatMessage_MessageType `protobuf:"varint,7,opt,name=message_type,json=messageType,proto3,enum=protobuf.ChatMessage_MessageType" json:"message_type,omitempty"`
// The type of the content of the message
ContentType ChatMessage_ContentType `protobuf:"varint,8,opt,name=content_type,json=contentType,proto3,enum=protobuf.ChatMessage_ContentType" json:"content_type,omitempty"`
// Types that are valid to be assigned to Payload:
// *ChatMessage_Sticker
Payload isChatMessage_Payload `protobuf_oneof:"payload"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ChatMessage) Reset() { *m = ChatMessage{} }
func (m *ChatMessage) String() string { return proto.CompactTextString(m) }
func (*ChatMessage) ProtoMessage() {}
func (*ChatMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{1}
}
func (m *ChatMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChatMessage.Unmarshal(m, b)
}
func (m *ChatMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ChatMessage.Marshal(b, m, deterministic)
}
func (m *ChatMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ChatMessage.Merge(m, src)
}
func (m *ChatMessage) XXX_Size() int {
return xxx_messageInfo_ChatMessage.Size(m)
}
func (m *ChatMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ChatMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ChatMessage proto.InternalMessageInfo
func (m *ChatMessage) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
func (m *ChatMessage) GetTimestamp() uint64 {
if m != nil {
return m.Timestamp
}
return 0
}
func (m *ChatMessage) GetText() string {
if m != nil {
return m.Text
}
return ""
}
func (m *ChatMessage) GetResponseTo() string {
if m != nil {
return m.ResponseTo
}
return ""
}
func (m *ChatMessage) GetEnsName() string {
if m != nil {
return m.EnsName
}
return ""
}
func (m *ChatMessage) GetChatId() string {
if m != nil {
return m.ChatId
}
return ""
}
func (m *ChatMessage) GetMessageType() ChatMessage_MessageType {
if m != nil {
return m.MessageType
}
return ChatMessage_ONE_TO_ONE
}
func (m *ChatMessage) GetContentType() ChatMessage_ContentType {
if m != nil {
return m.ContentType
}
return ChatMessage_TEXT_PLAIN
}
type isChatMessage_Payload interface {
isChatMessage_Payload()
}
type ChatMessage_Sticker struct {
Sticker *StickerMessage `protobuf:"bytes,9,opt,name=sticker,proto3,oneof"`
}
func (*ChatMessage_Sticker) isChatMessage_Payload() {}
func (m *ChatMessage) GetPayload() isChatMessage_Payload {
if m != nil {
return m.Payload
}
return nil
}
func (m *ChatMessage) GetSticker() *StickerMessage {
if x, ok := m.GetPayload().(*ChatMessage_Sticker); ok {
return x.Sticker
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*ChatMessage) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*ChatMessage_Sticker)(nil),
}
}
type ApplicationMetadataMessage struct {
// Signature of the payload field
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
// This is the encoded protobuf of the application level message, i.e ChatMessage
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
// The type of protobuf message sent
MessageType ApplicationMetadataMessage_MessageType `protobuf:"varint,3,opt,name=message_type,json=messageType,proto3,enum=protobuf.ApplicationMetadataMessage_MessageType" json:"message_type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ApplicationMetadataMessage) Reset() { *m = ApplicationMetadataMessage{} }
func (m *ApplicationMetadataMessage) String() string { return proto.CompactTextString(m) }
func (*ApplicationMetadataMessage) ProtoMessage() {}
func (*ApplicationMetadataMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{2}
}
func (m *ApplicationMetadataMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplicationMetadataMessage.Unmarshal(m, b)
}
func (m *ApplicationMetadataMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplicationMetadataMessage.Marshal(b, m, deterministic)
}
func (m *ApplicationMetadataMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplicationMetadataMessage.Merge(m, src)
}
func (m *ApplicationMetadataMessage) XXX_Size() int {
return xxx_messageInfo_ApplicationMetadataMessage.Size(m)
}
func (m *ApplicationMetadataMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ApplicationMetadataMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ApplicationMetadataMessage proto.InternalMessageInfo
func (m *ApplicationMetadataMessage) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func (m *ApplicationMetadataMessage) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
func (m *ApplicationMetadataMessage) GetMessageType() ApplicationMetadataMessage_MessageType {
if m != nil {
return m.MessageType
}
return ApplicationMetadataMessage_TEXT_MESSAGE
}
func init() {
proto.RegisterEnum("protobuf.ChatMessage_MessageType", ChatMessage_MessageType_name, ChatMessage_MessageType_value)
proto.RegisterEnum("protobuf.ChatMessage_ContentType", ChatMessage_ContentType_name, ChatMessage_ContentType_value)
proto.RegisterEnum("protobuf.ApplicationMetadataMessage_MessageType", ApplicationMetadataMessage_MessageType_name, ApplicationMetadataMessage_MessageType_value)
proto.RegisterType((*StickerMessage)(nil), "protobuf.StickerMessage")
proto.RegisterType((*ChatMessage)(nil), "protobuf.ChatMessage")
proto.RegisterType((*ApplicationMetadataMessage)(nil), "protobuf.ApplicationMetadataMessage")
}
func init() { proto.RegisterFile("message.proto", fileDescriptor_33c57e4bae7b9afd) }
var fileDescriptor_33c57e4bae7b9afd = []byte{
// 563 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x5f, 0x6f, 0xda, 0x3e,
0x14, 0x25, 0x10, 0xa0, 0xdc, 0xd0, 0xfe, 0x5c, 0xff, 0x36, 0x2d, 0x9b, 0x2a, 0x8d, 0xf1, 0xc4,
0x13, 0x9a, 0xba, 0x3d, 0xec, 0x35, 0x4d, 0xad, 0x36, 0x1b, 0xf9, 0x33, 0xdb, 0x4c, 0xeb, 0x93,
0xe5, 0x06, 0xaf, 0xa0, 0x96, 0x24, 0x22, 0xae, 0x34, 0xbe, 0xcf, 0x3e, 0xc9, 0x3e, 0xd9, 0x14,
0x07, 0x0a, 0x4c, 0xea, 0x9e, 0xec, 0x73, 0x7c, 0x7d, 0xee, 0xbd, 0xe7, 0x5e, 0x38, 0x5e, 0xaa,
0xb2, 0x94, 0x77, 0x6a, 0x5c, 0xac, 0x72, 0x9d, 0xe3, 0x23, 0x73, 0xdc, 0x3e, 0xfe, 0x18, 0x7e,
0x82, 0x13, 0xa6, 0x17, 0xe9, 0xbd, 0x5a, 0x85, 0x75, 0x04, 0xc6, 0x60, 0xcf, 0x65, 0x39, 0x77,
0xad, 0x81, 0x35, 0xea, 0x51, 0x73, 0xaf, 0xb8, 0x42, 0xa6, 0xf7, 0x6e, 0x73, 0x60, 0x8d, 0xda,
0xd4, 0xdc, 0x87, 0xbf, 0x6d, 0x70, 0xfc, 0xb9, 0xd4, 0xdb, 0x7f, 0x2f, 0xa0, 0x9d, 0x3e, 0xe4,
0xe9, 0xbd, 0xf9, 0x68, 0xd3, 0x1a, 0xe0, 0x33, 0xe8, 0xe9, 0xc5, 0x52, 0x95, 0x5a, 0x2e, 0x0b,
0xf3, 0xdd, 0xa6, 0x3b, 0xa2, 0xd2, 0xd5, 0xea, 0xa7, 0x76, 0x5b, 0x75, 0xae, 0xea, 0x8e, 0xdf,
0x82, 0xb3, 0x52, 0x65, 0x91, 0x67, 0xa5, 0x12, 0x3a, 0x77, 0x6d, 0xf3, 0x04, 0x5b, 0x8a, 0xe7,
0xf8, 0x35, 0x1c, 0xa9, 0xac, 0x14, 0x99, 0x5c, 0x2a, 0xb7, 0x6d, 0x5e, 0xbb, 0x2a, 0x2b, 0x23,
0xb9, 0x54, 0xf8, 0x15, 0x74, 0xd3, 0xb9, 0xd4, 0x62, 0x31, 0x73, 0x3b, 0xe6, 0xa5, 0x53, 0xc1,
0x60, 0x86, 0x2f, 0xa1, 0xbf, 0x71, 0x40, 0xe8, 0x75, 0xa1, 0xdc, 0xee, 0xc0, 0x1a, 0x9d, 0x9c,
0xbf, 0x1b, 0x6f, 0x7d, 0x18, 0xef, 0x75, 0x32, 0xde, 0x9c, 0x7c, 0x5d, 0x28, 0xea, 0x2c, 0x77,
0xa0, 0x52, 0x49, 0xf3, 0x4c, 0xab, 0x4c, 0xd7, 0x2a, 0x47, 0xff, 0x52, 0xf1, 0xeb, 0xc8, 0x5a,
0x25, 0xdd, 0x01, 0xfc, 0x11, 0xba, 0x65, 0x6d, 0xb9, 0xdb, 0x1b, 0x58, 0x23, 0xe7, 0xdc, 0xdd,
0x09, 0x1c, 0xce, 0xe2, 0xba, 0x41, 0xb7, 0xa1, 0xc3, 0x19, 0x38, 0x7b, 0x75, 0xe1, 0x13, 0x80,
0x38, 0x22, 0x82, 0xc7, 0x22, 0x8e, 0x08, 0x6a, 0x60, 0x04, 0xfd, 0x64, 0x7a, 0x31, 0x09, 0x7c,
0x71, 0x45, 0xe3, 0x69, 0x82, 0x2c, 0x7c, 0x0a, 0xc7, 0x09, 0x0d, 0xbe, 0x79, 0x9c, 0x6c, 0xa8,
0x26, 0x1e, 0xc0, 0x19, 0xbb, 0x61, 0x9c, 0x84, 0x22, 0x24, 0x8c, 0x79, 0x57, 0x44, 0x1c, 0x46,
0xb4, 0x86, 0x29, 0x38, 0x7b, 0x75, 0x57, 0x59, 0x38, 0xf9, 0xce, 0x45, 0x32, 0xf1, 0x82, 0x08,
0x35, 0xb0, 0x03, 0x5d, 0xc6, 0x03, 0xff, 0x0b, 0xa1, 0xc8, 0xc2, 0x00, 0x1d, 0xc6, 0x3d, 0x3e,
0x65, 0xa8, 0x89, 0x7b, 0xd0, 0x26, 0x61, 0xfc, 0x39, 0x40, 0xad, 0x2a, 0xc6, 0x8f, 0xc3, 0xd0,
0x8b, 0x2e, 0x91, 0x8d, 0xff, 0x87, 0xff, 0x36, 0x40, 0x50, 0xf2, 0x75, 0x4a, 0x18, 0x47, 0xed,
0x8b, 0x1e, 0x74, 0x0b, 0xb9, 0x7e, 0xc8, 0xe5, 0x6c, 0xf8, 0xab, 0x09, 0x6f, 0xbc, 0xa2, 0x78,
0x58, 0xa4, 0x52, 0x2f, 0xf2, 0x2c, 0x54, 0x5a, 0xce, 0xa4, 0x96, 0xdb, 0x9d, 0x3a, 0x83, 0x5e,
0xb9, 0xb8, 0xcb, 0xa4, 0x7e, 0x5c, 0x29, 0xb3, 0x57, 0x7d, 0xba, 0x23, 0xb0, 0xfb, 0xa4, 0x63,
0x36, 0xab, 0x4f, 0xb7, 0x10, 0xb3, 0xbf, 0xc6, 0xdd, 0x32, 0x83, 0x7a, 0xbf, 0xf3, 0xf9, 0xf9,
0x9c, 0xcf, 0x4e, 0x7f, 0xb8, 0x3e, 0x9c, 0x00, 0x82, 0xbe, 0xf1, 0x66, 0x63, 0x25, 0x6a, 0xd4,
0xcd, 0x46, 0xdc, 0xf3, 0xf9, 0x53, 0xb3, 0x16, 0x7e, 0x09, 0xa7, 0x21, 0x09, 0x2f, 0x08, 0x65,
0xd7, 0x41, 0x22, 0xa6, 0xc9, 0xa5, 0xc7, 0x09, 0x6a, 0x56, 0x74, 0xe2, 0x05, 0x54, 0x04, 0x11,
0xe3, 0xde, 0x64, 0xe2, 0xf1, 0x20, 0x8e, 0x50, 0xab, 0xa2, 0xd9, 0x4d, 0xe4, 0x1f, 0xd2, 0xf6,
0x6d, 0xc7, 0x14, 0xfe, 0xe1, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf6, 0xa4, 0x11, 0xfe, 0xc7,
0x03, 0x00, 0x00,
}

View file

@ -4,7 +4,7 @@ import (
"github.com/golang/protobuf/proto"
)
//go:generate protoc --go_out=. ./message.proto
//go:generate protoc --go_out=. ./chat_message.proto ./application_metadata_message.proto ./membership_update_message.proto
func Unmarshal(payload []byte) (*ApplicationMetadataMessage, error) {
var message ApplicationMetadataMessage

View file

@ -2,17 +2,17 @@ package protocol
import "time"
const clockBumpInMs = int64(time.Minute / time.Millisecond)
const clockBumpInMs = uint64(time.Minute / time.Millisecond)
// CalcMessageClock calculates a new clock value for Message.
// It is used to properly sort messages and accommodate the fact
// that time might be different on each device.
func CalcMessageClock(lastObservedValue int64, timeInMs TimestampInMs) int64 {
func CalcMessageClock(lastObservedValue uint64, timeInMs uint64) uint64 {
clock := lastObservedValue
if clock < int64(timeInMs) {
if clock < timeInMs {
// Added time should be larger than time skew tollerance for a message.
// Here, we use 1 minute which is larger than accepted message time skew by Whisper.
clock = int64(timeInMs) + clockBumpInMs
clock = timeInMs + clockBumpInMs
} else {
clock++
}

View file

@ -1,7 +1,6 @@
package protocol
import (
"container/list"
"errors"
"fmt"
"io"
@ -15,14 +14,12 @@ import (
func NewMessageDecoder(r io.Reader) *transit.Decoder {
decoder := transit.NewDecoder(r)
decoder.AddHandler(pairMessageTag, pairMessageHandler)
decoder.AddHandler(membershipUpdateTag, membershipUpdateMessageHandler)
return decoder
}
const (
messageTag = "c4"
pairMessageTag = "p2"
membershipUpdateTag = "g5"
messageTag = "c4"
pairMessageTag = "p2"
)
func pairMessageHandler(d transit.Decoder, value interface{}) (interface{}, error) {
@ -60,83 +57,6 @@ func pairMessageHandler(d transit.Decoder, value interface{}) (interface{}, erro
return pm, nil
}
func membershipUpdateMessageHandler(d transit.Decoder, value interface{}) (interface{}, error) {
taggedValue, ok := value.(transit.TaggedValue)
if !ok {
return nil, errors.New("not a tagged value")
}
values, ok := taggedValue.Value.([]interface{})
if !ok {
return nil, errors.New("tagged value does not contain values")
}
m := MembershipUpdateMessage{}
for idx, v := range values {
var ok bool
switch idx {
case 0:
m.ChatID, ok = v.(string)
case 1:
var updates *list.List
updates, ok = v.(*list.List)
if !ok {
break
}
for e := updates.Front(); e != nil; e = e.Next() {
var value map[interface{}]interface{}
value, ok = e.Value.(map[interface{}]interface{})
if !ok {
break
}
update := MembershipUpdate{}
update.ChatID, ok = value[transit.Keyword("chat-id")].(string)
if !ok {
break
}
update.Signature, ok = value[transit.Keyword("signature")].(string)
if !ok {
break
}
// parse events
var events []interface{}
events, ok = value[transit.Keyword("events")].([]interface{})
if !ok {
break
}
for _, item := range events {
var event map[interface{}]interface{}
event, ok = item.(map[interface{}]interface{})
if !ok {
break
}
var updateEvent MembershipUpdateEvent
updateEvent, ok = parseEvent(event)
if !ok {
break
}
update.Events = append(update.Events, updateEvent)
}
m.Updates = append(m.Updates, update)
}
default:
// skip any other values
ok = true
}
if !ok {
return nil, fmt.Errorf("invalid value for index: %d", idx)
}
}
return m, nil
}
func setToString(set *transit.Set) ([]string, bool) {
result := make([]string, 0, len(set.Contents))
for _, item := range set.Contents {
@ -148,43 +68,3 @@ func setToString(set *transit.Set) ([]string, bool) {
}
return result, true
}
func parseEvent(event map[interface{}]interface{}) (result MembershipUpdateEvent, ok bool) {
// Type is required
result.Type, ok = event[transit.Keyword("type")].(string)
if !ok {
return
}
// ClockValue is required
result.ClockValue, ok = event[transit.Keyword("clock-value")].(int64)
if !ok {
return
}
// Name is optional
if val, exists := event[transit.Keyword("name")]; exists {
result.Name, ok = val.(string)
if !ok {
return
}
}
// Member is optional
if val, exists := event[transit.Keyword("member")]; exists {
result.Member, ok = val.(string)
if !ok {
return
}
}
// Members is optional
if val, exists := event[transit.Keyword("members")]; exists {
var members *transit.Set
members, ok = val.(*transit.Set)
if !ok {
return
}
result.Members, ok = setToString(members)
if !ok {
return
}
}
return
}

View file

@ -1,7 +1,6 @@
package protocol
import (
"container/list"
"errors"
"io"
"reflect"
@ -10,8 +9,7 @@ import (
)
var (
pairMessageType = reflect.TypeOf(PairMessage{})
membershipUpdateType = reflect.TypeOf(MembershipUpdateMessage{})
pairMessageType = reflect.TypeOf(PairMessage{})
defaultMessageValueEncoder = &messageValueEncoder{}
)
@ -22,7 +20,6 @@ var (
func NewMessageEncoder(w io.Writer) *transit.Encoder {
encoder := transit.NewEncoder(w, false)
encoder.AddHandler(pairMessageType, defaultMessageValueEncoder)
encoder.AddHandler(membershipUpdateType, defaultMessageValueEncoder)
return encoder
}
@ -45,47 +42,6 @@ func (messageValueEncoder) Encode(e transit.Encoder, value reflect.Value, asStri
},
}
return e.EncodeInterface(taggedValue, false)
case MembershipUpdateMessage:
updatesList := list.New()
for _, update := range message.Updates {
var events []interface{}
for _, event := range update.Events {
eventMap := map[interface{}]interface{}{
transit.Keyword("type"): event.Type,
transit.Keyword("clock-value"): event.ClockValue,
}
if event.Name != "" {
eventMap[transit.Keyword("name")] = event.Name
}
if event.Member != "" {
eventMap[transit.Keyword("member")] = event.Member
}
if len(event.Members) > 0 {
members := make([]interface{}, len(event.Members))
for idx, m := range event.Members {
members[idx] = m
}
eventMap[transit.Keyword("members")] = transit.NewSet(members)
}
events = append(events, eventMap)
}
element := map[interface{}]interface{}{
transit.Keyword("chat-id"): update.ChatID,
transit.Keyword("events"): events,
transit.Keyword("signature"): update.Signature,
}
updatesList.PushBack(element)
}
value := []interface{}{
message.ChatID,
updatesList,
}
taggedValue := transit.TaggedValue{
Tag: membershipUpdateTag,
Value: value,
}
return e.EncodeInterface(taggedValue, false)
}
return errors.New("unknown message type to encode")

View file

@ -3,145 +3,147 @@ package protocol
import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"sort"
"strings"
"time"
"github.com/golang/protobuf/proto"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
const (
MembershipUpdateChatCreated = "chat-created"
MembershipUpdateNameChanged = "name-changed"
MembershipUpdateMembersAdded = "members-added"
MembershipUpdateMemberJoined = "member-joined"
MembershipUpdateMemberRemoved = "member-removed"
MembershipUpdateAdminsAdded = "admins-added"
MembershipUpdateAdminRemoved = "admin-removed"
"github.com/status-im/status-go/protocol/protobuf"
)
// MembershipUpdateMessage is a message used to propagate information
// about group membership changes.
// For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
type MembershipUpdateMessage struct {
ChatID string `json:"chatId"` // UUID concatenated with hex-encoded public key of the creator for the chat
Updates []MembershipUpdate `json:"updates"`
ChatID string `json:"chatId"` // UUID concatenated with hex-encoded public key of the creator for the chat
Events []MembershipUpdateEvent `json:"events"`
Message *protobuf.ChatMessage `json:"-"`
}
// Verify makes sure that the received update message has a valid signature.
// It also extracts public key from the signature available as From field.
// It does not verify the updates and their events. This should be done
// separately using Group struct.
func (m *MembershipUpdateMessage) Verify() error {
for idx, update := range m.Updates {
if err := update.extractFrom(); err != nil {
return errors.Wrapf(err, "failed to extract an author of %d update", idx)
}
m.Updates[idx] = update
const signatureLength = 65
func MembershipUpdateEventFromProtobuf(chatID string, raw []byte) (*MembershipUpdateEvent, error) {
if len(raw) <= signatureLength {
return nil, errors.New("invalid payload length")
}
return nil
}
decodedEvent := protobuf.MembershipUpdateEvent{}
signature := raw[:signatureLength]
encodedEvent := raw[signatureLength:]
// EncodeMembershipUpdateMessage encodes a MembershipUpdateMessage using Transit serialization.
func EncodeMembershipUpdateMessage(value MembershipUpdateMessage) ([]byte, error) {
var buf bytes.Buffer
encoder := NewMessageEncoder(&buf)
if err := encoder.Encode(value); err != nil {
signatureMaterial := append([]byte(chatID), encodedEvent...)
publicKey, err := crypto.ExtractSignature(signatureMaterial, signature)
if err != nil {
return nil, errors.Wrap(err, "failed to extract signature")
}
from := types.EncodeHex(crypto.FromECDSAPub(publicKey))
err = proto.Unmarshal(encodedEvent, &decodedEvent)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
return &MembershipUpdateEvent{
ClockValue: decodedEvent.Clock,
ChatID: chatID,
Members: decodedEvent.Members,
Name: decodedEvent.Name,
Type: decodedEvent.Type,
Signature: signature,
RawPayload: encodedEvent,
From: from,
}, nil
}
type MembershipUpdate struct {
ChatID string `json:"chatId"`
Signature string `json:"signature"` // hex-encoded without 0x prefix
Events []MembershipUpdateEvent `json:"events"`
From string `json:"from"` // hex-encoded with 0x prefix
func (m *MembershipUpdateMessage) ToProtobuf() *protobuf.MembershipUpdateMessage {
var rawEvents [][]byte
for _, e := range m.Events {
var encodedEvent []byte
encodedEvent = append(encodedEvent, e.Signature...)
encodedEvent = append(encodedEvent, e.RawPayload...)
rawEvents = append(rawEvents, encodedEvent)
}
return &protobuf.MembershipUpdateMessage{
ChatId: m.ChatID,
Events: rawEvents,
Message: m.Message,
}
}
// Sign creates a signature from MembershipUpdateEvents
// and updates MembershipUpdate's signature.
// It follows the algorithm describe in the spec:
// https://github.com/status-im/specs/blob/master/status-group-chats-spec.md#signature.
func (u *MembershipUpdate) Sign(identity *ecdsa.PrivateKey) error {
signature, err := createMembershipUpdateSignature(u.ChatID, u.Events, identity)
if err != nil {
return err
func MembershipUpdateMessageFromProtobuf(raw *protobuf.MembershipUpdateMessage) (*MembershipUpdateMessage, error) {
var events []MembershipUpdateEvent
for _, e := range raw.Events {
verifiedEvent, err := MembershipUpdateEventFromProtobuf(raw.ChatId, e)
if err != nil {
return nil, err
}
events = append(events, *verifiedEvent)
}
u.Signature = signature
return nil
return &MembershipUpdateMessage{
ChatID: raw.ChatId,
Events: events,
Message: raw.Message,
}, nil
}
func (u *MembershipUpdate) extractFrom() error {
content, err := stringifyMembershipUpdateEvents(u.ChatID, u.Events)
if err != nil {
return errors.Wrap(err, "failed to stringify events")
}
signatureBytes, err := hex.DecodeString(u.Signature)
if err != nil {
return errors.Wrap(err, "failed to decode signature")
}
publicKey, err := crypto.ExtractSignature(content, signatureBytes)
if err != nil {
return errors.Wrap(err, "failed to extract signature")
}
u.From = types.EncodeHex(crypto.FromECDSAPub(publicKey))
return nil
}
func (u *MembershipUpdate) Flat() []MembershipUpdateFlat {
result := make([]MembershipUpdateFlat, 0, len(u.Events))
for _, event := range u.Events {
result = append(result, MembershipUpdateFlat{
MembershipUpdateEvent: event,
ChatID: u.ChatID,
Signature: u.Signature,
From: u.From,
})
}
return result
// EncodeMembershipUpdateMessage encodes a MembershipUpdateMessage using protobuf serialization.
func EncodeMembershipUpdateMessage(value MembershipUpdateMessage) ([]byte, error) {
return proto.Marshal(value.ToProtobuf())
}
// MembershipUpdateEvent contains an event information.
// Member and Members are hex-encoded values with 0x prefix.
type MembershipUpdateEvent struct {
Type string `json:"type"`
ClockValue int64 `json:"clockValue"`
Member string `json:"member,omitempty"` // in "member-joined", "member-removed" and "admin-removed" events
Members []string `json:"members,omitempty"` // in "members-added" and "admins-added" events
Name string `json:"name,omitempty"` // name of the group chat
Type protobuf.MembershipUpdateEvent_EventType `json:"type"`
ClockValue uint64 `json:"clockValue"`
Members []string `json:"members,omitempty"` // in "members-added" and "admins-added" events
Name string `json:"name,omitempty"` // name of the group chat
From string
Signature []byte
ChatID string
RawPayload []byte
}
func (u MembershipUpdateEvent) Equal(update MembershipUpdateEvent) bool {
return u.Type == update.Type &&
u.ClockValue == update.ClockValue &&
u.Member == update.Member &&
stringSliceEquals(u.Members, update.Members) &&
u.Name == update.Name
func (u *MembershipUpdateEvent) Equal(update MembershipUpdateEvent) bool {
return bytes.Compare(u.Signature, update.Signature) == 0
}
type MembershipUpdateFlat struct {
MembershipUpdateEvent
ChatID string `json:"chatId"`
Signature string `json:"signature"`
From string `json:"from"`
func (u *MembershipUpdateEvent) Sign(key *ecdsa.PrivateKey) error {
if len(u.ChatID) == 0 {
return errors.New("can't sign with empty chatID")
}
encodedEvent, err := proto.Marshal(u.ToProtobuf())
if err != nil {
return err
}
u.RawPayload = encodedEvent
var signatureMaterial []byte
signatureMaterial = append(signatureMaterial, []byte(u.ChatID)...)
signatureMaterial = crypto.Keccak256(append(signatureMaterial, u.RawPayload...))
signature, err := crypto.Sign(signatureMaterial, key)
if err != nil {
return err
}
u.Signature = signature
u.From = types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey))
return nil
}
func (u MembershipUpdateFlat) Equal(update MembershipUpdateFlat) bool {
return u.ChatID == update.ChatID &&
u.Signature == update.Signature &&
u.From == update.From &&
u.MembershipUpdateEvent.Equal(update.MembershipUpdateEvent)
func (u *MembershipUpdateEvent) ToProtobuf() *protobuf.MembershipUpdateEvent {
return &protobuf.MembershipUpdateEvent{
Clock: u.ClockValue,
Name: u.Name,
Members: u.Members,
Type: u.Type,
}
}
func MergeFlatMembershipUpdates(dest []MembershipUpdateFlat, src []MembershipUpdateFlat) []MembershipUpdateFlat {
func MergeMembershipUpdateEvents(dest []MembershipUpdateEvent, src []MembershipUpdateEvent) []MembershipUpdateEvent {
for _, update := range src {
var exists bool
for _, existing := range dest {
@ -157,166 +159,101 @@ func MergeFlatMembershipUpdates(dest []MembershipUpdateFlat, src []MembershipUpd
return dest
}
func NewChatCreatedEvent(name string, admin string, clock int64) MembershipUpdateEvent {
func NewChatCreatedEvent(name string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateChatCreated,
Name: name,
Member: admin,
ClockValue: clock,
}
}
func NewNameChangedEvent(name string, clock int64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateNameChanged,
Type: protobuf.MembershipUpdateEvent_CHAT_CREATED,
Name: name,
ClockValue: clock,
}
}
func NewMembersAddedEvent(members []string, clock int64) MembershipUpdateEvent {
func NewNameChangedEvent(name string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateMembersAdded,
Type: protobuf.MembershipUpdateEvent_NAME_CHANGED,
Name: name,
ClockValue: clock,
}
}
func NewMembersAddedEvent(members []string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: protobuf.MembershipUpdateEvent_MEMBERS_ADDED,
Members: members,
ClockValue: clock,
}
}
func NewMemberJoinedEvent(member string, clock int64) MembershipUpdateEvent {
func NewMemberJoinedEvent(clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateMemberJoined,
Member: member,
Type: protobuf.MembershipUpdateEvent_MEMBER_JOINED,
ClockValue: clock,
}
}
func NewAdminsAddedEvent(admins []string, clock int64) MembershipUpdateEvent {
func NewAdminsAddedEvent(admins []string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateAdminsAdded,
Type: protobuf.MembershipUpdateEvent_ADMINS_ADDED,
Members: admins,
ClockValue: clock,
}
}
func NewMemberRemovedEvent(member string, clock int64) MembershipUpdateEvent {
func NewMemberRemovedEvent(member string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateMemberRemoved,
Member: member,
Type: protobuf.MembershipUpdateEvent_MEMBER_REMOVED,
Members: []string{member},
ClockValue: clock,
}
}
func NewAdminRemovedEvent(admin string, clock int64) MembershipUpdateEvent {
func NewAdminRemovedEvent(admin string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateAdminRemoved,
Member: admin,
Type: protobuf.MembershipUpdateEvent_ADMIN_REMOVED,
Members: []string{admin},
ClockValue: clock,
}
}
func stringifyMembershipUpdateEvents(chatID string, events []MembershipUpdateEvent) ([]byte, error) {
sort.Slice(events, func(i, j int) bool {
return events[i].ClockValue < events[j].ClockValue
})
tuples := make([]interface{}, len(events))
for idx, event := range events {
tuples[idx] = tupleMembershipUpdateEvent(event)
}
structureToSign := []interface{}{
tuples,
chatID,
}
return json.Marshal(structureToSign)
}
func createMembershipUpdateSignature(chatID string, events []MembershipUpdateEvent, identity *ecdsa.PrivateKey) (string, error) {
data, err := stringifyMembershipUpdateEvents(chatID, events)
if err != nil {
return "", err
}
return crypto.SignBytesAsHex(data, identity)
}
var membershipUpdateEventFieldNamesCompat = map[string]string{
"ClockValue": "clock-value",
"Name": "name",
"Type": "type",
"Member": "member",
"Members": "members",
}
func tupleMembershipUpdateEvent(update MembershipUpdateEvent) [][]interface{} {
// Sort all slices first.
sort.Slice(update.Members, func(i, j int) bool {
return update.Members[i] < update.Members[j]
})
v := reflect.ValueOf(update)
result := make([][]interface{}, 0, v.NumField())
for i := 0; i < v.NumField(); i++ {
fieldName := v.Type().Field(i).Name
if name, exists := membershipUpdateEventFieldNamesCompat[fieldName]; exists {
fieldName = name
}
field := v.Field(i)
if !isZeroValue(field) {
result = append(result, []interface{}{fieldName, field.Interface()})
}
}
// Sort the result lexicographically.
// We know that the first item of a tuple is a string
// because it's a field name.
sort.Slice(result, func(i, j int) bool {
return result[i][0].(string) < result[j][0].(string)
})
return result
}
type Group struct {
chatID string
name string
updates []MembershipUpdateFlat
events []MembershipUpdateEvent
admins *stringSet
members *stringSet
joined *stringSet
}
func groupChatID(creator *ecdsa.PublicKey) string {
return uuid.New().String() + "-" + types.EncodeHex(crypto.FromECDSAPub(creator))
}
func NewGroupWithMembershipUpdates(chatID string, updates []MembershipUpdate) (*Group, error) {
flatten := make([]MembershipUpdateFlat, 0, len(updates))
for _, update := range updates {
flatten = append(flatten, update.Flat()...)
}
return newGroup(chatID, flatten)
func NewGroupWithEvents(chatID string, events []MembershipUpdateEvent) (*Group, error) {
return newGroup(chatID, events)
}
func NewGroupWithCreator(name string, creator *ecdsa.PrivateKey) (*Group, error) {
chatID := groupChatID(&creator.PublicKey)
creatorHex := publicKeyToString(&creator.PublicKey)
clock := TimestampInMsFromTime(time.Now())
chatCreated := NewChatCreatedEvent(name, creatorHex, int64(clock))
update := MembershipUpdate{
ChatID: chatID,
From: creatorHex,
Events: []MembershipUpdateEvent{chatCreated},
}
if err := update.Sign(creator); err != nil {
chatCreated := NewChatCreatedEvent(name, clock)
chatCreated.ChatID = chatID
err := chatCreated.Sign(creator)
if err != nil {
return nil, err
}
return newGroup(chatID, update.Flat())
return newGroup(chatID, []MembershipUpdateEvent{chatCreated})
}
func NewGroup(chatID string, updates []MembershipUpdateFlat) (*Group, error) {
return newGroup(chatID, updates)
func NewGroup(chatID string, events []MembershipUpdateEvent) (*Group, error) {
return newGroup(chatID, events)
}
func newGroup(chatID string, updates []MembershipUpdateFlat) (*Group, error) {
func newGroup(chatID string, events []MembershipUpdateEvent) (*Group, error) {
g := Group{
chatID: chatID,
updates: updates,
events: events,
admins: newStringSet(),
members: newStringSet(),
joined: newStringSet(),
}
if err := g.init(); err != nil {
return nil, err
@ -329,17 +266,17 @@ func (g *Group) init() error {
var chatID string
for _, update := range g.updates {
for _, event := range g.events {
if chatID == "" {
chatID = update.ChatID
} else if update.ChatID != chatID {
chatID = event.ChatID
} else if event.ChatID != chatID {
return errors.New("updates contain different chat IDs")
}
valid := g.validateEvent(update.From, update.MembershipUpdateEvent)
valid := g.validateEvent(event)
if !valid {
return fmt.Errorf("invalid event %#+v from %s", update.MembershipUpdateEvent, update.From)
return fmt.Errorf("invalid event %#+v from %s", event, event.From)
}
g.processEvent(update.From, update.MembershipUpdateEvent)
g.processEvent(event)
}
valid := g.validateChatID(g.chatID)
@ -357,8 +294,8 @@ func (g Group) ChatID() string {
return g.chatID
}
func (g Group) Updates() []MembershipUpdateFlat {
return g.updates
func (g Group) Events() []MembershipUpdateEvent {
return g.events
}
func (g Group) Name() string {
@ -374,18 +311,12 @@ func (g Group) Admins() []string {
}
func (g Group) Joined() []string {
var result []string
for _, update := range g.updates {
if update.Type == MembershipUpdateMemberJoined {
result = append(result, update.Member)
}
}
return result
return g.joined.List()
}
func (g *Group) ProcessEvents(from *ecdsa.PublicKey, events []MembershipUpdateEvent) error {
func (g *Group) ProcessEvents(events []MembershipUpdateEvent) error {
for _, event := range events {
err := g.ProcessEvent(from, event)
err := g.ProcessEvent(event)
if err != nil {
return err
}
@ -393,38 +324,33 @@ func (g *Group) ProcessEvents(from *ecdsa.PublicKey, events []MembershipUpdateEv
return nil
}
func (g *Group) ProcessEvent(from *ecdsa.PublicKey, event MembershipUpdateEvent) error {
fromHex := types.EncodeHex(crypto.FromECDSAPub(from))
if !g.validateEvent(fromHex, event) {
return fmt.Errorf("invalid event %#+v from %s", event, from)
func (g *Group) ProcessEvent(event MembershipUpdateEvent) error {
if !g.validateEvent(event) {
return fmt.Errorf("invalid event %#+v", event)
}
update := MembershipUpdate{
ChatID: g.chatID,
From: fromHex,
Events: []MembershipUpdateEvent{event},
}
g.updates = append(g.updates, update.Flat()...)
g.processEvent(fromHex, event)
// Check if exists
g.events = append(g.events, event)
g.processEvent(event)
return nil
}
func (g Group) LastClockValue() int64 {
if len(g.updates) == 0 {
func (g Group) LastClockValue() uint64 {
if len(g.events) == 0 {
return 0
}
return g.updates[len(g.updates)-1].ClockValue
return g.events[len(g.events)-1].ClockValue
}
func (g Group) NextClockValue() int64 {
func (g Group) NextClockValue() uint64 {
return g.LastClockValue() + 1
}
func (g Group) creator() (string, error) {
if len(g.updates) == 0 {
if len(g.events) == 0 {
return "", errors.New("no events in the group")
}
first := g.updates[0]
if first.Type != MembershipUpdateChatCreated {
first := g.events[0]
if first.Type != protobuf.MembershipUpdateEvent_CHAT_CREATED {
return "", fmt.Errorf("expected first event to be 'chat-created', got %s", first.Type)
}
return first.From, nil
@ -440,53 +366,63 @@ func (g Group) validateChatID(chatID string) bool {
return strings.HasSuffix(chatID, creator) && chatID != creator
}
func (g Group) IsMember(id string) bool {
return g.members.Has(id)
}
// validateEvent returns true if a given event is valid.
func (g Group) validateEvent(from string, event MembershipUpdateEvent) bool {
func (g Group) validateEvent(event MembershipUpdateEvent) bool {
if len(event.From) == 0 {
return false
}
switch event.Type {
case MembershipUpdateChatCreated:
case protobuf.MembershipUpdateEvent_CHAT_CREATED:
return g.admins.Empty() && g.members.Empty()
case MembershipUpdateNameChanged:
return g.admins.Has(from) && len(event.Name) > 0
case MembershipUpdateMembersAdded:
return g.admins.Has(from)
case MembershipUpdateMemberJoined:
return g.members.Has(from) && from == event.Member
case MembershipUpdateMemberRemoved:
case protobuf.MembershipUpdateEvent_NAME_CHANGED:
return g.admins.Has(event.From) && len(event.Name) > 0
case protobuf.MembershipUpdateEvent_MEMBERS_ADDED:
return g.admins.Has(event.From)
case protobuf.MembershipUpdateEvent_MEMBER_JOINED:
return g.members.Has(event.From)
case protobuf.MembershipUpdateEvent_MEMBER_REMOVED:
// Member can remove themselves or admin can remove a member.
return from == event.Member || (g.admins.Has(from) && !g.admins.Has(event.Member))
case MembershipUpdateAdminsAdded:
return g.admins.Has(from) && stringSliceSubset(event.Members, g.members.List())
case MembershipUpdateAdminRemoved:
return g.admins.Has(from) && from == event.Member
return len(event.Members) == 1 && (event.From == event.Members[0] || (g.admins.Has(event.From) && !g.admins.Has(event.Members[0])))
case protobuf.MembershipUpdateEvent_ADMINS_ADDED:
return g.admins.Has(event.From) && stringSliceSubset(event.Members, g.members.List())
case protobuf.MembershipUpdateEvent_ADMIN_REMOVED:
return len(event.Members) == 1 && g.admins.Has(event.From) && event.From == event.Members[0]
default:
return false
}
}
func (g *Group) processEvent(from string, event MembershipUpdateEvent) {
func (g *Group) processEvent(event MembershipUpdateEvent) {
switch event.Type {
case MembershipUpdateChatCreated:
case protobuf.MembershipUpdateEvent_CHAT_CREATED:
g.name = event.Name
g.members.Add(event.Member)
g.admins.Add(event.Member)
case MembershipUpdateNameChanged:
g.members.Add(event.From)
g.joined.Add(event.From)
g.admins.Add(event.From)
case protobuf.MembershipUpdateEvent_NAME_CHANGED:
g.name = event.Name
case MembershipUpdateAdminsAdded:
case protobuf.MembershipUpdateEvent_ADMINS_ADDED:
g.admins.Add(event.Members...)
case MembershipUpdateAdminRemoved:
g.admins.Remove(event.Member)
case MembershipUpdateMembersAdded:
case protobuf.MembershipUpdateEvent_ADMIN_REMOVED:
g.admins.Remove(event.Members[0])
case protobuf.MembershipUpdateEvent_MEMBERS_ADDED:
g.members.Add(event.Members...)
case MembershipUpdateMemberRemoved:
g.members.Remove(event.Member)
case MembershipUpdateMemberJoined:
g.members.Add(event.Member)
case protobuf.MembershipUpdateEvent_MEMBER_REMOVED:
g.admins.Remove(event.Members[0])
g.joined.Remove(event.Members[0])
g.members.Remove(event.Members[0])
case protobuf.MembershipUpdateEvent_MEMBER_JOINED:
g.joined.Add(event.From)
}
}
func (g *Group) sortEvents() {
sort.Slice(g.updates, func(i, j int) bool {
return g.updates[i].ClockValue < g.updates[j].ClockValue
sort.Slice(g.events, func(i, j int) bool {
return g.events[i].ClockValue < g.events[j].ClockValue
})
}

View file

@ -1,92 +1,63 @@
package protocol
import (
"encoding/hex"
"strings"
"testing"
"unicode"
"github.com/golang/protobuf/proto"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var (
testMembershipUpdateMessageBytes = []byte(`["~#g5",["072ea460-84d3-53c5-9979-1ca36fb5d1020x0424a68f89ba5fcd5e0640c1e1f591d561fa4125ca4e2a43592bc4123eca10ce064e522c254bb83079ba404327f6eafc01ec90a1444331fe769d3f3a7f90b0dde1",["~#list",[["^ ","~:chat-id","072ea460-84d3-53c5-9979-1ca36fb5d1020x0424a68f89ba5fcd5e0640c1e1f591d561fa4125ca4e2a43592bc4123eca10ce064e522c254bb83079ba404327f6eafc01ec90a1444331fe769d3f3a7f90b0dde1","~:events",[["^ ","~:type","chat-created","~:name","thathata","~:clock-value",156897373998501],["^ ","^4","members-added","^6",156897373998502,"~:members",["~#set",["0x04aebe2bb01a988abe7d978662f21de7760486119876c680e5a559e38e086a2df6dad41c4e4d9079c03db3bced6cb70fca76afc5650e50ea19b81572046a813534"]]]],"~:signature","7fca3d614cf55bc6cdf9c17fd1e65d1688673322bf1f004c58c78e0927edefea3d1053bf6a9d2e058ae88079f588105dccf2a2f9f330f6035cd47c715ee5950601"]]],null]]`)
testMembershipUpdateMessageStruct = MembershipUpdateMessage{
ChatID: "072ea460-84d3-53c5-9979-1ca36fb5d1020x0424a68f89ba5fcd5e0640c1e1f591d561fa4125ca4e2a43592bc4123eca10ce064e522c254bb83079ba404327f6eafc01ec90a1444331fe769d3f3a7f90b0dde1",
Updates: []MembershipUpdate{
ChatID: "chat-id",
Events: []MembershipUpdateEvent{
{
ChatID: "072ea460-84d3-53c5-9979-1ca36fb5d1020x0424a68f89ba5fcd5e0640c1e1f591d561fa4125ca4e2a43592bc4123eca10ce064e522c254bb83079ba404327f6eafc01ec90a1444331fe769d3f3a7f90b0dde1",
Signature: "7fca3d614cf55bc6cdf9c17fd1e65d1688673322bf1f004c58c78e0927edefea3d1053bf6a9d2e058ae88079f588105dccf2a2f9f330f6035cd47c715ee5950601",
Events: []MembershipUpdateEvent{
{
Type: MembershipUpdateChatCreated,
Name: "thathata",
ClockValue: 156897373998501,
},
{
Type: MembershipUpdateMembersAdded,
Members: []string{"0x04aebe2bb01a988abe7d978662f21de7760486119876c680e5a559e38e086a2df6dad41c4e4d9079c03db3bced6cb70fca76afc5650e50ea19b81572046a813534"},
ClockValue: 156897373998502,
},
},
Type: protobuf.MembershipUpdateEvent_CHAT_CREATED,
Name: "thathata",
ChatID: "chat-id",
ClockValue: 156897373998501,
},
{
Type: protobuf.MembershipUpdateEvent_MEMBERS_ADDED,
Members: []string{"0x04aebe2bb01a988abe7d978662f21de7760486119876c680e5a559e38e086a2df6dad41c4e4d9079c03db3bced6cb70fca76afc5650e50ea19b81572046a813534"},
ChatID: "chat-id",
ClockValue: 156897373998502,
},
},
}
)
func TestTupleMembershipUpdateEvent(t *testing.T) {
event1 := testMembershipUpdateMessageStruct.Updates[0].Events[0]
result1 := tupleMembershipUpdateEvent(event1)
require.EqualValues(t, [][]interface{}{
{"clock-value", event1.ClockValue},
{"name", "thathata"},
{"type", "chat-created"},
}, result1)
event2 := testMembershipUpdateMessageStruct.Updates[0].Events[1]
result2 := tupleMembershipUpdateEvent(event2)
require.EqualValues(t, [][]interface{}{
{"clock-value", event2.ClockValue},
{"members", event2.Members},
{"type", "members-added"},
}, result2)
}
func TestSignMembershipUpdate(t *testing.T) {
key, err := crypto.HexToECDSA("838fbdd1b670209a258b90af25653a018bc582c44c56e6290a973eebbeb15732")
require.NoError(t, err)
update := testMembershipUpdateMessageStruct.Updates[0]
err = update.Sign(key)
event := &testMembershipUpdateMessageStruct.Events[0]
err = event.Sign(key)
require.NoError(t, err)
expected, err := crypto.SignStringAsHex(
strings.Map(func(r rune) rune {
if unicode.IsSpace(r) {
return -1
}
return r
}, `
[
[
[
["clock-value", 156897373998501],
["name", "thathata"],
["type", "chat-created"]
],
[
["clock-value", 156897373998502],
["members", ["0x04aebe2bb01a988abe7d978662f21de7760486119876c680e5a559e38e086a2df6dad41c4e4d9079c03db3bced6cb70fca76afc5650e50ea19b81572046a813534"]],
["type", "members-added"]
]
],
"072ea460-84d3-53c5-9979-1ca36fb5d1020x0424a68f89ba5fcd5e0640c1e1f591d561fa4125ca4e2a43592bc4123eca10ce064e522c254bb83079ba404327f6eafc01ec90a1444331fe769d3f3a7f90b0dde1"
]
`),
key,
)
encodedEvent, err := proto.Marshal(event.ToProtobuf())
require.NoError(t, err)
require.Equal(t, expected, update.Signature)
var signatureMaterial []byte
signatureMaterial = append(signatureMaterial, []byte(testMembershipUpdateMessageStruct.ChatID)...)
signatureMaterial = crypto.Keccak256(append(signatureMaterial, encodedEvent...))
expected, err := crypto.Sign(signatureMaterial, key)
require.NoError(t, err)
require.Equal(t, encodedEvent, event.RawPayload)
require.Equal(t, expected, event.Signature)
// Sign the other event
err = testMembershipUpdateMessageStruct.Events[1].Sign(key)
require.NoError(t, err)
// Encode message
encodedMessage := testMembershipUpdateMessageStruct.ToProtobuf()
// Verify it
verifiedMessage, err := MembershipUpdateMessageFromProtobuf(encodedMessage)
require.NoError(t, err)
require.Equal(t, verifiedMessage, &testMembershipUpdateMessageStruct)
}
func TestGroupCreator(t *testing.T) {
@ -100,10 +71,11 @@ func TestGroupCreator(t *testing.T) {
}
func TestGroupProcessEvent(t *testing.T) {
createGroup := func(admins, members []string, name string) Group {
createGroup := func(admins, members, joined []string, name string) Group {
return Group{
name: name,
admins: newStringSetFromSlice(admins),
joined: newStringSetFromSlice(joined),
members: newStringSetFromSlice(members),
}
}
@ -117,59 +89,60 @@ func TestGroupProcessEvent(t *testing.T) {
}{
{
Name: "chat-created event",
Group: createGroup(nil, nil, ""),
Result: createGroup([]string{"0xabc"}, []string{"0xabc"}, "some-name"),
Group: createGroup(nil, nil, nil, ""),
Result: createGroup([]string{"0xabc"}, []string{"0xabc"}, []string{"0xabc"}, "some-name"),
From: "0xabc",
Event: NewChatCreatedEvent("some-name", "0xabc", 0),
Event: NewChatCreatedEvent("some-name", 0),
},
{
Name: "name-changed event",
Group: createGroup(nil, nil, ""),
Result: createGroup(nil, nil, "some-name"),
Group: createGroup(nil, nil, nil, ""),
Result: createGroup(nil, nil, nil, "some-name"),
From: "0xabc",
Event: NewNameChangedEvent("some-name", 0),
},
{
Name: "admins-added event",
Group: createGroup(nil, nil, ""),
Result: createGroup([]string{"0xabc", "0x123"}, nil, ""),
Group: createGroup(nil, nil, nil, ""),
Result: createGroup([]string{"0xabc", "0x123"}, nil, nil, ""),
From: "0xabc",
Event: NewAdminsAddedEvent([]string{"0xabc", "0x123"}, 0),
},
{
Name: "admin-removed event",
Group: createGroup([]string{"0xabc", "0xdef"}, nil, ""),
Result: createGroup([]string{"0xdef"}, nil, ""),
Group: createGroup([]string{"0xabc", "0xdef"}, nil, nil, ""),
Result: createGroup([]string{"0xdef"}, nil, nil, ""),
From: "0xabc",
Event: NewAdminRemovedEvent("0xabc", 0),
},
{
Name: "members-added event",
Group: createGroup(nil, nil, ""),
Result: createGroup(nil, []string{"0xabc", "0xdef"}, ""),
Group: createGroup(nil, nil, nil, ""),
Result: createGroup(nil, []string{"0xabc", "0xdef"}, nil, ""),
From: "0xabc",
Event: NewMembersAddedEvent([]string{"0xabc", "0xdef"}, 0),
},
{
Name: "member-removed event",
Group: createGroup(nil, []string{"0xabc", "0xdef"}, ""),
Result: createGroup(nil, []string{"0xdef"}, ""),
Group: createGroup(nil, []string{"0xabc", "0xdef"}, []string{"0xdef", "0xabc"}, ""),
Result: createGroup(nil, []string{"0xdef"}, []string{"0xdef"}, ""),
From: "0xabc",
Event: NewMemberRemovedEvent("0xabc", 0),
},
{
Name: "member-joined event",
Group: createGroup(nil, []string{"0xabc"}, ""),
Result: createGroup(nil, []string{"0xabc", "0xdef"}, ""),
From: "0xabc",
Event: NewMemberJoinedEvent("0xdef", 0),
Group: createGroup(nil, []string{"0xabc", "0xdef"}, []string{"0xabc"}, ""),
Result: createGroup(nil, []string{"0xabc", "0xdef"}, []string{"0xabc", "0xdef"}, ""),
From: "0xdef",
Event: NewMemberJoinedEvent(0),
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
g := tc.Group
g.processEvent(tc.From, tc.Event)
tc.Event.From = tc.From
g.processEvent(tc.Event)
require.EqualValues(t, tc.Result, g)
})
}
@ -193,19 +166,22 @@ func TestGroupValidateEvent(t *testing.T) {
{
Name: "chat-created with empty admins and members",
Group: createGroup(nil, nil),
Event: NewChatCreatedEvent("test", "0xabc", 0),
From: "0xabc",
Event: NewChatCreatedEvent("test", 0),
Result: true,
},
{
Name: "chat-created with existing admins",
Group: createGroup([]string{"0xabc"}, nil),
Event: NewChatCreatedEvent("test", "0xabc", 0),
From: "0xabc",
Event: NewChatCreatedEvent("test", 0),
Result: false,
},
{
Name: "chat-created with existing members",
Group: createGroup(nil, []string{"0xabc"}),
Event: NewChatCreatedEvent("test", "0xabc", 0),
From: "0xabc",
Event: NewChatCreatedEvent("test", 0),
Result: false,
},
{
@ -261,21 +237,21 @@ func TestGroupValidateEvent(t *testing.T) {
Name: "member-joined must be in members",
From: "0xabc",
Group: createGroup(nil, []string{"0xabc"}),
Event: NewMemberJoinedEvent("0xabc", 0),
Event: NewMemberJoinedEvent(0),
Result: true,
},
{
Name: "member-joined not valid because not in members",
From: "0xabc",
Group: createGroup(nil, nil),
Event: NewMemberJoinedEvent("0xabc", 0),
Event: NewMemberJoinedEvent(0),
Result: false,
},
{
Name: "member-joined not valid because from differs from the event",
From: "0xdef",
Group: createGroup(nil, nil),
Event: NewMemberJoinedEvent("0xabc", 0),
Event: NewMemberJoinedEvent(0),
Result: false,
},
{
@ -324,101 +300,25 @@ func TestGroupValidateEvent(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
result := tc.Group.validateEvent(tc.From, tc.Event)
tc.Event.From = tc.From
result := tc.Group.validateEvent(tc.Event)
assert.Equal(t, tc.Result, result)
})
}
}
func TestMembershipUpdateMessageProcess(t *testing.T) {
key, err := crypto.GenerateKey()
require.NoError(t, err)
updates := []MembershipUpdate{
{
ChatID: "some-chat",
Events: []MembershipUpdateEvent{
NewChatCreatedEvent("some-name", "0xabc", 0),
},
},
}
err = updates[0].Sign(key)
require.NoError(t, err)
require.NotEmpty(t, updates[0].Signature)
message := MembershipUpdateMessage{
ChatID: "some-chat",
Updates: updates,
}
err = message.Verify()
require.NoError(t, err)
require.EqualValues(t, "0x"+hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey)), updates[0].From)
}
func TestMembershipUpdateEventEqual(t *testing.T) {
u1 := MembershipUpdateEvent{
Type: MembershipUpdateChatCreated,
Type: protobuf.MembershipUpdateEvent_CHAT_CREATED,
ClockValue: 1,
Member: "0xabc",
Members: []string{"0xabc"},
Name: "abc",
Signature: []byte("signature"),
}
require.True(t, u1.Equal(u1))
// Verify equality breaking.
u2 := u1
u2.Members = append(u2.Members, "0xdef")
require.False(t, u1.Equal(u2))
u2 = u1
u2.Type = MembershipUpdateMembersAdded
require.False(t, u1.Equal(u2))
u2 = u1
u2.ClockValue = 2
require.False(t, u1.Equal(u2))
u2 = u1
u2.Member = "0xdef"
require.False(t, u1.Equal(u2))
u2 = u1
u2.Name = "def"
u2.Signature = []byte("different-signature")
require.False(t, u1.Equal(u2))
}
func TestMembershipUpdateFlatEqual(t *testing.T) {
u1 := MembershipUpdateFlat{
ChatID: "abc",
Signature: "abc",
From: "0xabc",
}
require.True(t, u1.Equal(u1))
// Verify equality breaking.
u2 := u1
u2.ChatID = "def"
require.False(t, u1.Equal(u2))
u2 = u1
u2.Signature = "def"
require.False(t, u1.Equal(u2))
u2 = u1
u2.From = "0xdef"
require.False(t, u1.Equal(u2))
}
func TestMergeFlatMembershipUpdates(t *testing.T) {
u1 := []MembershipUpdateFlat{
{
ChatID: "abc",
Signature: "abc",
From: "0xabc",
},
}
u2 := []MembershipUpdateFlat{
{
ChatID: "abc",
Signature: "def",
From: "0xdef",
},
}
result := MergeFlatMembershipUpdates(u1, u1)
require.EqualValues(t, u1, result)
result = MergeFlatMembershipUpdates(u1, u2)
require.EqualValues(t, append(u1, u2...), result)
}

View file

@ -17,34 +17,11 @@ var (
ErrInvalidDecodedValue = errors.New("invalid decoded value type")
)
// TimestampInMs is a timestamp in milliseconds.
type TimestampInMs int64
// Time returns a time.Time instance.
func (t TimestampInMs) Time() time.Time {
ts := int64(t)
seconds := ts / 1000
return time.Unix(seconds, (ts%1000)*int64(time.Millisecond))
}
// TimestampInMsFromTime returns a TimestampInMs from a time.Time instance.
func TimestampInMsFromTime(t time.Time) TimestampInMs {
return TimestampInMs(t.UnixNano() / int64(time.Millisecond))
func TimestampInMsFromTime(t time.Time) uint64 {
return uint64(t.UnixNano() / int64(time.Millisecond))
}
// Flags define various boolean properties of a message.
type Flags uint64
func (f *Flags) Set(val Flags) { *f = *f | val }
func (f *Flags) Clear(val Flags) { *f = *f &^ val }
func (f *Flags) Toggle(val Flags) { *f = *f ^ val }
func (f Flags) Has(val Flags) bool { return f&val != 0 }
// A list of Message flags. By default, a message is unread.
const (
MessageRead Flags = 1 << iota
)
// MessageID calculates the messageID from author's compressed public key
// and not encrypted but encoded payload.
func MessageID(author *ecdsa.PublicKey, data []byte) types.HexBytes {
@ -53,7 +30,7 @@ func MessageID(author *ecdsa.PublicKey, data []byte) types.HexBytes {
}
// WrapMessageV1 wraps a payload into a protobuf message and signs it if an identity is provided
func WrapMessageV1(payload []byte, identity *ecdsa.PrivateKey) ([]byte, error) {
func WrapMessageV1(payload []byte, messageType protobuf.ApplicationMetadataMessage_Type, identity *ecdsa.PrivateKey) ([]byte, error) {
var signature []byte
if identity != nil {
var err error
@ -65,6 +42,7 @@ func WrapMessageV1(payload []byte, identity *ecdsa.PrivateKey) ([]byte, error) {
message := &protobuf.ApplicationMetadataMessage{
Signature: signature,
Type: messageType,
Payload: payload,
}
return proto.Marshal(message)

View file

@ -2,7 +2,6 @@ package protocol
import (
"testing"
"time"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
@ -19,10 +18,3 @@ func TestMessageID(t *testing.T) {
expectedID := types.HexBytes(crypto.Keccak256(append(keyBytes, data...)))
require.Equal(t, expectedID, MessageID(&key.PublicKey, data))
}
func TestTimestampInMs(t *testing.T) {
ts := TimestampInMs(1555274502548) // random timestamp in milliseconds
tt := ts.Time()
require.Equal(t, tt.UnixNano(), 1555274502548*int64(time.Millisecond))
require.Equal(t, ts, TimestampInMsFromTime(tt))
}

View file

@ -17,18 +17,12 @@ import (
type StatusMessageT int
const (
MessageT StatusMessageT = iota + 1
MembershipUpdateMessageT
PairMessageT
)
// StatusMessage is any Status Protocol message.
type StatusMessage struct {
// TransportMessage is the parsed message received from the transport layer, i.e the input
TransportMessage *types.Message `json:"transportMessage"`
// MessageType is the type of application message contained
MessageType StatusMessageT `json:"-"`
// Type is the type of application message contained
Type protobuf.ApplicationMetadataMessage_Type `json:"-"`
// ParsedMessage is the parsed message by the application layer, i.e the output
ParsedMessage interface{} `json:"-"`
@ -157,23 +151,37 @@ func (m *StatusMessage) HandleApplicationMetadata() error {
// Calculate ID using the wrapped record
m.ID = MessageID(recoveredKey, m.DecryptedPayload)
m.DecryptedPayload = message.Payload
m.Type = message.Type
return nil
}
func (m *StatusMessage) HandleApplication() error {
// Try protobuf first
var message protobuf.ChatMessage
switch m.Type {
case protobuf.ApplicationMetadataMessage_CHAT_MESSAGE:
var message protobuf.ChatMessage
err := proto.Unmarshal(m.DecryptedPayload, &message)
if err != nil {
m.ParsedMessage = nil
log.Printf("[message::DecodeMessage] could not decode protobuf message: %#x, err: %v", m.Hash, err.Error())
} else {
m.MessageType = MessageT
m.ParsedMessage = message
err := proto.Unmarshal(m.DecryptedPayload, &message)
if err != nil {
m.ParsedMessage = nil
log.Printf("[message::DecodeMessage] could not decode ChatMessage: %#x, err: %v", m.Hash, err.Error())
} else {
m.ParsedMessage = message
return nil
return nil
}
case protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE:
var message protobuf.MembershipUpdateMessage
err := proto.Unmarshal(m.DecryptedPayload, &message)
if err != nil {
m.ParsedMessage = nil
log.Printf("[message::DecodeMessage] could not decode MembershipUpdateMessage: %#x, err: %v", m.Hash, err.Error())
} else {
m.ParsedMessage = message
return nil
}
}
return nil
}

View file

@ -21,7 +21,6 @@ import (
"github.com/status-im/status-go/whisper/v6"
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
enstypes "github.com/status-im/status-go/eth-node/types/ens"
"github.com/status-im/status-go/protocol"
@ -448,17 +447,46 @@ func (api *PublicAPI) SendPublicMessage(ctx context.Context, msg SendPublicMessa
// It's important to call PublicAPI.afterSend() so that the client receives a signal
// with confirmation that the message left the device.
func (api *PublicAPI) SendDirectMessage(ctx context.Context, msg SendDirectMessageRPC) (types.HexBytes, error) {
publicKey, err := crypto.UnmarshalPubkey(msg.PubKey)
if err != nil {
return nil, err
}
chat := protocol.Chat{
PublicKey: publicKey,
ChatType: protocol.ChatTypeOneToOne,
ID: types.EncodeHex(msg.PubKey),
}
return api.service.messenger.SendRaw(ctx, chat, msg.Payload)
}
func (api *PublicAPI) Join(chat protocol.Chat) error {
return api.service.messenger.Join(chat)
}
func (api *PublicAPI) Leave(chat protocol.Chat) error {
return api.service.messenger.Leave(chat)
}
func (api *PublicAPI) LeaveGroupChat(ctx Context, chatID string) (*protocol.MessengerResponse, error) {
return api.service.messenger.LeaveGroupChat(ctx, chatID)
}
func (api *PublicAPI) CreateGroupChatWithMembers(ctx Context, name string, members []string) (*protocol.MessengerResponse, error) {
return api.service.messenger.CreateGroupChatWithMembers(ctx, name, members)
}
func (api *PublicAPI) AddMembersToGroupChat(ctx Context, chatID string, members []string) (*protocol.MessengerResponse, error) {
return api.service.messenger.AddMembersToGroupChat(ctx, chatID, members)
}
func (api *PublicAPI) RemoveMemberFromGroupChat(ctx Context, chatID string, member string) (*protocol.MessengerResponse, error) {
return api.service.messenger.RemoveMemberFromGroupChat(ctx, chatID, member)
}
func (api *PublicAPI) AddAdminsToGroupChat(ctx Context, chatID string, members []string) (*protocol.MessengerResponse, error) {
return api.service.messenger.AddAdminsToGroupChat(ctx, chatID, members)
}
func (api *PublicAPI) ConfirmJoiningGroup(ctx context.Context, chatID string) (*protocol.MessengerResponse, error) {
return api.service.messenger.ConfirmJoiningGroup(ctx, chatID)
}
func (api *PublicAPI) requestMessagesUsingPayload(request db.HistoryRequest, peer, symkeyID string, payload []byte, force bool, timeout time.Duration, topics []types.TopicType) (hash types.Hash, err error) {
shh := api.service.w
now := api.service.w.GetCurrentTime()
@ -571,12 +599,12 @@ func (api *PublicAPI) LoadFilters(parent context.Context, chats []*statustransp.
return api.service.messenger.LoadFilters(chats)
}
func (api *PublicAPI) SaveChat(parent context.Context, chat protocol.Chat) error {
func (api *PublicAPI) SaveChat(parent context.Context, chat *protocol.Chat) error {
api.log.Info("saving chat", "chat", chat)
return api.service.messenger.SaveChat(chat)
}
func (api *PublicAPI) Chats(parent context.Context) ([]*protocol.Chat, error) {
func (api *PublicAPI) Chats(parent context.Context) []*protocol.Chat {
return api.service.messenger.Chats()
}
@ -584,16 +612,16 @@ func (api *PublicAPI) DeleteChat(parent context.Context, chatID string) error {
return api.service.messenger.DeleteChat(chatID)
}
func (api *PublicAPI) SaveContact(parent context.Context, contact protocol.Contact) error {
func (api *PublicAPI) SaveContact(parent context.Context, contact *protocol.Contact) error {
return api.service.messenger.SaveContact(contact)
}
func (api *PublicAPI) BlockContact(parent context.Context, contact protocol.Contact) ([]*protocol.Chat, error) {
func (api *PublicAPI) BlockContact(parent context.Context, contact *protocol.Contact) ([]*protocol.Chat, error) {
api.log.Info("blocking contact", "contact", contact.ID)
return api.service.messenger.BlockContact(contact)
}
func (api *PublicAPI) Contacts(parent context.Context) ([]*protocol.Contact, error) {
func (api *PublicAPI) Contacts(parent context.Context) []*protocol.Contact {
return api.service.messenger.Contacts()
}
@ -643,10 +671,6 @@ func (api *PublicAPI) ChatMessages(chatID, cursor string, limit int) (*Applicati
}, nil
}
func (api *PublicAPI) AddSystemMessages(messages []*protocol.Message) ([]*protocol.Message, error) {
return api.service.messenger.AddSystemMessages(messages)
}
func (api *PublicAPI) DeleteMessage(id string) error {
return api.service.messenger.DeleteMessage(id)
}

View file

@ -151,7 +151,7 @@ func (s *Service) InitProtocol(db *sql.DB) error { // nolint: gocyclo
s.cancelMessenger = make(chan struct{})
go s.retrieveMessagesLoop(time.Second, s.cancelMessenger)
return nil
return s.messenger.Init()
}
func (s *Service) retrieveMessagesLoop(tick time.Duration, cancel <-chan struct{}) {

View file

@ -12,17 +12,6 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Deprecated
## [0.10.5]
### Fixed
- Fixed uptime calculation under Windows. #126
- Fixed compilation issue for darwin/386. #128
### Changed
- Load DLLs only from Windows system directory. #132
## [0.10.4]
### Fixed

View file

@ -37,7 +37,6 @@ The features vary by operating system.
| ProcMem | X | X | X | | X |
| ProcState | X | X | X | | X |
| ProcTime | X | X | X | | X |
| Rusage | X | | X | | |
| Swap | X | X | | X | X |
| Uptime | X | X | | X | X |

View file

@ -40,6 +40,18 @@ func (self *LoadAverage) Get() error {
return nil
}
func (self *Uptime) Get() error {
tv := syscall.Timeval32{}
if err := sysctlbyname("kern.boottime", &tv); err != nil {
return err
}
self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds()
return nil
}
func (self *Mem) Get() error {
var vmstat C.vm_statistics_data_t

View file

@ -1,18 +0,0 @@
package gosigar
import (
"syscall"
"time"
)
func (self *Uptime) Get() error {
tv := syscall.Timeval{}
if err := sysctlbyname("kern.boottime", &tv); err != nil {
return err
}
self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds()
return nil
}

View file

@ -1,18 +0,0 @@
package gosigar
import (
"syscall"
"time"
)
func (self *Uptime) Get() error {
tv := syscall.Timeval32{}
if err := sysctlbyname("kern.boottime", &tv); err != nil {
return err
}
self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds()
return nil
}

View file

@ -4,7 +4,6 @@ import (
"time"
)
// ErrNotImplemented is returned when a particular statistic isn't implemented on the host OS.
type ErrNotImplemented struct {
OS string
}
@ -13,7 +12,6 @@ func (e ErrNotImplemented) Error() string {
return "not implemented on " + e.OS
}
// IsNotImplemented returns true if the error is ErrNotImplemented
func IsNotImplemented(err error) bool {
switch err.(type) {
case ErrNotImplemented, *ErrNotImplemented:
@ -23,7 +21,6 @@ func IsNotImplemented(err error) bool {
}
}
// Sigar is an interface for gathering system host stats
type Sigar interface {
CollectCpuStats(collectionInterval time.Duration) (<-chan Cpu, chan<- struct{})
GetLoadAverage() (LoadAverage, error)
@ -35,7 +32,6 @@ type Sigar interface {
GetRusage(who int) (Rusage, error)
}
// Cpu contains CPU time stats
type Cpu struct {
User uint64
Nice uint64
@ -47,13 +43,11 @@ type Cpu struct {
Stolen uint64
}
// Total returns total CPU time
func (cpu *Cpu) Total() uint64 {
return cpu.User + cpu.Nice + cpu.Sys + cpu.Idle +
cpu.Wait + cpu.Irq + cpu.SoftIrq + cpu.Stolen
}
// Delta returns the difference between two Cpu stat objects
func (cpu Cpu) Delta(other Cpu) Cpu {
return Cpu{
User: cpu.User - other.User,
@ -67,17 +61,14 @@ func (cpu Cpu) Delta(other Cpu) Cpu {
}
}
// LoadAverage reports standard load averages
type LoadAverage struct {
One, Five, Fifteen float64
}
// Uptime reports system uptime
type Uptime struct {
Length float64
}
// Mem contains host memory stats
type Mem struct {
Total uint64
Used uint64
@ -86,14 +77,12 @@ type Mem struct {
ActualUsed uint64
}
// Swap contains stats on swap space
type Swap struct {
Total uint64
Used uint64
Free uint64
}
// HugeTLBPages contains HugePages stats
type HugeTLBPages struct {
Total uint64
Free uint64
@ -103,19 +92,16 @@ type HugeTLBPages struct {
TotalAllocatedSize uint64
}
// CpuList contains a list of CPUs on the host system
type CpuList struct {
List []Cpu
}
// FDUsage contains stats on filesystem usage
type FDUsage struct {
Open uint64
Unused uint64
Max uint64
}
// FileSystem contains basic information about a given mounted filesystem
type FileSystem struct {
DirName string
DevName string
@ -125,12 +111,10 @@ type FileSystem struct {
Flags uint32
}
// FileSystemList gets a list of mounted filesystems
type FileSystemList struct {
List []FileSystem
}
// FileSystemUsage contains basic stats for the specified filesystem
type FileSystemUsage struct {
Total uint64
Used uint64
@ -140,30 +124,21 @@ type FileSystemUsage struct {
FreeFiles uint64
}
// ProcList contains a list of processes found on the host system
type ProcList struct {
List []int
}
// RunState is a byte-long code used to specify the current runtime state of a process
type RunState byte
const (
// RunStateSleep corresponds to a sleep state
RunStateSleep = 'S'
// RunStateRun corresponds to a running state
RunStateRun = 'R'
// RunStateStop corresponds to a stopped state
RunStateStop = 'T'
// RunStateZombie marks a zombie process
RunStateZombie = 'Z'
// RunStateIdle corresponds to an idle state
RunStateIdle = 'D'
// RunStateUnknown corresponds to a process in an unknown state
RunStateSleep = 'S'
RunStateRun = 'R'
RunStateStop = 'T'
RunStateZombie = 'Z'
RunStateIdle = 'D'
RunStateUnknown = '?'
)
// ProcState contains basic metadata and process ownership info for the specified process
type ProcState struct {
Name string
Username string
@ -176,7 +151,6 @@ type ProcState struct {
Processor int
}
// ProcMem contains memory statistics for a specified process
type ProcMem struct {
Size uint64
Resident uint64
@ -186,7 +160,6 @@ type ProcMem struct {
PageFaults uint64
}
// ProcTime contains run time statistics for a specified process
type ProcTime struct {
StartTime uint64
User uint64
@ -194,31 +167,26 @@ type ProcTime struct {
Total uint64
}
// ProcArgs contains a list of args for a specified process
type ProcArgs struct {
List []string
}
// ProcEnv contains a map of environment variables for specified process
type ProcEnv struct {
Vars map[string]string
}
// ProcExe contains basic data about a specified process
type ProcExe struct {
Name string
Cwd string
Root string
}
// ProcFDUsage contains data on file limits and usage
type ProcFDUsage struct {
Open uint64
SoftLimit uint64
HardLimit uint64
}
// Rusage contains data on resource usage for a specified process
type Rusage struct {
Utime time.Duration
Stime time.Duration

View file

@ -8,6 +8,7 @@ import (
"path/filepath"
"runtime"
"strings"
"sync"
"syscall"
"time"
@ -23,6 +24,11 @@ var (
// 2003 and XP where PROCESS_QUERY_LIMITED_INFORMATION is unknown. For all newer
// OS versions it is set to PROCESS_QUERY_LIMITED_INFORMATION.
processQueryLimitedInfoAccess = windows.PROCESS_QUERY_LIMITED_INFORMATION
// bootTime is the time when the OS was last booted. This value may be nil
// on operating systems that do not support the WMI query used to obtain it.
bootTime *time.Time
bootTimeLock sync.Mutex
)
func init() {
@ -57,11 +63,19 @@ func (self *Uptime) Get() error {
if !version.IsWindowsVistaOrGreater() {
return ErrNotImplemented{runtime.GOOS}
}
uptimeMs, err := windows.GetTickCount64()
if err != nil {
return errors.Wrap(err, "failed to get boot time using GetTickCount64 api")
bootTimeLock.Lock()
defer bootTimeLock.Unlock()
if bootTime == nil {
uptime, err := windows.GetTickCount64()
if err != nil {
return errors.Wrap(err, "failed to get boot time using win32 api")
}
var boot = time.Unix(int64(uptime), 0)
bootTime = &boot
}
self.Length = float64(time.Duration(uptimeMs)*time.Millisecond) / float64(time.Second)
self.Length = time.Since(*bootTime).Seconds()
return nil
}

View file

@ -1,8 +1,2 @@
// Package windows contains various Windows system call.
package windows
// Use "go generate -v -x ." to generate the source.
// Add -trace to enable debug prints around syscalls.
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=true -output zsyscall_windows.go syscall_windows.go
//go:generate go run fix_generated.go -input zsyscall_windows.go

View file

@ -580,6 +580,11 @@ func GetTickCount64() (uptime uint64, err error) {
return uptime, nil
}
// Use "GOOS=windows go generate -v -x ." to generate the source.
// Add -trace to enable debug prints around syscalls.
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output zsyscall_windows.go syscall_windows.go
// Windows API calls
//sys _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) = kernel32.GlobalMemoryStatusEx
//sys _GetLogicalDriveStringsW(bufferLength uint32, buffer *uint16) (length uint32, err error) = kernel32.GetLogicalDriveStringsW

View file

@ -5,8 +5,6 @@ package windows
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
@ -37,10 +35,10 @@ func errnoErr(e syscall.Errno) error {
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modpsapi = windows.NewLazySystemDLL("psapi.dll")
modntdll = windows.NewLazySystemDLL("ntdll.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
modpsapi = syscall.NewLazyDLL("psapi.dll")
modntdll = syscall.NewLazyDLL("ntdll.dll")
modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW")

View file

@ -36,66 +36,66 @@ type ErrorCode uint32
const (
SCardSuccess ErrorCode = 0x00000000 /* No error was encountered. */
ErrSCardInternal ErrorCode = 0x80100001 /* An internal consistency check failed. */
ErrSCardCancelled ErrorCode = 0x80100002 /* The action was cancelled by an SCardCancel request. */
ErrSCardInvalidHandle ErrorCode = 0x80100003 /* The supplied handle was invalid. */
ErrSCardInvalidParameter ErrorCode = 0x80100004 /* One or more of the supplied parameters could not be properly interpreted. */
ErrSCardInvalidTarget ErrorCode = 0x80100005 /* Registry startup information is missing or invalid. */
ErrSCardNoMemory ErrorCode = 0x80100006 /* Not enough memory available to complete this command. */
ErrSCardWaitedTooLong ErrorCode = 0x80100007 /* An internal consistency timer has expired. */
ErrSCardInsufficientBuffer ErrorCode = 0x80100008 /* The data buffer to receive returned data is too small for the returned data. */
ErrScardUnknownReader ErrorCode = 0x80100009 /* The specified reader name is not recognized. */
ErrSCardTimeout ErrorCode = 0x8010000A /* The user-specified timeout value has expired. */
ErrSCardSharingViolation ErrorCode = 0x8010000B /* The smart card cannot be accessed because of other connections outstanding. */
ErrSCardNoSmartCard ErrorCode = 0x8010000C /* The operation requires a Smart Card, but no Smart Card is currently in the device. */
ErrSCardUnknownCard ErrorCode = 0x8010000D /* The specified smart card name is not recognized. */
ErrSCardCannotDispose ErrorCode = 0x8010000E /* The system could not dispose of the media in the requested manner. */
ErrSCardProtoMismatch ErrorCode = 0x8010000F /* The requested protocols are incompatible with the protocol currently in use with the smart card. */
ErrSCardNotReady ErrorCode = 0x80100010 /* The reader or smart card is not ready to accept commands. */
ErrSCardInvalidValue ErrorCode = 0x80100011 /* One or more of the supplied parameters values could not be properly interpreted. */
ErrSCardSystemCancelled ErrorCode = 0x80100012 /* The action was cancelled by the system, presumably to log off or shut down. */
ErrSCardCommError ErrorCode = 0x80100013 /* An internal communications error has been detected. */
ErrScardUnknownError ErrorCode = 0x80100014 /* An internal error has been detected, but the source is unknown. */
ErrSCardInvalidATR ErrorCode = 0x80100015 /* An ATR obtained from the registry is not a valid ATR string. */
ErrSCardNotTransacted ErrorCode = 0x80100016 /* An attempt was made to end a non-existent transaction. */
ErrSCardReaderUnavailable ErrorCode = 0x80100017 /* The specified reader is not currently available for use. */
ErrSCardShutdown ErrorCode = 0x80100018 /* The operation has been aborted to allow the server application to exit. */
ErrSCardPCITooSmall ErrorCode = 0x80100019 /* The PCI Receive buffer was too small. */
ErrSCardReaderUnsupported ErrorCode = 0x8010001A /* The reader driver does not meet minimal requirements for support. */
ErrSCardDuplicateReader ErrorCode = 0x8010001B /* The reader driver did not produce a unique reader name. */
ErrSCardCardUnsupported ErrorCode = 0x8010001C /* The smart card does not meet minimal requirements for support. */
ErrScardNoService ErrorCode = 0x8010001D /* The Smart card resource manager is not running. */
ErrSCardServiceStopped ErrorCode = 0x8010001E /* The Smart card resource manager has shut down. */
ErrSCardUnexpected ErrorCode = 0x8010001F /* An unexpected card error has occurred. */
ErrSCardUnsupportedFeature ErrorCode = 0x8010001F /* This smart card does not support the requested feature. */
ErrSCardICCInstallation ErrorCode = 0x80100020 /* No primary provider can be found for the smart card. */
ErrSCardICCCreateOrder ErrorCode = 0x80100021 /* The requested order of object creation is not supported. */
ErrSCardDirNotFound ErrorCode = 0x80100023 /* The identified directory does not exist in the smart card. */
ErrSCardFileNotFound ErrorCode = 0x80100024 /* The identified file does not exist in the smart card. */
ErrSCardNoDir ErrorCode = 0x80100025 /* The supplied path does not represent a smart card directory. */
ErrSCardNoFile ErrorCode = 0x80100026 /* The supplied path does not represent a smart card file. */
ErrScardNoAccess ErrorCode = 0x80100027 /* Access is denied to this file. */
ErrSCardWriteTooMany ErrorCode = 0x80100028 /* The smart card does not have enough memory to store the information. */
ErrSCardBadSeek ErrorCode = 0x80100029 /* There was an error trying to set the smart card file object pointer. */
ErrSCardInvalidCHV ErrorCode = 0x8010002A /* The supplied PIN is incorrect. */
ErrSCardUnknownResMNG ErrorCode = 0x8010002B /* An unrecognized error code was returned from a layered component. */
ErrSCardNoSuchCertificate ErrorCode = 0x8010002C /* The requested certificate does not exist. */
ErrSCardCertificateUnavailable ErrorCode = 0x8010002D /* The requested certificate could not be obtained. */
ErrSCardNoReadersAvailable ErrorCode = 0x8010002E /* Cannot find a smart card reader. */
ErrSCardCommDataLost ErrorCode = 0x8010002F /* A communications error with the smart card has been detected. Retry the operation. */
ErrScardNoKeyContainer ErrorCode = 0x80100030 /* The requested key container does not exist on the smart card. */
ErrSCardServerTooBusy ErrorCode = 0x80100031 /* The Smart Card Resource Manager is too busy to complete this operation. */
ErrSCardUnsupportedCard ErrorCode = 0x80100065 /* The reader cannot communicate with the card, due to ATR string configuration conflicts. */
ErrSCardUnresponsiveCard ErrorCode = 0x80100066 /* The smart card is not responding to a reset. */
ErrSCardUnpoweredCard ErrorCode = 0x80100067 /* Power has been removed from the smart card, so that further communication is not possible. */
ErrSCardResetCard ErrorCode = 0x80100068 /* The smart card has been reset, so any shared state information is invalid. */
ErrSCardRemovedCard ErrorCode = 0x80100069 /* The smart card has been removed, so further communication is not possible. */
ErrSCardSecurityViolation ErrorCode = 0x8010006A /* Access was denied because of a security violation. */
ErrSCardWrongCHV ErrorCode = 0x8010006B /* The card cannot be accessed because the wrong PIN was presented. */
ErrSCardCHVBlocked ErrorCode = 0x8010006C /* The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */
ErrSCardEOF ErrorCode = 0x8010006D /* The end of the smart card file has been reached. */
ErrSCardCancelledByUser ErrorCode = 0x8010006E /* The user pressed "Cancel" on a Smart Card Selection Dialog. */
ErrSCardCardNotAuthenticated ErrorCode = 0x8010006F /* No PIN was presented to the smart card. */
ErrSCardInternal = 0x80100001 /* An internal consistency check failed. */
ErrSCardCancelled = 0x80100002 /* The action was cancelled by an SCardCancel request. */
ErrSCardInvalidHandle = 0x80100003 /* The supplied handle was invalid. */
ErrSCardInvalidParameter = 0x80100004 /* One or more of the supplied parameters could not be properly interpreted. */
ErrSCardInvalidTarget = 0x80100005 /* Registry startup information is missing or invalid. */
ErrSCardNoMemory = 0x80100006 /* Not enough memory available to complete this command. */
ErrSCardWaitedTooLong = 0x80100007 /* An internal consistency timer has expired. */
ErrSCardInsufficientBuffer = 0x80100008 /* The data buffer to receive returned data is too small for the returned data. */
ErrScardUnknownReader = 0x80100009 /* The specified reader name is not recognized. */
ErrSCardTimeout = 0x8010000A /* The user-specified timeout value has expired. */
ErrSCardSharingViolation = 0x8010000B /* The smart card cannot be accessed because of other connections outstanding. */
ErrSCardNoSmartCard = 0x8010000C /* The operation requires a Smart Card, but no Smart Card is currently in the device. */
ErrSCardUnknownCard = 0x8010000D /* The specified smart card name is not recognized. */
ErrSCardCannotDispose = 0x8010000E /* The system could not dispose of the media in the requested manner. */
ErrSCardProtoMismatch = 0x8010000F /* The requested protocols are incompatible with the protocol currently in use with the smart card. */
ErrSCardNotReady = 0x80100010 /* The reader or smart card is not ready to accept commands. */
ErrSCardInvalidValue = 0x80100011 /* One or more of the supplied parameters values could not be properly interpreted. */
ErrSCardSystemCancelled = 0x80100012 /* The action was cancelled by the system, presumably to log off or shut down. */
ErrSCardCommError = 0x80100013 /* An internal communications error has been detected. */
ErrScardUnknownError = 0x80100014 /* An internal error has been detected, but the source is unknown. */
ErrSCardInvalidATR = 0x80100015 /* An ATR obtained from the registry is not a valid ATR string. */
ErrSCardNotTransacted = 0x80100016 /* An attempt was made to end a non-existent transaction. */
ErrSCardReaderUnavailable = 0x80100017 /* The specified reader is not currently available for use. */
ErrSCardShutdown = 0x80100018 /* The operation has been aborted to allow the server application to exit. */
ErrSCardPCITooSmall = 0x80100019 /* The PCI Receive buffer was too small. */
ErrSCardReaderUnsupported = 0x8010001A /* The reader driver does not meet minimal requirements for support. */
ErrSCardDuplicateReader = 0x8010001B /* The reader driver did not produce a unique reader name. */
ErrSCardCardUnsupported = 0x8010001C /* The smart card does not meet minimal requirements for support. */
ErrScardNoService = 0x8010001D /* The Smart card resource manager is not running. */
ErrSCardServiceStopped = 0x8010001E /* The Smart card resource manager has shut down. */
ErrSCardUnexpected = 0x8010001F /* An unexpected card error has occurred. */
ErrSCardUnsupportedFeature = 0x8010001F /* This smart card does not support the requested feature. */
ErrSCardICCInstallation = 0x80100020 /* No primary provider can be found for the smart card. */
ErrSCardICCCreateOrder = 0x80100021 /* The requested order of object creation is not supported. */
ErrSCardDirNotFound = 0x80100023 /* The identified directory does not exist in the smart card. */
ErrSCardFileNotFound = 0x80100024 /* The identified file does not exist in the smart card. */
ErrSCardNoDir = 0x80100025 /* The supplied path does not represent a smart card directory. */
ErrSCardNoFile = 0x80100026 /* The supplied path does not represent a smart card file. */
ErrScardNoAccess = 0x80100027 /* Access is denied to this file. */
ErrSCardWriteTooMany = 0x80100028 /* The smart card does not have enough memory to store the information. */
ErrSCardBadSeek = 0x80100029 /* There was an error trying to set the smart card file object pointer. */
ErrSCardInvalidCHV = 0x8010002A /* The supplied PIN is incorrect. */
ErrSCardUnknownResMNG = 0x8010002B /* An unrecognized error code was returned from a layered component. */
ErrSCardNoSuchCertificate = 0x8010002C /* The requested certificate does not exist. */
ErrSCardCertificateUnavailable = 0x8010002D /* The requested certificate could not be obtained. */
ErrSCardNoReadersAvailable = 0x8010002E /* Cannot find a smart card reader. */
ErrSCardCommDataLost = 0x8010002F /* A communications error with the smart card has been detected. Retry the operation. */
ErrScardNoKeyContainer = 0x80100030 /* The requested key container does not exist on the smart card. */
ErrSCardServerTooBusy = 0x80100031 /* The Smart Card Resource Manager is too busy to complete this operation. */
ErrSCardUnsupportedCard = 0x80100065 /* The reader cannot communicate with the card, due to ATR string configuration conflicts. */
ErrSCardUnresponsiveCard = 0x80100066 /* The smart card is not responding to a reset. */
ErrSCardUnpoweredCard = 0x80100067 /* Power has been removed from the smart card, so that further communication is not possible. */
ErrSCardResetCard = 0x80100068 /* The smart card has been reset, so any shared state information is invalid. */
ErrSCardRemovedCard = 0x80100069 /* The smart card has been removed, so further communication is not possible. */
ErrSCardSecurityViolation = 0x8010006A /* Access was denied because of a security violation. */
ErrSCardWrongCHV = 0x8010006B /* The card cannot be accessed because the wrong PIN was presented. */
ErrSCardCHVBlocked = 0x8010006C /* The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */
ErrSCardEOF = 0x8010006D /* The end of the smart card file has been reached. */
ErrSCardCancelledByUser = 0x8010006E /* The user pressed "Cancel" on a Smart Card Selection Dialog. */
ErrSCardCardNotAuthenticated = 0x8010006F /* No PIN was presented to the smart card. */
)
// Code returns the error code, with an uint32 type to be used in PutUInt32
@ -106,95 +106,95 @@ func (code ErrorCode) Code() uint32 {
func (code ErrorCode) Error() error {
switch code {
case SCardSuccess:
return fmt.Errorf("command successful")
return fmt.Errorf("Command successful")
case ErrSCardInternal:
return fmt.Errorf("internal error")
return fmt.Errorf("Internal error")
case ErrSCardCancelled:
return fmt.Errorf("command cancelled")
return fmt.Errorf("Command cancelled")
case ErrSCardInvalidHandle:
return fmt.Errorf("invalid handle")
return fmt.Errorf("Invalid handle")
case ErrSCardInvalidParameter:
return fmt.Errorf("invalid parameter given")
return fmt.Errorf("Invalid parameter given")
case ErrSCardInvalidTarget:
return fmt.Errorf("invalid target given")
return fmt.Errorf("Invalid target given")
case ErrSCardNoMemory:
return fmt.Errorf("not enough memory")
return fmt.Errorf("Not enough memory")
case ErrSCardWaitedTooLong:
return fmt.Errorf("waited too long")
return fmt.Errorf("Waited too long")
case ErrSCardInsufficientBuffer:
return fmt.Errorf("insufficient buffer")
return fmt.Errorf("Insufficient buffer")
case ErrScardUnknownReader:
return fmt.Errorf("unknown reader specified")
return fmt.Errorf("Unknown reader specified")
case ErrSCardTimeout:
return fmt.Errorf("command timeout")
return fmt.Errorf("Command timeout")
case ErrSCardSharingViolation:
return fmt.Errorf("sharing violation")
return fmt.Errorf("Sharing violation")
case ErrSCardNoSmartCard:
return fmt.Errorf("no smart card inserted")
return fmt.Errorf("No smart card inserted")
case ErrSCardUnknownCard:
return fmt.Errorf("unknown card")
return fmt.Errorf("Unknown card")
case ErrSCardCannotDispose:
return fmt.Errorf("cannot dispose handle")
return fmt.Errorf("Cannot dispose handle")
case ErrSCardProtoMismatch:
return fmt.Errorf("card protocol mismatch")
return fmt.Errorf("Card protocol mismatch")
case ErrSCardNotReady:
return fmt.Errorf("subsystem not ready")
return fmt.Errorf("Subsystem not ready")
case ErrSCardInvalidValue:
return fmt.Errorf("invalid value given")
return fmt.Errorf("Invalid value given")
case ErrSCardSystemCancelled:
return fmt.Errorf("system cancelled")
return fmt.Errorf("System cancelled")
case ErrSCardCommError:
return fmt.Errorf("rpc transport error")
return fmt.Errorf("RPC transport error")
case ErrScardUnknownError:
return fmt.Errorf("unknown error")
return fmt.Errorf("Unknown error")
case ErrSCardInvalidATR:
return fmt.Errorf("invalid ATR")
return fmt.Errorf("Invalid ATR")
case ErrSCardNotTransacted:
return fmt.Errorf("transaction failed")
return fmt.Errorf("Transaction failed")
case ErrSCardReaderUnavailable:
return fmt.Errorf("reader is unavailable")
return fmt.Errorf("Reader is unavailable")
/* case SCARD_P_SHUTDOWN: */
case ErrSCardPCITooSmall:
return fmt.Errorf("PCI struct too small")
case ErrSCardReaderUnsupported:
return fmt.Errorf("reader is unsupported")
return fmt.Errorf("Reader is unsupported")
case ErrSCardDuplicateReader:
return fmt.Errorf("reader already exists")
return fmt.Errorf("Reader already exists")
case ErrSCardCardUnsupported:
return fmt.Errorf("card is unsupported")
return fmt.Errorf("Card is unsupported")
case ErrScardNoService:
return fmt.Errorf("service not available")
return fmt.Errorf("Service not available")
case ErrSCardServiceStopped:
return fmt.Errorf("service was stopped")
return fmt.Errorf("Service was stopped")
/* case SCARD_E_UNEXPECTED: */
/* case SCARD_E_ICC_CREATEORDER: */
@ -210,7 +210,7 @@ func (code ErrorCode) Error() error {
/* case SCARD_E_NO_SUCH_CERTIFICATE: */
/* case SCARD_E_CERTIFICATE_UNAVAILABLE: */
case ErrSCardNoReadersAvailable:
return fmt.Errorf("cannot find a smart card reader")
return fmt.Errorf("Cannot find a smart card reader")
/* case SCARD_E_COMM_DATA_LOST: */
/* case SCARD_E_NO_KEY_CONTAINER: */
@ -238,7 +238,7 @@ func (code ErrorCode) Error() error {
/* case SCARD_W_CARD_NOT_AUTHENTICATED: */
case ErrSCardUnsupportedFeature:
return fmt.Errorf("feature not supported")
return fmt.Errorf("Feature not supported")
default:
return fmt.Errorf("unknown error: %08x", code)

View file

@ -291,16 +291,16 @@ func (client *Client) Connect(name string, shareMode uint32, preferredProtocol u
*
* These data are passed throw the field \c sharedSegmentMsg.data.
*/
//type transmit struct {
//hCard uint32
//ioSendPciProtocol uint32
//ioSendPciLength uint32
//cbSendLength uint32
//ioRecvPciProtocol uint32
//ioRecvPciLength uint32
//pcbRecvLength uint32
//rv uint32
//}
type transmit struct {
hCard uint32
ioSendPciProtocol uint32
ioSendPciLength uint32
cbSendLength uint32
ioRecvPciProtocol uint32
ioRecvPciLength uint32
pcbRecvLength uint32
rv uint32
}
// SCardIoRequest contains the info needed for performing an IO request
type SCardIoRequest struct {
@ -336,7 +336,7 @@ func (card *Card) Transmit(adpu []byte) ([]byte, *SCardIoRequest, error) {
return nil, nil, err
}
if n != len(adpu) {
return nil, nil, fmt.Errorf("invalid number of bytes written: expected %d, got %d", len(adpu), n)
return nil, nil, fmt.Errorf("Invalid number of bytes written: expected %d, got %d", len(adpu), n)
}
response := [TransmitRequestLength]byte{}
total := 0

View file

@ -1,6 +1,6 @@
run:
# timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 2m
deadline: 2m
linters:
enable:
#- golint

View file

@ -6,8 +6,8 @@ matrix:
- go: master
include:
# Supported versions of Go: https://golang.org/dl/
- go: "1.11.x"
- go: "1.12.x"
- go: "1.13.x"
- go: master
go_import_path: github.com/golang-migrate/migrate
@ -34,7 +34,7 @@ before_install:
- sudo apt-get update
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
# Install golangci-lint
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.20.0
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.17.1
- echo "TRAVIS_GO_VERSION=${TRAVIS_GO_VERSION}"
install:
@ -57,7 +57,7 @@ deploy:
secure: hWH1HLPpzpfA8pXQ93T1qKQVFSpQp0as/JLQ7D91jHuJ8p+RxVeqblDrR6HQY/95R/nyiE9GJmvUolSuw5h449LSrGxPtVWhdh6EnkxlQHlen5XeMhVjRjFV0sE9qGe8v7uAkiTfRO61ktTWHrEAvw5qpyqnNISodmZS78XIasPODQbNlzwINhWhDTHIjXGb4FpizYaL3OGCanrxfR9fQyCaqKGGBjRq3Mfq8U6Yd4mApmsE+uJxgaZV8K5zBqpkSzQRWhcVGNL5DuLsU3gfSJOo7kZeA2G71SHffH577dBoqtCZ4VFv169CoUZehLWCb+7XKJZmHXVujCURATSySLGUOPc6EoLFAn3YtsCA04mS4bZVo5FZPWVwfhjmkhtDR4f6wscKp7r1HsFHSOgm59QfETQdrn4MnZ44H2Jd39axqndn5DvK9EcZVjPHynOPnueXP2u6mTuUgh2VyyWBCDO3CNo0fGlo7VJI69IkIWNSD87K9cHZWYMClyKZkUzS+PmRAhHRYbVd+9ZjKOmnU36kUHNDG/ft1D4ogsY+rhVtXB4lgWDM5adri+EIScYdYnB1/pQexLBigcJY9uE7nQTR0U6QgVNYvun7uRNs40E0c4voSfmPdFO0FlOD2y1oQhnaXfWLbu9nMcTcs4RFGrcC7NzkUN4/WjG8s285V6w=
skip_cleanup: true
on:
go: "1.13.x"
go: "1.12.x"
repo: golang-migrate/migrate
tags: true
file:
@ -75,7 +75,7 @@ deploy:
package_glob: '*.deb'
skip_cleanup: true
on:
go: "1.13.x"
go: "1.12.x"
repo: golang-migrate/migrate
tags: true
- provider: packagecloud
@ -87,7 +87,7 @@ deploy:
package_glob: '*.deb'
skip_cleanup: true
on:
go: "1.13.x"
go: "1.12.x"
repo: golang-migrate/migrate
tags: true
- provider: packagecloud
@ -99,7 +99,7 @@ deploy:
package_glob: '*.deb'
skip_cleanup: true
on:
go: "1.13.x"
go: "1.12.x"
repo: golang-migrate/migrate
tags: true
- provider: packagecloud
@ -111,7 +111,7 @@ deploy:
package_glob: '*.deb'
skip_cleanup: true
on:
go: "1.13.x"
go: "1.12.x"
repo: golang-migrate/migrate
tags: true
- provider: packagecloud
@ -123,13 +123,13 @@ deploy:
package_glob: '*.deb'
skip_cleanup: true
on:
go: "1.13.x"
go: "1.12.x"
repo: golang-migrate/migrate
tags: true
- provider: script
script: ./docker-deploy.sh
skip_cleanup: true
on:
go: "1.13.x"
go: "1.12.x"
repo: golang-migrate/migrate
tags: true

View file

@ -8,7 +8,7 @@ WORKDIR /go/src/github.com/golang-migrate/migrate
COPY . ./
ENV GO111MODULE=on
ENV DATABASES="postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver firebird"
ENV DATABASES="postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver"
ENV SOURCES="file go_bindata github github_ee aws_s3 google_cloud_storage godoc_vfs gitlab"
RUN go build -a -o build/migrate.linux-386 -ldflags="-s -w -X main.Version=${VERSION}" -tags "$DATABASES $SOURCES" ./cmd/migrate

View file

@ -1,5 +1,5 @@
SOURCE ?= file go_bindata github github_ee aws_s3 google_cloud_storage godoc_vfs gitlab
DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver firebird
DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver
VERSION ?= $(shell git describe --tags 2>/dev/null | cut -c 2-)
TEST_FLAGS ?=
REPO_OWNER ?= $(shell cd .. && basename "$$(pwd)")

View file

@ -3,7 +3,7 @@
[![Coverage Status](https://img.shields.io/coveralls/github/golang-migrate/migrate/master.svg)](https://coveralls.io/github/golang-migrate/migrate?branch=master)
[![packagecloud.io](https://img.shields.io/badge/deb-packagecloud.io-844fec.svg)](https://packagecloud.io/golang-migrate/migrate?filter=debs)
[![Docker Pulls](https://img.shields.io/docker/pulls/migrate/migrate.svg)](https://hub.docker.com/r/migrate/migrate/)
![Supported Go Versions](https://img.shields.io/badge/Go-1.12%2C%201.13-lightgrey.svg)
![Supported Go Versions](https://img.shields.io/badge/Go-1.11%2C%201.12-lightgrey.svg)
[![GitHub Release](https://img.shields.io/github/release/golang-migrate/migrate.svg)](https://github.com/golang-migrate/migrate/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/golang-migrate/migrate)](https://goreportcard.com/report/github.com/golang-migrate/migrate)
@ -36,7 +36,7 @@ Database drivers run migrations. [Add a new database?](database/driver.go)
* [Google Cloud Spanner](database/spanner)
* [CockroachDB](database/cockroachdb)
* [ClickHouse](database/clickhouse)
* [Firebird](database/firebird)
* [Firebird](database/firebird) ([todo #49](https://github.com/golang-migrate/migrate/issues/49))
* [MS SQL Server](database/sqlserver)
### Database URLs

View file

@ -54,5 +54,3 @@ require (
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb
google.golang.org/grpc v1.20.1 // indirect
)
go 1.12

View file

@ -348,6 +348,21 @@ func (c *StatusTag) MarshalJSON() ([]byte, error) {
return json.Marshal(&c1)
}
type Mention struct {
Leaf
}
func (c *Mention) MarshalJSON() ([]byte, error) {
type MentionJSON struct {
Type string `json:"type"`
Literal string `json:"literal"`
}
var c1 MentionJSON
c1.Literal = string(c.Literal)
c1.Type = "mention"
return json.Marshal(&c1)
}
// Strong represents markdown strong node
type Strong struct {
Leaf

View file

@ -63,6 +63,41 @@ func (p *Parser) Inline(currBlock ast.Node, data []byte) {
p.nesting--
}
const pkLength = 132
func mention(p *Parser, data []byte, offset int) (int, ast.Node) {
data = data[offset:]
n := len(data)
if n < pkLength+1 {
return 0, nil
}
// need to start with 0x
if data[1] != '0' || data[2] != 'x' {
return 0, nil
}
i := 3
for i < pkLength+1 {
if !isValidPublicKeyChar(data[i]) {
return 0, nil
}
i++
}
// Check there's a space
if n != pkLength+1 && !isValidTerminatingMentionChar(data[pkLength+1]) {
return 0, nil
}
mention := &ast.Mention{}
mention.Literal = data[1 : pkLength+1]
return i, mention
}
func statusTag(p *Parser, data []byte, offset int) (int, ast.Node) {
data = data[offset:]
n := len(data)

View file

@ -143,6 +143,7 @@ func NewWithExtensions(extension Extensions) *Parser {
p.inlineCallback[' '] = maybeLineBreak
p.inlineCallback['*'] = emphasis
p.inlineCallback['#'] = statusTag
p.inlineCallback['@'] = mention
p.inlineCallback['_'] = emphasis
if p.extensions&Strikethrough != 0 {
p.inlineCallback['~'] = emphasis
@ -684,6 +685,14 @@ func isValidStatusTagChar(c byte) bool {
return isAlnum(c) || c == '-'
}
func isValidTerminatingMentionChar(c byte) bool {
return isSpace(c) || c == '.' || c == ',' || c == ':' || c == ';'
}
func isValidPublicKeyChar(c byte) bool {
return c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9' || c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' || c == 'f'
}
// TODO: this is not used
// Replace tab characters with spaces, aligning to the next TAB_SIZE column.
// always ends output with a newline

View file

@ -5,12 +5,23 @@ import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
"math/rand"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
var chatColors = []string{
"#fa6565", // red
"#887af9", // blue
"#FE8F59", // orange
"#7cda00", // green
"#51d0f0", // light-blue
"#d37ef4", // purple
}
type ChatType int
const (
@ -31,9 +42,6 @@ type Chat struct {
ChatType ChatType `json:"chatType"`
// Only filled for one to one chats
PublicKey *ecdsa.PublicKey `json:"-"`
// Timestamp indicates the last time this chat has received/sent a message
Timestamp int64 `json:"timestamp"`
// LastClockValue indicates the last clock value to be used when sending messages
@ -50,7 +58,21 @@ type Chat struct {
// Members are the members who have been invited to the group chat
Members []ChatMember `json:"members"`
// MembershipUpdates is all the membership events in the chat
MembershipUpdates []ChatMembershipUpdate `json:"membershipUpdates"`
MembershipUpdates []v1protocol.MembershipUpdateEvent `json:"membershipUpdateEvents"`
}
func (c *Chat) PublicKey() (*ecdsa.PublicKey, error) {
// For one to one chatID is an encoded public key
if c.ChatType != ChatTypeOneToOne {
return nil, nil
}
pkey, err := hex.DecodeString(c.ID[2:])
if err != nil {
return nil, err
}
// Safety check, make sure is well formed
return crypto.UnmarshalPubkey(pkey)
}
func (c *Chat) MarshalJSON() ([]byte, error) {
@ -131,30 +153,15 @@ func (c *Chat) updateChatFromProtocolGroup(g *v1protocol.Group) {
c.Members = chatMembers
// MembershipUpdates
updates := g.Updates()
membershipUpdates := make([]ChatMembershipUpdate, 0, len(updates))
for _, update := range updates {
membershipUpdate := ChatMembershipUpdate{
Type: update.Type,
Name: update.Name,
ClockValue: uint64(update.ClockValue), // TODO: get rid of type casting
Signature: update.Signature,
From: update.From,
Member: update.Member,
Members: update.Members,
}
membershipUpdate.setID()
membershipUpdates = append(membershipUpdates, membershipUpdate)
}
c.MembershipUpdates = membershipUpdates
c.MembershipUpdates = g.Events()
}
// ChatMembershipUpdate represent an event on membership of the chat
type ChatMembershipUpdate struct {
// Unique identifier for the event
ID string `json:"id"`
// Type indicates the kind of event (i.e changed-name, added-member, etc)
Type string `json:"type"`
// Type indicates the kind of event
Type protobuf.MembershipUpdateEvent_EventType `json:"type"`
// Name represents the name in the event of changing name events
Name string `json:"name,omitempty"`
// Clock value of the event
@ -198,11 +205,10 @@ func oneToOneChatID(publicKey *ecdsa.PublicKey) string {
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey) Chat {
return Chat{
ID: oneToOneChatID(publicKey),
Name: name,
Active: true,
ChatType: ChatTypeOneToOne,
PublicKey: publicKey,
ID: oneToOneChatID(publicKey),
Name: name,
Active: true,
ChatType: ChatTypeOneToOne,
}
}
@ -211,14 +217,17 @@ func CreatePublicChat(name string) Chat {
ID: name,
Name: name,
Active: true,
Color: chatColors[rand.Intn(len(chatColors))],
ChatType: ChatTypePublic,
}
}
func createGroupChat() Chat {
return Chat{
Active: true,
ChatType: ChatTypePrivateGroupChat,
Active: true,
Color: chatColors[rand.Intn(len(chatColors))],
Timestamp: int64(timestampInMs()),
ChatType: ChatTypePrivateGroupChat,
}
}

View file

@ -5,24 +5,5 @@ import (
)
func newProtocolGroupFromChat(chat *Chat) (*v1protocol.Group, error) {
return v1protocol.NewGroup(chat.ID, chatToFlattenMembershipUpdate(chat))
}
func chatToFlattenMembershipUpdate(chat *Chat) []v1protocol.MembershipUpdateFlat {
result := make([]v1protocol.MembershipUpdateFlat, len(chat.MembershipUpdates))
for idx, update := range chat.MembershipUpdates {
result[idx] = v1protocol.MembershipUpdateFlat{
ChatID: chat.ID,
From: update.From,
Signature: update.Signature,
MembershipUpdateEvent: v1protocol.MembershipUpdateEvent{
Name: update.Name,
Type: update.Type,
ClockValue: int64(update.ClockValue), // TODO: remove type difference
Member: update.Member,
Members: update.Members,
},
}
}
return result
return v1protocol.NewGroup(chat.ID, chat.MembershipUpdates)
}

View file

@ -4,7 +4,7 @@ go 1.13
replace github.com/ethereum/go-ethereum v1.9.5 => github.com/status-im/go-ethereum v1.9.5-status.7
replace github.com/gomarkdown/markdown => github.com/status-im/markdown v0.0.0-20191113114344-af599402d015
replace github.com/gomarkdown/markdown => github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba
replace github.com/status-im/status-go/eth-node => ../eth-node
@ -14,20 +14,18 @@ require (
github.com/cenkalti/backoff/v3 v3.0.0
github.com/ethereum/go-ethereum v1.9.5
github.com/golang/protobuf v1.3.2
github.com/gomarkdown/markdown v0.0.0-20191113114344-af599402d015
github.com/gomarkdown/markdown v0.0.0-20191209105822-e3ba6c6109ba
github.com/google/uuid v1.1.1
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
github.com/lucasb-eyer/go-colorful v1.0.2
github.com/mattn/go-pointer v0.0.0-20190911064623-a0a44394634f
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
github.com/pkg/errors v0.8.1
github.com/russolsen/transit v0.0.0-20180705123435-0794b4c4505a
github.com/status-im/doubleratchet v3.0.0+incompatible
github.com/status-im/migrate/v4 v4.6.2-status.2
github.com/status-im/status-go/eth-node v0.0.0-20191120100713-5053b0b6835b
github.com/status-im/status-go/whisper/v6 v6.0.0
github.com/status-im/status-go/eth-node v1.0.0
github.com/status-im/status-go/whisper/v6 v6.0.1
github.com/stretchr/testify v1.4.0
github.com/vacp2p/mvds v0.0.23
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba
)

View file

@ -34,9 +34,8 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:
github.com/aristanetworks/goarista v0.0.0-20181002214814-33151c4543a7/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0=
github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708 h1:tS7jSmwRqSxTnonTRlDD1oHo6Q9YOK4xHS9/v4L56eg=
github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7 h1:fKnuvQ/O22ZpD7HaJjGQXn/GxOdDJOQFL8bpM8Xe3X8=
github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
@ -49,6 +48,8 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR
github.com/btcsuite/btcd v0.0.0-20181013004428-67e573d211ac/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.0.0-20190418232430-6867ff32788a/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
@ -124,6 +125,8 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB
github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo=
github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo=
github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/ethereum/go-ethereum v1.8.20/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
@ -136,6 +139,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gizak/termui v0.0.0-20170117222342-991cd3d38091/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
@ -145,10 +150,10 @@ github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2i
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-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
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=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
@ -160,6 +165,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k=
github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0=
github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs=
github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@ -254,6 +261,8 @@ github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2vi
github.com/karalabe/hid v0.0.0-20181128192157-d815e0c1a2e2/go.mod h1:YvbcH+3Wo6XPs9nkgTY3u19KXLauXW+J5nB7hEHuX0A=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 h1:VhnqxaTIudc9IWKx8uXRLnpdSb9noCEj+vHacjmhp68=
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 h1:ZHuwnjpP8LsVsUYqTqeVAI+GfDfJ6UNPrExZF+vX/DQ=
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@ -270,8 +279,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -359,8 +368,14 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex
github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg=
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -373,8 +388,26 @@ github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVq
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
github.com/multiformats/go-multiaddr-dns v0.1.0/go.mod h1:01k2RAqtoXIuPa3DCavAE9/6jc6nM0H3EgZyfUhN2oY=
github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=
github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik=
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg=
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f h1:hd3r+uv9DNLScbOrnlj82rBldHQf3XWmCeXAWbw8euQ=
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f/go.mod h1:MyUWrZlB1aI5bs7j9/pJ8ckLLZ4QcCYcNiSbsAW32D4=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@ -480,21 +513,27 @@ github.com/status-im/doubleratchet v3.0.0+incompatible h1:aJ1ejcSERpSzmWZBgtfYti
github.com/status-im/doubleratchet v3.0.0+incompatible/go.mod h1:1sqR0+yhiM/bd+wrdX79AOt2csZuJOni0nUDzKNuqOU=
github.com/status-im/go-ethereum v1.9.5-status.6 h1:ytuTO1yBIAuTVRtRQoc2mrdyngtP+XOQ9IHIibbz7/I=
github.com/status-im/go-ethereum v1.9.5-status.6/go.mod h1:08JvQWE+IOnAFSe4UD4ACLNe2fDd9XmWMCq5Yzy9mk0=
github.com/status-im/go-ethereum v1.9.5-status.7 h1:DKH1GiF52LwaZaw6YDBliFEgm/JDsbIT+hn7ph6X94Q=
github.com/status-im/go-ethereum v1.9.5-status.7/go.mod h1:YyH5DKB6+z+Vaya7eIm67pnuPZ1oiUMbbsZW41ktN0g=
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/markdown v0.0.0-20191113114344-af599402d015 h1:ijC73VP0hucsy/MRn4cmtoQVB1mKdLcvurMYPvmPc4Y=
github.com/status-im/markdown v0.0.0-20191113114344-af599402d015/go.mod h1:tmG2bxyvZ2EItDO5JewbdFvV45j13IYQgvnMJ3+qAaE=
github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0 h1:5UdlDkkBoPrJfh7zkfoR3X5utJhNs/MCQysK3x0ycgg=
github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba h1:Ut2CKuG+L9eWFL7dTEPuLE+RKecUYBkDNhqXSIgY92U=
github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba/go.mod h1:tmG2bxyvZ2EItDO5JewbdFvV45j13IYQgvnMJ3+qAaE=
github.com/status-im/migrate/v4 v4.6.2-status.2 h1:SdC+sMDl/aI7vUlwD2qj2p7KsK4T60IS9z4/rYCCbI8=
github.com/status-im/migrate/v4 v4.6.2-status.2/go.mod h1:c/kc90n47GZu/58nnz1OMLTf7uE4Da4gZP5qmU+A/v8=
github.com/status-im/rendezvous v1.3.0/go.mod h1:+hzjuP+j/XzLPeF6E50b88pWOTLdTcwjvNYt+Gh1W1s=
github.com/status-im/status-go v0.36.0 h1:91qDMJjHv+T3Li9FwxsWQ2JBVcYtvVDT0nGFSMnmM+8=
github.com/status-im/status-go v0.36.1 h1:nb9eTq0UQJ57YyTZSl5U05emFT+R4AW8/Bga6ocgOks=
github.com/status-im/status-go v0.37.3 h1:94/bOA8qrEIgWd23mSLN39SwUJwCu2TPQFV2HzSI2ZE=
github.com/status-im/status-go v0.37.3/go.mod h1:9qHQ2+8NS6ivPJS5YbsI3gWkr0t6DWmJzKnr4M7vudw=
github.com/status-im/status-go/extkeys v1.0.0 h1:Qyirsoi5Ye5UFfisgPtCjPb/RkBxyK+UsSiEcr2PVlM=
github.com/status-im/status-go/extkeys v1.0.0/go.mod h1:GdqJbrcpkNm5ZsSCpp+PdMxnXx+OcRBdm3PI0rs1FpU=
github.com/status-im/status-go/protocol v1.0.1/go.mod h1:LpA7BsaNmj6EOdq7BwuqncewjPqIRHCletZOb2wlWrY=
github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501/go.mod h1:RYo/itke1oU5k/6sj9DNM3QAwtE5rZSgg5JnkOv83hk=
github.com/status-im/whisper v1.5.2 h1:26NgiKusmPic38eQdtXnaY+iaQ/LuQ3Dh0kCGYT/Uxs=
github.com/status-im/whisper v1.5.2/go.mod h1:emrOxzJme0k66QtbbQ2bdd3P8RCdLZ8sTD7SkwH1s2s=
github.com/status-im/whisper v1.6.1 h1:C/T1HQHZfUI2jbccf3yIe8yfkl435I3BILIKeNASJDc=
github.com/status-im/whisper v1.6.1/go.mod h1:lygchT4p9Y1/hR451OhNNqfinvy9EYEDxtXU2T/U30Q=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
@ -503,6 +542,7 @@ github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9C
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@ -604,8 +644,11 @@ golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/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-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -616,6 +659,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -629,8 +674,15 @@ golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=

View file

@ -0,0 +1,88 @@
package protocol
import (
"fmt"
"strings"
"time"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
var defaultSystemMessagesTranslations = map[protobuf.MembershipUpdateEvent_EventType]string{
protobuf.MembershipUpdateEvent_CHAT_CREATED: "{{from}} created the group {{name}}",
protobuf.MembershipUpdateEvent_NAME_CHANGED: "{{from}} changed the group's name to {{name}}",
protobuf.MembershipUpdateEvent_MEMBERS_ADDED: "{{from}} has invited {{members}}",
protobuf.MembershipUpdateEvent_MEMBER_JOINED: "{{from}} joined the group",
protobuf.MembershipUpdateEvent_ADMINS_ADDED: "{{from}} has made {{members}} admin",
protobuf.MembershipUpdateEvent_MEMBER_REMOVED: "{{member}} left the group",
protobuf.MembershipUpdateEvent_ADMIN_REMOVED: "{{member}} is not admin anymore",
}
func tsprintf(format string, params map[string]string) string {
for key, val := range params {
format = strings.Replace(format, "{{"+key+"}}", fmt.Sprintf("%s", val), -1)
}
return fmt.Sprintf(format)
}
func eventToSystemMessage(e v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) *Message {
var text string
switch e.Type {
case protobuf.MembershipUpdateEvent_CHAT_CREATED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_CHAT_CREATED], map[string]string{"from": "@" + e.From, "name": e.Name})
case protobuf.MembershipUpdateEvent_NAME_CHANGED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_NAME_CHANGED], map[string]string{"from": "@" + e.From, "name": e.Name})
case protobuf.MembershipUpdateEvent_MEMBERS_ADDED:
var memberMentions []string
for _, s := range e.Members {
memberMentions = append(memberMentions, "@"+s)
}
text = tsprintf(translations[protobuf.MembershipUpdateEvent_MEMBERS_ADDED], map[string]string{"from": "@" + e.From, "members": strings.Join(memberMentions, ", ")})
case protobuf.MembershipUpdateEvent_MEMBER_JOINED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_MEMBER_JOINED], map[string]string{"from": "@" + e.From})
case protobuf.MembershipUpdateEvent_ADMINS_ADDED:
var memberMentions []string
for _, s := range e.Members {
memberMentions = append(memberMentions, "@"+s)
}
text = tsprintf(translations[protobuf.MembershipUpdateEvent_ADMINS_ADDED], map[string]string{"from": "@" + e.From, "members": strings.Join(memberMentions, ", ")})
case protobuf.MembershipUpdateEvent_MEMBER_REMOVED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_MEMBER_REMOVED], map[string]string{"member": "@" + e.Members[0]})
case protobuf.MembershipUpdateEvent_ADMIN_REMOVED:
text = tsprintf(translations[protobuf.MembershipUpdateEvent_ADMIN_REMOVED], map[string]string{"member": "@" + e.Members[0]})
}
timestamp := v1protocol.TimestampInMsFromTime(time.Now())
message := &Message{
ChatMessage: protobuf.ChatMessage{
ChatId: e.ChatID,
Text: text,
MessageType: protobuf.ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP,
ContentType: protobuf.ChatMessage_TEXT_PLAIN,
Clock: e.ClockValue,
Timestamp: timestamp,
},
From: e.From,
WhisperTimestamp: timestamp,
LocalChatID: e.ChatID,
Seen: true,
ID: types.EncodeHex(crypto.Keccak256(e.Signature)),
}
message.PrepareContent()
return message
}
func buildSystemMessages(events []v1protocol.MembershipUpdateEvent, translations map[protobuf.MembershipUpdateEvent_EventType]string) []*Message {
var messages []*Message
for _, e := range events {
messages = append(messages, eventToSystemMessage(e, translations))
}
return messages
}

View file

@ -3,66 +3,44 @@ package protocol
import (
"github.com/pkg/errors"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
type persistentMessageHandler struct {
persistence *sqlitePersistence
}
func newPersistentMessageHandler(persistence *sqlitePersistence) *persistentMessageHandler {
return &persistentMessageHandler{persistence: persistence}
}
// HandleMembershipUpdate updates a Chat instance according to the membership updates.
// It retrieves chat, if exists, and merges membership updates from the message.
// Finally, the Chat is updated with the new group events.
func (h *persistentMessageHandler) HandleMembershipUpdate(m v1protocol.MembershipUpdateMessage) error {
chat, err := h.chatID(m.ChatID)
switch err {
case errChatNotFound:
group, err := v1protocol.NewGroupWithMembershipUpdates(m.ChatID, m.Updates)
func HandleMembershipUpdate(chat *Chat, m *v1protocol.MembershipUpdateMessage, myIdentity string, translations map[protobuf.MembershipUpdateEvent_EventType]string) (*Chat, []*Message, error) {
if chat == nil {
if len(m.Events) == 0 {
return nil, nil, errors.New("can't create new group chat without events")
}
group, err := v1protocol.NewGroupWithEvents(m.ChatID, m.Events)
if err != nil {
return err
return nil, nil, err
}
// A new chat must contain us
if !group.IsMember(myIdentity) {
return nil, nil, errors.New("can't create a new group chat without us being a member")
}
newChat := createGroupChat()
newChat.updateChatFromProtocolGroup(group)
chat = &newChat
case nil:
existingGroup, err := newProtocolGroupFromChat(chat)
if err != nil {
return errors.Wrap(err, "failed to create a Group from Chat")
}
updateGroup, err := v1protocol.NewGroupWithMembershipUpdates(m.ChatID, m.Updates)
if err != nil {
return errors.Wrap(err, "invalid membership update")
}
merged := v1protocol.MergeFlatMembershipUpdates(existingGroup.Updates(), updateGroup.Updates())
newGroup, err := v1protocol.NewGroup(chat.ID, merged)
if err != nil {
return errors.Wrap(err, "failed to create a group with new membership updates")
}
chat.updateChatFromProtocolGroup(newGroup)
default:
return err
return &newChat, buildSystemMessages(m.Events, translations), nil
}
return h.persistence.SaveChat(*chat)
}
func (h *persistentMessageHandler) chatID(chatID string) (*Chat, error) {
var chat *Chat
chats, err := h.persistence.Chats()
existingGroup, err := newProtocolGroupFromChat(chat)
if err != nil {
return nil, err
return nil, nil, errors.Wrap(err, "failed to create a Group from Chat")
}
for _, ch := range chats {
if ch.ID == chatID {
chat = ch
break
}
updateGroup, err := v1protocol.NewGroupWithEvents(m.ChatID, m.Events)
if err != nil {
return nil, nil, errors.Wrap(err, "invalid membership update")
}
if chat == nil {
return nil, errChatNotFound
merged := v1protocol.MergeMembershipUpdateEvents(existingGroup.Events(), updateGroup.Events())
newGroup, err := v1protocol.NewGroup(chat.ID, merged)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create a group with new membership updates")
}
return chat, nil
chat.updateChatFromProtocolGroup(newGroup)
return chat, buildSystemMessages(m.Events, translations), nil
}

View file

@ -14,6 +14,7 @@ import (
datasyncpeer "github.com/status-im/status-go/protocol/datasync/peer"
"github.com/status-im/status-go/protocol/encryption"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/protobuf"
transport "github.com/status-im/status-go/protocol/transport/whisper"
v1protocol "github.com/status-im/status-go/protocol/v1"
datasyncnode "github.com/vacp2p/mvds/node"
@ -28,16 +29,11 @@ const (
whisperPoWTime = 5
)
type messageHandler interface {
HandleMembershipUpdate(m v1protocol.MembershipUpdateMessage) error
}
type messageProcessor struct {
identity *ecdsa.PrivateKey
datasync *datasync.DataSync
protocol *encryption.Protocol
transport *transport.WhisperServiceTransport
handler messageHandler
logger *zap.Logger
featureFlags featureFlags
@ -48,7 +44,6 @@ func newMessageProcessor(
database *sql.DB,
enc *encryption.Protocol,
transport *transport.WhisperServiceTransport,
handler messageHandler,
logger *zap.Logger,
features featureFlags,
) (*messageProcessor, error) {
@ -71,7 +66,6 @@ func newMessageProcessor(
datasync: ds,
protocol: enc,
transport: transport,
handler: handler,
logger: logger,
featureFlags: features,
}
@ -97,13 +91,14 @@ func (p *messageProcessor) SendPrivateRaw(
ctx context.Context,
recipient *ecdsa.PublicKey,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
p.logger.Debug(
"sending a private message",
zap.Binary("public-key", crypto.FromECDSAPub(recipient)),
zap.String("site", "SendPrivateRaw"),
)
return p.sendPrivate(ctx, recipient, data)
return p.sendPrivate(ctx, recipient, data, messageType)
}
// SendGroupRaw takes encoded data, encrypts it and sends through the wire,
@ -112,13 +107,14 @@ func (p *messageProcessor) SendGroupRaw(
ctx context.Context,
recipients []*ecdsa.PublicKey,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
p.logger.Debug(
"sending a private group message",
zap.String("site", "SendGroupRaw"),
)
// Calculate messageID first
wrappedMessage, err := p.wrapMessageV1(data)
wrappedMessage, err := p.wrapMessageV1(data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
@ -126,7 +122,7 @@ func (p *messageProcessor) SendGroupRaw(
messageID := v1protocol.MessageID(&p.identity.PublicKey, wrappedMessage)
for _, recipient := range recipients {
_, err = p.sendPrivate(ctx, recipient, data)
_, err = p.sendPrivate(ctx, recipient, data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to send message")
}
@ -139,10 +135,11 @@ func (p *messageProcessor) sendPrivate(
ctx context.Context,
recipient *ecdsa.PublicKey,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
p.logger.Debug("sending private message", zap.Binary("recipient", crypto.FromECDSAPub(recipient)))
wrappedMessage, err := p.wrapMessageV1(data)
wrappedMessage, err := p.wrapMessageV1(data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
@ -176,37 +173,34 @@ func (p *messageProcessor) sendPrivate(
func (p *messageProcessor) SendMembershipUpdate(
ctx context.Context,
recipients []*ecdsa.PublicKey,
chatID string,
updates []v1protocol.MembershipUpdate,
clock int64,
) ([][]byte, error) {
group *v1protocol.Group,
chatMessage *protobuf.ChatMessage,
) ([]byte, error) {
p.logger.Debug("sending a membership update", zap.Int("membersCount", len(recipients)))
message := v1protocol.MembershipUpdateMessage{
ChatID: chatID,
Updates: updates,
ChatID: group.ChatID(),
Events: group.Events(),
Message: chatMessage,
}
encodedMessage, err := v1protocol.EncodeMembershipUpdateMessage(message)
if err != nil {
return nil, errors.Wrap(err, "failed to encode membership update message")
}
var resultIDs [][]byte
for _, recipient := range recipients {
messageID, err := p.sendPrivate(ctx, recipient, encodedMessage)
if err != nil {
return nil, err
}
resultIDs = append(resultIDs, messageID)
}
return resultIDs, nil
return p.SendGroupRaw(ctx, recipients, encodedMessage, protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE)
}
// SendPublicRaw takes encoded data, encrypts it and sends through the wire.
func (p *messageProcessor) SendPublicRaw(ctx context.Context, chatName string, data []byte) ([]byte, error) {
func (p *messageProcessor) SendPublicRaw(
ctx context.Context,
chatName string,
data []byte,
messageType protobuf.ApplicationMetadataMessage_Type,
) ([]byte, error) {
var newMessage *types.NewMessage
wrappedMessage, err := p.wrapMessageV1(data)
wrappedMessage, err := p.wrapMessageV1(data, messageType)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
@ -230,16 +224,6 @@ func (p *messageProcessor) SendPublicRaw(ctx context.Context, chatName string, d
return messageID, nil
}
func (p *messageProcessor) processMembershipUpdate(m v1protocol.MembershipUpdateMessage) error {
if err := m.Verify(); err != nil {
return err
}
if p.handler != nil {
return p.handler.HandleMembershipUpdate(m)
}
return errors.New("missing handler")
}
func (p *messageProcessor) processPairMessage(m v1protocol.PairMessage) error {
metadata := &multidevice.InstallationMetadata{
Name: m.Name,
@ -336,8 +320,8 @@ func (p *messageProcessor) handleErrDeviceNotFound(ctx context.Context, publicKe
return nil
}
func (p *messageProcessor) wrapMessageV1(encodedMessage []byte) ([]byte, error) {
wrappedMessage, err := v1protocol.WrapMessageV1(encodedMessage, p.identity)
func (p *messageProcessor) wrapMessageV1(encodedMessage []byte, messageType protobuf.ApplicationMetadataMessage_Type) ([]byte, error) {
wrappedMessage, err := v1protocol.WrapMessageV1(encodedMessage, messageType, p.identity)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}

View file

@ -0,0 +1,51 @@
package protocol
import (
"errors"
"github.com/status-im/status-go/protocol/protobuf"
"strings"
)
func ValidateReceivedChatMessage(message *protobuf.ChatMessage) error {
if message.Clock == 0 {
return errors.New("Clock can't be 0")
}
if message.Timestamp == 0 {
return errors.New("Timestamp can't be 0")
}
if len(strings.TrimSpace(message.Text)) == 0 {
return errors.New("Text can't be empty")
}
if len(message.ChatId) == 0 {
return errors.New("ChatId can't be empty")
}
if message.ContentType == protobuf.ChatMessage_UNKNOWN_CONTENT_TYPE {
return errors.New("Unknown content type")
}
if message.MessageType == protobuf.ChatMessage_UNKNOWN_MESSAGE_TYPE || message.MessageType == protobuf.ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP {
return errors.New("Unknown message type")
}
if message.ContentType == protobuf.ChatMessage_STICKER {
if message.Payload == nil {
return errors.New("No sticker content")
}
sticker := message.GetSticker()
if sticker == nil {
return errors.New("No sticker content")
}
if sticker.Pack == 0 {
return errors.New("Sticker pack not set")
}
if len(sticker.Hash) == 0 {
return errors.New("Sticker hash not set")
}
}
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -114,7 +114,7 @@ func _000001_initUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 832, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 832, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1c, 0xa4, 0xac, 0x0, 0xd3, 0x19, 0x53, 0x35, 0x91, 0x1c, 0x94, 0xea, 0xde, 0xa7, 0x75, 0xb6, 0x73, 0x1d, 0x42, 0x14, 0xca, 0x84, 0x5b, 0xdb, 0x10, 0x94, 0x28, 0xc0, 0x33, 0x95, 0x7f, 0xf}}
return a, nil
}
@ -154,7 +154,7 @@ func _000002_add_chatsUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 495, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "000002_add_chats.up.db.sql", size: 495, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6e, 0xca, 0x2b, 0xf7, 0xca, 0x21, 0xda, 0x17, 0x1f, 0x97, 0xa8, 0x12, 0xb5, 0x6c, 0xad, 0x92, 0xe7, 0x2, 0xaf, 0x1, 0xcb, 0x5e, 0xe9, 0x71, 0xc4, 0x81, 0xa7, 0x3, 0x93, 0x5b, 0x73, 0x73}}
return a, nil
}
@ -234,7 +234,7 @@ func _000004_user_messages_compatibilityUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000004_user_messages_compatibility.up.sql", size: 980, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "000004_user_messages_compatibility.up.sql", size: 980, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x7a, 0xba, 0xae, 0x6d, 0xef, 0x69, 0x12, 0x6b, 0x48, 0xe3, 0xa7, 0xad, 0x21, 0x4a, 0xcf, 0x4f, 0xbc, 0x14, 0xc1, 0x19, 0x69, 0x1c, 0xc, 0xa2, 0x3d, 0xbc, 0x12, 0x32, 0x71, 0x76, 0x15}}
return a, nil
}
@ -274,7 +274,7 @@ func _1567112142_user_messagesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1567112142_user_messages.up.sql", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1575009877, 0)}
info := bindataFileInfo{name: "1567112142_user_messages.up.sql", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1575563165, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xff, 0xc0, 0x47, 0x32, 0xa9, 0xa4, 0x6, 0x63, 0x6b, 0xe7, 0x79, 0x2b, 0x80, 0x52, 0x2b, 0x6f, 0xf9, 0x9d, 0x9a, 0xc2, 0xa9, 0x7a, 0xf7, 0x4d, 0x14, 0x12, 0x21, 0x10, 0xc4, 0x30, 0x42, 0xaa}}
return a, nil
}

View file

@ -5,10 +5,8 @@ import (
"context"
"database/sql"
"encoding/gob"
"encoding/hex"
"github.com/pkg/errors"
"github.com/status-im/status-go/eth-node/crypto"
)
var (
@ -45,6 +43,26 @@ func (db sqlitePersistence) SaveChats(chats []*Chat) error {
return nil
}
func (db sqlitePersistence) SaveContacts(contacts []*Contact) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
for _, contact := range contacts {
err := db.SaveContact(contact, tx)
if err != nil {
return err
}
}
return nil
}
func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
var err error
if tx == nil {
@ -62,21 +80,6 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
}()
}
pkey := []byte{}
// For one to one chatID is an encoded public key
if chat.ChatType == ChatTypeOneToOne {
pkey, err = hex.DecodeString(chat.ID[2:])
if err != nil {
return err
}
// Safety check, make sure is well formed
_, err := crypto.UnmarshalPubkey(pkey)
if err != nil {
return err
}
}
// Encode members
var encodedMembers bytes.Buffer
memberEncoder := gob.NewEncoder(&encodedMembers)
@ -94,8 +97,8 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
}
// Insert record
stmt, err := tx.Prepare(`INSERT INTO chats(id, name, color, active, type, timestamp, deleted_at_clock_value, public_key, unviewed_message_count, last_clock_value, last_message, members, membership_updates)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
stmt, err := tx.Prepare(`INSERT INTO chats(id, name, color, active, type, timestamp, deleted_at_clock_value, unviewed_message_count, last_clock_value, last_message, members, membership_updates)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
if err != nil {
return err
}
@ -109,7 +112,6 @@ func (db sqlitePersistence) saveChat(tx *sql.Tx, chat Chat) error {
chat.ChatType,
chat.Timestamp,
chat.DeletedAtClockValue,
pkey,
chat.UnviewedMessagesCount,
chat.LastClockValue,
chat.LastMessage,
@ -157,7 +159,6 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
type,
timestamp,
deleted_at_clock_value,
public_key,
unviewed_message_count,
last_clock_value,
last_message,
@ -176,7 +177,6 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
chat Chat
encodedMembers []byte
encodedMembershipUpdates []byte
pkey []byte
)
err = rows.Scan(
&chat.ID,
@ -186,7 +186,6 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
&chat.ChatType,
&chat.Timestamp,
&chat.DeletedAtClockValue,
&pkey,
&chat.UnviewedMessagesCount,
&chat.LastClockValue,
&chat.LastMessage,
@ -211,18 +210,73 @@ func (db sqlitePersistence) chats(tx *sql.Tx) (chats []*Chat, err error) {
return
}
if len(pkey) != 0 {
chat.PublicKey, err = crypto.UnmarshalPubkey(pkey)
if err != nil {
return
}
}
chats = append(chats, &chat)
}
return
}
func (db sqlitePersistence) Chat(chatID string) (*Chat, error) {
var (
chat Chat
encodedMembers []byte
encodedMembershipUpdates []byte
)
err := db.db.QueryRow(`
SELECT
id,
name,
color,
active,
type,
timestamp,
deleted_at_clock_value,
unviewed_message_count,
last_clock_value,
last_message,
members,
membership_updates
FROM chats
WHERE id = ?
`, chatID).Scan(&chat.ID,
&chat.Name,
&chat.Color,
&chat.Active,
&chat.ChatType,
&chat.Timestamp,
&chat.DeletedAtClockValue,
&chat.UnviewedMessagesCount,
&chat.LastClockValue,
&chat.LastMessage,
&encodedMembers,
&encodedMembershipUpdates,
)
switch err {
case sql.ErrNoRows:
return nil, nil
case nil:
// Restore members
membersDecoder := gob.NewDecoder(bytes.NewBuffer(encodedMembers))
err = membersDecoder.Decode(&chat.Members)
if err != nil {
return nil, err
}
// Restore membership updates
membershipUpdatesDecoder := gob.NewDecoder(bytes.NewBuffer(encodedMembershipUpdates))
err = membershipUpdatesDecoder.Decode(&chat.MembershipUpdates)
if err != nil {
return nil, err
}
return &chat, nil
}
return nil, err
}
func (db sqlitePersistence) Contacts() ([]*Contact, error) {
rows, err := db.db.Query(`
SELECT
@ -293,83 +347,7 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
return response, nil
}
func (db sqlitePersistence) SetContactsENSData(contacts []*Contact) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
// Ensure contacts exists
err = db.SetContactsGeneratedData(contacts, tx)
if err != nil {
return err
}
// Update ens data
for _, contact := range contacts {
_, err := tx.Exec(`UPDATE contacts SET name = ?, ens_verified = ? , ens_verified_at = ? WHERE id = ?`, contact.Name, contact.ENSVerified, contact.ENSVerifiedAt, contact.ID)
if err != nil {
return err
}
}
return nil
}
// SetContactsGeneratedData sets a contact generated data if not existing already
// in the database
func (db sqlitePersistence) SetContactsGeneratedData(contacts []*Contact, tx *sql.Tx) (err error) {
if tx == nil {
tx, err = db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
}
for _, contact := range contacts {
_, err = tx.Exec(`
INSERT OR IGNORE INTO contacts(
id,
address,
name,
alias,
identicon,
photo,
last_updated,
tribute_to_talk
) VALUES (?, ?, "", ?, ?, "", 0, "")`,
contact.ID,
contact.Address,
contact.Alias,
contact.Identicon,
)
if err != nil {
return
}
}
return
}
func (db sqlitePersistence) SaveContact(contact Contact, tx *sql.Tx) (err error) {
func (db sqlitePersistence) SaveContact(contact *Contact, tx *sql.Tx) (err error) {
if tx == nil {
tx, err = db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {

View file

@ -406,7 +406,7 @@ func (db sqlitePersistence) UpdateMessageOutgoingStatus(id string, newOutgoingSt
}
// BlockContact updates a contact, deletes all the messages and 1-to-1 chat, updates the unread messages count and returns a map with the new count
func (db sqlitePersistence) BlockContact(contact Contact) ([]*Chat, error) {
func (db sqlitePersistence) BlockContact(contact *Contact) ([]*Chat, error) {
var chats []*Chat
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {

View file

@ -0,0 +1,144 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: application_metadata_message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ApplicationMetadataMessage_Type int32
const (
ApplicationMetadataMessage_UNKNOWN ApplicationMetadataMessage_Type = 0
ApplicationMetadataMessage_CHAT_MESSAGE ApplicationMetadataMessage_Type = 1
ApplicationMetadataMessage_CONTACT_REQUEST ApplicationMetadataMessage_Type = 2
ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ApplicationMetadataMessage_Type = 3
ApplicationMetadataMessage_PAIR_INSTALLATION ApplicationMetadataMessage_Type = 4
ApplicationMetadataMessage_SYNC_INSTALLATION ApplicationMetadataMessage_Type = 5
)
var ApplicationMetadataMessage_Type_name = map[int32]string{
0: "UNKNOWN",
1: "CHAT_MESSAGE",
2: "CONTACT_REQUEST",
3: "MEMBERSHIP_UPDATE_MESSAGE",
4: "PAIR_INSTALLATION",
5: "SYNC_INSTALLATION",
}
var ApplicationMetadataMessage_Type_value = map[string]int32{
"UNKNOWN": 0,
"CHAT_MESSAGE": 1,
"CONTACT_REQUEST": 2,
"MEMBERSHIP_UPDATE_MESSAGE": 3,
"PAIR_INSTALLATION": 4,
"SYNC_INSTALLATION": 5,
}
func (x ApplicationMetadataMessage_Type) String() string {
return proto.EnumName(ApplicationMetadataMessage_Type_name, int32(x))
}
func (ApplicationMetadataMessage_Type) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_ad09a6406fcf24c7, []int{0, 0}
}
type ApplicationMetadataMessage struct {
// Signature of the payload field
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
// This is the encoded protobuf of the application level message, i.e ChatMessage
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
// The type of protobuf message sent
Type ApplicationMetadataMessage_Type `protobuf:"varint,3,opt,name=type,proto3,enum=protobuf.ApplicationMetadataMessage_Type" json:"type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ApplicationMetadataMessage) Reset() { *m = ApplicationMetadataMessage{} }
func (m *ApplicationMetadataMessage) String() string { return proto.CompactTextString(m) }
func (*ApplicationMetadataMessage) ProtoMessage() {}
func (*ApplicationMetadataMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_ad09a6406fcf24c7, []int{0}
}
func (m *ApplicationMetadataMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplicationMetadataMessage.Unmarshal(m, b)
}
func (m *ApplicationMetadataMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplicationMetadataMessage.Marshal(b, m, deterministic)
}
func (m *ApplicationMetadataMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplicationMetadataMessage.Merge(m, src)
}
func (m *ApplicationMetadataMessage) XXX_Size() int {
return xxx_messageInfo_ApplicationMetadataMessage.Size(m)
}
func (m *ApplicationMetadataMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ApplicationMetadataMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ApplicationMetadataMessage proto.InternalMessageInfo
func (m *ApplicationMetadataMessage) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func (m *ApplicationMetadataMessage) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
func (m *ApplicationMetadataMessage) GetType() ApplicationMetadataMessage_Type {
if m != nil {
return m.Type
}
return ApplicationMetadataMessage_UNKNOWN
}
func init() {
proto.RegisterEnum("protobuf.ApplicationMetadataMessage_Type", ApplicationMetadataMessage_Type_name, ApplicationMetadataMessage_Type_value)
proto.RegisterType((*ApplicationMetadataMessage)(nil), "protobuf.ApplicationMetadataMessage")
}
func init() { proto.RegisterFile("application_metadata_message.proto", fileDescriptor_ad09a6406fcf24c7) }
var fileDescriptor_ad09a6406fcf24c7 = []byte{
// 269 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x8e, 0x41, 0x4b, 0xc3, 0x30,
0x18, 0x86, 0x6d, 0x57, 0x9d, 0x7e, 0x0e, 0xad, 0x11, 0xa1, 0x8a, 0xc2, 0xe8, 0x69, 0x5e, 0x7a,
0xd0, 0xb3, 0x87, 0x58, 0x83, 0x2b, 0xae, 0x69, 0x4d, 0x52, 0xc4, 0x53, 0xc8, 0x5c, 0x1c, 0x85,
0x6d, 0x0d, 0x6b, 0x76, 0xe8, 0x2f, 0xf0, 0x57, 0xf8, 0x5f, 0x65, 0xd5, 0x39, 0x3c, 0x78, 0x0a,
0xef, 0x93, 0xf7, 0xe1, 0xfd, 0x20, 0x54, 0xc6, 0xcc, 0xca, 0x37, 0x65, 0xcb, 0x6a, 0x21, 0xe7,
0xda, 0xaa, 0x89, 0xb2, 0x4a, 0xce, 0x75, 0x5d, 0xab, 0xa9, 0x8e, 0xcc, 0xb2, 0xb2, 0x15, 0xda,
0x6f, 0x9f, 0xf1, 0xea, 0x3d, 0xfc, 0x74, 0xe1, 0x02, 0x6f, 0x85, 0xf4, 0xa7, 0x9f, 0x7e, 0xd7,
0xd1, 0x25, 0x1c, 0xd4, 0xe5, 0x74, 0xa1, 0xec, 0x6a, 0xa9, 0x03, 0xa7, 0xef, 0x0c, 0x7a, 0x6c,
0x0b, 0x50, 0x00, 0x5d, 0xa3, 0x9a, 0x59, 0xa5, 0x26, 0x81, 0xdb, 0xfe, 0x6d, 0x22, 0xba, 0x03,
0xcf, 0x36, 0x46, 0x07, 0x9d, 0xbe, 0x33, 0x38, 0xba, 0xb9, 0x8e, 0x36, 0x7b, 0xd1, 0xff, 0x5b,
0x91, 0x68, 0x8c, 0x66, 0xad, 0x16, 0x7e, 0x38, 0xe0, 0xad, 0x23, 0x3a, 0x84, 0x6e, 0x41, 0x9f,
0x68, 0xf6, 0x42, 0xfd, 0x1d, 0xe4, 0x43, 0x2f, 0x1e, 0x62, 0x21, 0x53, 0xc2, 0x39, 0x7e, 0x24,
0xbe, 0x83, 0x4e, 0xe1, 0x38, 0xce, 0xa8, 0xc0, 0xb1, 0x90, 0x8c, 0x3c, 0x17, 0x84, 0x0b, 0xdf,
0x45, 0x57, 0x70, 0x9e, 0x92, 0xf4, 0x9e, 0x30, 0x3e, 0x4c, 0x72, 0x59, 0xe4, 0x0f, 0x58, 0x90,
0x5f, 0xa7, 0x83, 0xce, 0xe0, 0x24, 0xc7, 0x09, 0x93, 0x09, 0xe5, 0x02, 0x8f, 0x46, 0x58, 0x24,
0x19, 0xf5, 0xbd, 0x35, 0xe6, 0xaf, 0x34, 0xfe, 0x8b, 0x77, 0xc7, 0x7b, 0xed, 0xe5, 0xb7, 0x5f,
0x01, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xdb, 0x0d, 0x56, 0x56, 0x01, 0x00, 0x00,
}

View file

@ -0,0 +1,22 @@
syntax = "proto3";
package protobuf;
message ApplicationMetadataMessage {
// Signature of the payload field
bytes signature = 1;
// This is the encoded protobuf of the application level message, i.e ChatMessage
bytes payload = 2;
// The type of protobuf message sent
Type type = 3;
enum Type {
UNKNOWN = 0;
CHAT_MESSAGE = 1;
CONTACT_REQUEST = 2;
MEMBERSHIP_UPDATE_MESSAGE = 3;
PAIR_INSTALLATION = 4;
SYNC_INSTALLATION = 5;
}
}

View file

@ -0,0 +1,326 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: chat_message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ChatMessage_MessageType int32
const (
ChatMessage_UNKNOWN_MESSAGE_TYPE ChatMessage_MessageType = 0
ChatMessage_ONE_TO_ONE ChatMessage_MessageType = 1
ChatMessage_PUBLIC_GROUP ChatMessage_MessageType = 2
ChatMessage_PRIVATE_GROUP ChatMessage_MessageType = 3
// Only local
ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP ChatMessage_MessageType = 4
)
var ChatMessage_MessageType_name = map[int32]string{
0: "UNKNOWN_MESSAGE_TYPE",
1: "ONE_TO_ONE",
2: "PUBLIC_GROUP",
3: "PRIVATE_GROUP",
4: "SYSTEM_MESSAGE_PRIVATE_GROUP",
}
var ChatMessage_MessageType_value = map[string]int32{
"UNKNOWN_MESSAGE_TYPE": 0,
"ONE_TO_ONE": 1,
"PUBLIC_GROUP": 2,
"PRIVATE_GROUP": 3,
"SYSTEM_MESSAGE_PRIVATE_GROUP": 4,
}
func (x ChatMessage_MessageType) String() string {
return proto.EnumName(ChatMessage_MessageType_name, int32(x))
}
func (ChatMessage_MessageType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{1, 0}
}
type ChatMessage_ContentType int32
const (
ChatMessage_UNKNOWN_CONTENT_TYPE ChatMessage_ContentType = 0
ChatMessage_TEXT_PLAIN ChatMessage_ContentType = 1
ChatMessage_STICKER ChatMessage_ContentType = 2
ChatMessage_STATUS ChatMessage_ContentType = 3
ChatMessage_EMOJI ChatMessage_ContentType = 4
ChatMessage_COMMAND ChatMessage_ContentType = 5
ChatMessage_COMMAND_REQUEST ChatMessage_ContentType = 6
)
var ChatMessage_ContentType_name = map[int32]string{
0: "UNKNOWN_CONTENT_TYPE",
1: "TEXT_PLAIN",
2: "STICKER",
3: "STATUS",
4: "EMOJI",
5: "COMMAND",
6: "COMMAND_REQUEST",
}
var ChatMessage_ContentType_value = map[string]int32{
"UNKNOWN_CONTENT_TYPE": 0,
"TEXT_PLAIN": 1,
"STICKER": 2,
"STATUS": 3,
"EMOJI": 4,
"COMMAND": 5,
"COMMAND_REQUEST": 6,
}
func (x ChatMessage_ContentType) String() string {
return proto.EnumName(ChatMessage_ContentType_name, int32(x))
}
func (ChatMessage_ContentType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{1, 1}
}
type StickerMessage struct {
Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
Pack int32 `protobuf:"varint,2,opt,name=pack,proto3" json:"pack,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *StickerMessage) Reset() { *m = StickerMessage{} }
func (m *StickerMessage) String() string { return proto.CompactTextString(m) }
func (*StickerMessage) ProtoMessage() {}
func (*StickerMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{0}
}
func (m *StickerMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StickerMessage.Unmarshal(m, b)
}
func (m *StickerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_StickerMessage.Marshal(b, m, deterministic)
}
func (m *StickerMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_StickerMessage.Merge(m, src)
}
func (m *StickerMessage) XXX_Size() int {
return xxx_messageInfo_StickerMessage.Size(m)
}
func (m *StickerMessage) XXX_DiscardUnknown() {
xxx_messageInfo_StickerMessage.DiscardUnknown(m)
}
var xxx_messageInfo_StickerMessage proto.InternalMessageInfo
func (m *StickerMessage) GetHash() string {
if m != nil {
return m.Hash
}
return ""
}
func (m *StickerMessage) GetPack() int32 {
if m != nil {
return m.Pack
}
return 0
}
type ChatMessage struct {
// Lamport timestamp of the chat message
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
// Unix timestamps in milliseconds, currently not used as we use whisper as more reliable, but here
// so that we don't rely on it
Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// Text of the message
Text string `protobuf:"bytes,3,opt,name=text,proto3" json:"text,omitempty"`
// Id of the message that we are replying to
ResponseTo string `protobuf:"bytes,4,opt,name=response_to,json=responseTo,proto3" json:"response_to,omitempty"`
// Ens name of the sender
EnsName string `protobuf:"bytes,5,opt,name=ens_name,json=ensName,proto3" json:"ens_name,omitempty"`
// Chat id, this field is symmetric for public-chats and private group chats,
// but asymmetric in case of one-to-ones, as the sender will use the chat-id
// of the received, while the receiver will use the chat-id of the sender.
// Probably should be the concatenation of sender-pk & receiver-pk in alphabetical order
ChatId string `protobuf:"bytes,6,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
// The type of message (public/one-to-one/private-group-chat)
MessageType ChatMessage_MessageType `protobuf:"varint,7,opt,name=message_type,json=messageType,proto3,enum=protobuf.ChatMessage_MessageType" json:"message_type,omitempty"`
// The type of the content of the message
ContentType ChatMessage_ContentType `protobuf:"varint,8,opt,name=content_type,json=contentType,proto3,enum=protobuf.ChatMessage_ContentType" json:"content_type,omitempty"`
// Types that are valid to be assigned to Payload:
// *ChatMessage_Sticker
Payload isChatMessage_Payload `protobuf_oneof:"payload"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ChatMessage) Reset() { *m = ChatMessage{} }
func (m *ChatMessage) String() string { return proto.CompactTextString(m) }
func (*ChatMessage) ProtoMessage() {}
func (*ChatMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_263952f55fd35689, []int{1}
}
func (m *ChatMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChatMessage.Unmarshal(m, b)
}
func (m *ChatMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ChatMessage.Marshal(b, m, deterministic)
}
func (m *ChatMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ChatMessage.Merge(m, src)
}
func (m *ChatMessage) XXX_Size() int {
return xxx_messageInfo_ChatMessage.Size(m)
}
func (m *ChatMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ChatMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ChatMessage proto.InternalMessageInfo
func (m *ChatMessage) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
func (m *ChatMessage) GetTimestamp() uint64 {
if m != nil {
return m.Timestamp
}
return 0
}
func (m *ChatMessage) GetText() string {
if m != nil {
return m.Text
}
return ""
}
func (m *ChatMessage) GetResponseTo() string {
if m != nil {
return m.ResponseTo
}
return ""
}
func (m *ChatMessage) GetEnsName() string {
if m != nil {
return m.EnsName
}
return ""
}
func (m *ChatMessage) GetChatId() string {
if m != nil {
return m.ChatId
}
return ""
}
func (m *ChatMessage) GetMessageType() ChatMessage_MessageType {
if m != nil {
return m.MessageType
}
return ChatMessage_UNKNOWN_MESSAGE_TYPE
}
func (m *ChatMessage) GetContentType() ChatMessage_ContentType {
if m != nil {
return m.ContentType
}
return ChatMessage_UNKNOWN_CONTENT_TYPE
}
type isChatMessage_Payload interface {
isChatMessage_Payload()
}
type ChatMessage_Sticker struct {
Sticker *StickerMessage `protobuf:"bytes,9,opt,name=sticker,proto3,oneof"`
}
func (*ChatMessage_Sticker) isChatMessage_Payload() {}
func (m *ChatMessage) GetPayload() isChatMessage_Payload {
if m != nil {
return m.Payload
}
return nil
}
func (m *ChatMessage) GetSticker() *StickerMessage {
if x, ok := m.GetPayload().(*ChatMessage_Sticker); ok {
return x.Sticker
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*ChatMessage) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*ChatMessage_Sticker)(nil),
}
}
func init() {
proto.RegisterEnum("protobuf.ChatMessage_MessageType", ChatMessage_MessageType_name, ChatMessage_MessageType_value)
proto.RegisterEnum("protobuf.ChatMessage_ContentType", ChatMessage_ContentType_name, ChatMessage_ContentType_value)
proto.RegisterType((*StickerMessage)(nil), "protobuf.StickerMessage")
proto.RegisterType((*ChatMessage)(nil), "protobuf.ChatMessage")
}
func init() { proto.RegisterFile("chat_message.proto", fileDescriptor_263952f55fd35689) }
var fileDescriptor_263952f55fd35689 = []byte{
// 462 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xcf, 0x6f, 0xd3, 0x30,
0x14, 0x5e, 0xda, 0xb4, 0x69, 0x5f, 0x46, 0x31, 0x66, 0x12, 0x46, 0x9a, 0x44, 0xe9, 0xa9, 0xa7,
0x1e, 0x06, 0x07, 0xae, 0x5d, 0x66, 0x8d, 0xb0, 0xc5, 0x29, 0x8e, 0x0b, 0xec, 0x64, 0x79, 0xa9,
0xa1, 0x55, 0x97, 0x1f, 0x6a, 0x8c, 0x44, 0x0f, 0xf0, 0x67, 0x73, 0x46, 0x71, 0x5a, 0xda, 0x5d,
0x76, 0xf2, 0xfb, 0xbe, 0xf7, 0xbd, 0xef, 0xe5, 0x7d, 0x01, 0x9c, 0x2e, 0x95, 0x91, 0x99, 0xae,
0x2a, 0xf5, 0x43, 0x4f, 0xca, 0x4d, 0x61, 0x0a, 0xdc, 0xb3, 0xcf, 0xfd, 0xcf, 0xef, 0xa3, 0x0f,
0x30, 0x48, 0xcc, 0x2a, 0x5d, 0xeb, 0x4d, 0xd4, 0x28, 0x30, 0x06, 0x77, 0xa9, 0xaa, 0x25, 0x71,
0x86, 0xce, 0xb8, 0xcf, 0x6d, 0x5d, 0x73, 0xa5, 0x4a, 0xd7, 0xa4, 0x35, 0x74, 0xc6, 0x1d, 0x6e,
0xeb, 0xd1, 0x5f, 0x17, 0xfc, 0x60, 0xa9, 0xcc, 0x7e, 0xee, 0x0c, 0x3a, 0xe9, 0x43, 0x91, 0xae,
0xed, 0xa0, 0xcb, 0x1b, 0x80, 0xcf, 0xa1, 0x6f, 0x56, 0x99, 0xae, 0x8c, 0xca, 0x4a, 0x3b, 0xee,
0xf2, 0x03, 0x51, 0xfb, 0x1a, 0xfd, 0xcb, 0x90, 0x76, 0xb3, 0xab, 0xae, 0xf1, 0x1b, 0xf0, 0x37,
0xba, 0x2a, 0x8b, 0xbc, 0xd2, 0xd2, 0x14, 0xc4, 0xb5, 0x2d, 0xd8, 0x53, 0xa2, 0xc0, 0xaf, 0xa1,
0xa7, 0xf3, 0x4a, 0xe6, 0x2a, 0xd3, 0xa4, 0x63, 0xbb, 0x9e, 0xce, 0x2b, 0xa6, 0x32, 0x8d, 0x5f,
0x81, 0x67, 0xaf, 0x5d, 0x2d, 0x48, 0xd7, 0x76, 0xba, 0x35, 0x0c, 0x17, 0xf8, 0x0a, 0x4e, 0x77,
0x09, 0x48, 0xb3, 0x2d, 0x35, 0xf1, 0x86, 0xce, 0x78, 0x70, 0xf1, 0x76, 0xb2, 0xcf, 0x61, 0x72,
0x74, 0xc9, 0x64, 0xf7, 0x8a, 0x6d, 0xa9, 0xb9, 0x9f, 0x1d, 0x40, 0xed, 0x92, 0x16, 0xb9, 0xd1,
0xb9, 0x69, 0x5c, 0x7a, 0x4f, 0xb9, 0x04, 0x8d, 0xb2, 0x71, 0x49, 0x0f, 0x00, 0xbf, 0x07, 0xaf,
0x6a, 0x22, 0x27, 0xfd, 0xa1, 0x33, 0xf6, 0x2f, 0xc8, 0xc1, 0xe0, 0xf1, 0xbf, 0xf8, 0x78, 0xc2,
0xf7, 0xd2, 0xd1, 0x1f, 0xf0, 0x8f, 0xbe, 0x0b, 0x13, 0x38, 0x9b, 0xb3, 0x1b, 0x16, 0x7f, 0x65,
0x32, 0xa2, 0x49, 0x32, 0xbd, 0xa6, 0x52, 0xdc, 0xcd, 0x28, 0x3a, 0xc1, 0x03, 0x80, 0x98, 0x51,
0x29, 0x62, 0x19, 0x33, 0x8a, 0x1c, 0x8c, 0xe0, 0x74, 0x36, 0xbf, 0xbc, 0x0d, 0x03, 0x79, 0xcd,
0xe3, 0xf9, 0x0c, 0xb5, 0xf0, 0x0b, 0x78, 0x36, 0xe3, 0xe1, 0x97, 0xa9, 0xa0, 0x3b, 0xaa, 0x8d,
0x87, 0x70, 0x9e, 0xdc, 0x25, 0x82, 0x46, 0xff, 0xdd, 0x1e, 0x2b, 0xdc, 0xd1, 0x6f, 0xf0, 0x8f,
0x2e, 0x3a, 0xde, 0x1f, 0xc4, 0x4c, 0x50, 0x26, 0x8e, 0xf6, 0x0b, 0xfa, 0x4d, 0xc8, 0xd9, 0xed,
0x34, 0x64, 0xc8, 0xc1, 0x3e, 0x78, 0x89, 0x08, 0x83, 0x1b, 0xca, 0x51, 0x0b, 0x03, 0x74, 0x13,
0x31, 0x15, 0xf3, 0x04, 0xb5, 0x71, 0x1f, 0x3a, 0x34, 0x8a, 0x3f, 0x85, 0xc8, 0xad, 0x35, 0x41,
0x1c, 0x45, 0x53, 0x76, 0x85, 0x3a, 0xf8, 0x25, 0x3c, 0xdf, 0x01, 0xc9, 0xe9, 0xe7, 0x39, 0x4d,
0x04, 0xea, 0x5e, 0xf6, 0xc1, 0x2b, 0xd5, 0xf6, 0xa1, 0x50, 0x8b, 0xfb, 0xae, 0x4d, 0xeb, 0xdd,
0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x19, 0x70, 0x9c, 0xd9, 0x02, 0x00, 0x00,
}

View file

@ -35,36 +35,20 @@ message ChatMessage {
}
enum MessageType {
ONE_TO_ONE = 0;
PUBLIC_GROUP = 1;
PRIVATE_GROUP = 2;
UNKNOWN_MESSAGE_TYPE = 0;
ONE_TO_ONE = 1;
PUBLIC_GROUP = 2;
PRIVATE_GROUP = 3;
// Only local
SYSTEM_MESSAGE_PRIVATE_GROUP = 3;
SYSTEM_MESSAGE_PRIVATE_GROUP = 4;
}
enum ContentType {
TEXT_PLAIN = 0;
STICKER = 1;
STATUS = 2;
EMOJI = 3;
COMMAND = 4;
COMMAND_REQUEST = 5;
}
}
message ApplicationMetadataMessage {
// Signature of the payload field
bytes signature = 1;
// This is the encoded protobuf of the application level message, i.e ChatMessage
bytes payload = 2;
// The type of protobuf message sent
MessageType message_type = 3;
enum MessageType {
TEXT_MESSAGE = 0;
CONTACT_REQUEST = 1;
MEMBERSHIP_UPDATE = 2;
PAIR_INSTALLATION = 3;
SYNC_INSTALLATION = 4;
UNKNOWN_CONTENT_TYPE = 0;
TEXT_PLAIN = 1;
STICKER = 2;
STATUS = 3;
EMOJI = 4;
COMMAND = 5;
COMMAND_REQUEST = 6;
}
}

View file

@ -0,0 +1,227 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: membership_update_message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type MembershipUpdateEvent_EventType int32
const (
MembershipUpdateEvent_UNKNOWN MembershipUpdateEvent_EventType = 0
MembershipUpdateEvent_CHAT_CREATED MembershipUpdateEvent_EventType = 1
MembershipUpdateEvent_NAME_CHANGED MembershipUpdateEvent_EventType = 2
MembershipUpdateEvent_MEMBERS_ADDED MembershipUpdateEvent_EventType = 3
MembershipUpdateEvent_MEMBER_JOINED MembershipUpdateEvent_EventType = 4
MembershipUpdateEvent_MEMBER_REMOVED MembershipUpdateEvent_EventType = 5
MembershipUpdateEvent_ADMINS_ADDED MembershipUpdateEvent_EventType = 6
MembershipUpdateEvent_ADMIN_REMOVED MembershipUpdateEvent_EventType = 7
)
var MembershipUpdateEvent_EventType_name = map[int32]string{
0: "UNKNOWN",
1: "CHAT_CREATED",
2: "NAME_CHANGED",
3: "MEMBERS_ADDED",
4: "MEMBER_JOINED",
5: "MEMBER_REMOVED",
6: "ADMINS_ADDED",
7: "ADMIN_REMOVED",
}
var MembershipUpdateEvent_EventType_value = map[string]int32{
"UNKNOWN": 0,
"CHAT_CREATED": 1,
"NAME_CHANGED": 2,
"MEMBERS_ADDED": 3,
"MEMBER_JOINED": 4,
"MEMBER_REMOVED": 5,
"ADMINS_ADDED": 6,
"ADMIN_REMOVED": 7,
}
func (x MembershipUpdateEvent_EventType) String() string {
return proto.EnumName(MembershipUpdateEvent_EventType_name, int32(x))
}
func (MembershipUpdateEvent_EventType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_8d37dd0dc857a6be, []int{0, 0}
}
type MembershipUpdateEvent struct {
// Lamport timestamp of the event
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
// List of public keys of objects of the action
Members []string `protobuf:"bytes,2,rep,name=members,proto3" json:"members,omitempty"`
// Name of the chat for the CHAT_CREATED/NAME_CHANGED event types
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
// The type of the event
Type MembershipUpdateEvent_EventType `protobuf:"varint,4,opt,name=type,proto3,enum=protobuf.MembershipUpdateEvent_EventType" json:"type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *MembershipUpdateEvent) Reset() { *m = MembershipUpdateEvent{} }
func (m *MembershipUpdateEvent) String() string { return proto.CompactTextString(m) }
func (*MembershipUpdateEvent) ProtoMessage() {}
func (*MembershipUpdateEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_8d37dd0dc857a6be, []int{0}
}
func (m *MembershipUpdateEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MembershipUpdateEvent.Unmarshal(m, b)
}
func (m *MembershipUpdateEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MembershipUpdateEvent.Marshal(b, m, deterministic)
}
func (m *MembershipUpdateEvent) XXX_Merge(src proto.Message) {
xxx_messageInfo_MembershipUpdateEvent.Merge(m, src)
}
func (m *MembershipUpdateEvent) XXX_Size() int {
return xxx_messageInfo_MembershipUpdateEvent.Size(m)
}
func (m *MembershipUpdateEvent) XXX_DiscardUnknown() {
xxx_messageInfo_MembershipUpdateEvent.DiscardUnknown(m)
}
var xxx_messageInfo_MembershipUpdateEvent proto.InternalMessageInfo
func (m *MembershipUpdateEvent) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
func (m *MembershipUpdateEvent) GetMembers() []string {
if m != nil {
return m.Members
}
return nil
}
func (m *MembershipUpdateEvent) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *MembershipUpdateEvent) GetType() MembershipUpdateEvent_EventType {
if m != nil {
return m.Type
}
return MembershipUpdateEvent_UNKNOWN
}
// MembershipUpdateMessage is a message used to propagate information
// about group membership changes.
// For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
type MembershipUpdateMessage struct {
// The chat id of the private group chat
ChatId string `protobuf:"bytes,1,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
// A list of events for this group chat, first x bytes are the signature, then is a
// protobuf encoded MembershipUpdateEvent
Events [][]byte `protobuf:"bytes,2,rep,name=events,proto3" json:"events,omitempty"`
// An optional chat message
Message *ChatMessage `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *MembershipUpdateMessage) Reset() { *m = MembershipUpdateMessage{} }
func (m *MembershipUpdateMessage) String() string { return proto.CompactTextString(m) }
func (*MembershipUpdateMessage) ProtoMessage() {}
func (*MembershipUpdateMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_8d37dd0dc857a6be, []int{1}
}
func (m *MembershipUpdateMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_MembershipUpdateMessage.Unmarshal(m, b)
}
func (m *MembershipUpdateMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_MembershipUpdateMessage.Marshal(b, m, deterministic)
}
func (m *MembershipUpdateMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_MembershipUpdateMessage.Merge(m, src)
}
func (m *MembershipUpdateMessage) XXX_Size() int {
return xxx_messageInfo_MembershipUpdateMessage.Size(m)
}
func (m *MembershipUpdateMessage) XXX_DiscardUnknown() {
xxx_messageInfo_MembershipUpdateMessage.DiscardUnknown(m)
}
var xxx_messageInfo_MembershipUpdateMessage proto.InternalMessageInfo
func (m *MembershipUpdateMessage) GetChatId() string {
if m != nil {
return m.ChatId
}
return ""
}
func (m *MembershipUpdateMessage) GetEvents() [][]byte {
if m != nil {
return m.Events
}
return nil
}
func (m *MembershipUpdateMessage) GetMessage() *ChatMessage {
if m != nil {
return m.Message
}
return nil
}
func init() {
proto.RegisterEnum("protobuf.MembershipUpdateEvent_EventType", MembershipUpdateEvent_EventType_name, MembershipUpdateEvent_EventType_value)
proto.RegisterType((*MembershipUpdateEvent)(nil), "protobuf.MembershipUpdateEvent")
proto.RegisterType((*MembershipUpdateMessage)(nil), "protobuf.MembershipUpdateMessage")
}
func init() { proto.RegisterFile("membership_update_message.proto", fileDescriptor_8d37dd0dc857a6be) }
var fileDescriptor_8d37dd0dc857a6be = []byte{
// 340 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x50, 0x41, 0x4f, 0xf2, 0x40,
0x10, 0xfd, 0x0a, 0xa5, 0xfd, 0x3a, 0x20, 0xa9, 0x13, 0x91, 0xc6, 0x8b, 0x0d, 0xa7, 0x7a, 0xa9,
0x09, 0x9e, 0x3d, 0xd4, 0xee, 0x46, 0xd0, 0xec, 0x92, 0xac, 0xa0, 0xc7, 0xa6, 0xc0, 0x2a, 0x44,
0x0b, 0x0d, 0x14, 0x13, 0xe2, 0x4f, 0xf1, 0x8f, 0xf8, 0xf3, 0x4c, 0x97, 0x16, 0xa2, 0xf1, 0xb2,
0xbb, 0xef, 0xcd, 0xbc, 0x37, 0x3b, 0x0f, 0xce, 0x13, 0x99, 0x8c, 0xe5, 0x6a, 0x3d, 0x9b, 0xa7,
0xd1, 0x26, 0x9d, 0xc6, 0x99, 0x8c, 0x12, 0xb9, 0x5e, 0xc7, 0x2f, 0xd2, 0x4f, 0x57, 0xcb, 0x6c,
0x89, 0xff, 0xd5, 0x35, 0xde, 0x3c, 0x9f, 0xe1, 0x64, 0x16, 0x67, 0x3f, 0xab, 0x9d, 0xaf, 0x0a,
0xb4, 0xd8, 0xde, 0x61, 0xa4, 0x0c, 0xe8, 0xbb, 0x5c, 0x64, 0x78, 0x02, 0xb5, 0xc9, 0xdb, 0x72,
0xf2, 0xea, 0x68, 0xae, 0xe6, 0xe9, 0x62, 0x07, 0xd0, 0x01, 0xb3, 0x18, 0xe8, 0x54, 0xdc, 0xaa,
0x67, 0x89, 0x12, 0x22, 0x82, 0xbe, 0x88, 0x13, 0xe9, 0x54, 0x5d, 0xcd, 0xb3, 0x84, 0x7a, 0xe3,
0x35, 0xe8, 0xd9, 0x36, 0x95, 0x8e, 0xee, 0x6a, 0x5e, 0xb3, 0x7b, 0xe1, 0x97, 0x5f, 0xf1, 0xff,
0x1c, 0xe9, 0xab, 0x73, 0xb8, 0x4d, 0xa5, 0x50, 0xb2, 0xce, 0xa7, 0x06, 0xd6, 0x9e, 0xc3, 0x3a,
0x98, 0x23, 0x7e, 0xcf, 0x07, 0x4f, 0xdc, 0xfe, 0x87, 0x36, 0x34, 0xc2, 0x5e, 0x30, 0x8c, 0x42,
0x41, 0x83, 0x21, 0x25, 0xb6, 0x96, 0x33, 0x3c, 0x60, 0x34, 0x0a, 0x7b, 0x01, 0xbf, 0xa5, 0xc4,
0xae, 0xe0, 0x31, 0x1c, 0x31, 0xca, 0x6e, 0xa8, 0x78, 0x88, 0x02, 0x42, 0x28, 0xb1, 0xab, 0x07,
0x2a, 0xba, 0x1b, 0xf4, 0x39, 0x25, 0xb6, 0x8e, 0x08, 0xcd, 0x82, 0x12, 0x94, 0x0d, 0x1e, 0x29,
0xb1, 0x6b, 0xb9, 0x57, 0x40, 0x58, 0x9f, 0x97, 0x42, 0x23, 0x17, 0x2a, 0x66, 0xdf, 0x64, 0x76,
0x3e, 0xa0, 0xfd, 0x7b, 0x0d, 0xb6, 0xcb, 0x16, 0xdb, 0x60, 0xaa, 0xac, 0xe7, 0x53, 0x95, 0x9e,
0x25, 0x8c, 0x1c, 0xf6, 0xa7, 0x78, 0x0a, 0x86, 0xcc, 0x17, 0xda, 0xa5, 0xd7, 0x10, 0x05, 0xc2,
0xcb, 0x3c, 0x56, 0xa5, 0x55, 0xf9, 0xd5, 0xbb, 0xad, 0x43, 0x56, 0xe1, 0x2c, 0xce, 0x0a, 0x63,
0x51, 0x76, 0x8d, 0x0d, 0x55, 0xbe, 0xfa, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x7f, 0xb8, 0xe8, 0x9e,
0xff, 0x01, 0x00, 0x00,
}

View file

@ -0,0 +1,40 @@
syntax = "proto3";
package protobuf;
import "chat_message.proto";
message MembershipUpdateEvent {
// Lamport timestamp of the event
uint64 clock = 1;
// List of public keys of objects of the action
repeated string members = 2;
// Name of the chat for the CHAT_CREATED/NAME_CHANGED event types
string name = 3;
// The type of the event
EventType type = 4;
enum EventType {
UNKNOWN = 0;
CHAT_CREATED = 1;
NAME_CHANGED = 2;
MEMBERS_ADDED = 3;
MEMBER_JOINED = 4;
MEMBER_REMOVED = 5;
ADMINS_ADDED = 6;
ADMIN_REMOVED = 7;
}
}
// MembershipUpdateMessage is a message used to propagate information
// about group membership changes.
// For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
message MembershipUpdateMessage {
// The chat id of the private group chat
string chat_id = 1;
// A list of events for this group chat, first x bytes are the signature, then is a
// protobuf encoded MembershipUpdateEvent
repeated bytes events = 2;
// An optional chat message
ChatMessage message = 3;
}

View file

@ -1,421 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ChatMessage_MessageType int32
const (
ChatMessage_ONE_TO_ONE ChatMessage_MessageType = 0
ChatMessage_PUBLIC_GROUP ChatMessage_MessageType = 1
ChatMessage_PRIVATE_GROUP ChatMessage_MessageType = 2
// Only local
ChatMessage_SYSTEM_MESSAGE_PRIVATE_GROUP ChatMessage_MessageType = 3
)
var ChatMessage_MessageType_name = map[int32]string{
0: "ONE_TO_ONE",
1: "PUBLIC_GROUP",
2: "PRIVATE_GROUP",
3: "SYSTEM_MESSAGE_PRIVATE_GROUP",
}
var ChatMessage_MessageType_value = map[string]int32{
"ONE_TO_ONE": 0,
"PUBLIC_GROUP": 1,
"PRIVATE_GROUP": 2,
"SYSTEM_MESSAGE_PRIVATE_GROUP": 3,
}
func (x ChatMessage_MessageType) String() string {
return proto.EnumName(ChatMessage_MessageType_name, int32(x))
}
func (ChatMessage_MessageType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{1, 0}
}
type ChatMessage_ContentType int32
const (
ChatMessage_TEXT_PLAIN ChatMessage_ContentType = 0
ChatMessage_STICKER ChatMessage_ContentType = 1
ChatMessage_STATUS ChatMessage_ContentType = 2
ChatMessage_EMOJI ChatMessage_ContentType = 3
ChatMessage_COMMAND ChatMessage_ContentType = 4
ChatMessage_COMMAND_REQUEST ChatMessage_ContentType = 5
)
var ChatMessage_ContentType_name = map[int32]string{
0: "TEXT_PLAIN",
1: "STICKER",
2: "STATUS",
3: "EMOJI",
4: "COMMAND",
5: "COMMAND_REQUEST",
}
var ChatMessage_ContentType_value = map[string]int32{
"TEXT_PLAIN": 0,
"STICKER": 1,
"STATUS": 2,
"EMOJI": 3,
"COMMAND": 4,
"COMMAND_REQUEST": 5,
}
func (x ChatMessage_ContentType) String() string {
return proto.EnumName(ChatMessage_ContentType_name, int32(x))
}
func (ChatMessage_ContentType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{1, 1}
}
type ApplicationMetadataMessage_MessageType int32
const (
ApplicationMetadataMessage_TEXT_MESSAGE ApplicationMetadataMessage_MessageType = 0
ApplicationMetadataMessage_CONTACT_REQUEST ApplicationMetadataMessage_MessageType = 1
ApplicationMetadataMessage_MEMBERSHIP_UPDATE ApplicationMetadataMessage_MessageType = 2
ApplicationMetadataMessage_PAIR_INSTALLATION ApplicationMetadataMessage_MessageType = 3
ApplicationMetadataMessage_SYNC_INSTALLATION ApplicationMetadataMessage_MessageType = 4
)
var ApplicationMetadataMessage_MessageType_name = map[int32]string{
0: "TEXT_MESSAGE",
1: "CONTACT_REQUEST",
2: "MEMBERSHIP_UPDATE",
3: "PAIR_INSTALLATION",
4: "SYNC_INSTALLATION",
}
var ApplicationMetadataMessage_MessageType_value = map[string]int32{
"TEXT_MESSAGE": 0,
"CONTACT_REQUEST": 1,
"MEMBERSHIP_UPDATE": 2,
"PAIR_INSTALLATION": 3,
"SYNC_INSTALLATION": 4,
}
func (x ApplicationMetadataMessage_MessageType) String() string {
return proto.EnumName(ApplicationMetadataMessage_MessageType_name, int32(x))
}
func (ApplicationMetadataMessage_MessageType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{2, 0}
}
type StickerMessage struct {
Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
Pack int32 `protobuf:"varint,2,opt,name=pack,proto3" json:"pack,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *StickerMessage) Reset() { *m = StickerMessage{} }
func (m *StickerMessage) String() string { return proto.CompactTextString(m) }
func (*StickerMessage) ProtoMessage() {}
func (*StickerMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{0}
}
func (m *StickerMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StickerMessage.Unmarshal(m, b)
}
func (m *StickerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_StickerMessage.Marshal(b, m, deterministic)
}
func (m *StickerMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_StickerMessage.Merge(m, src)
}
func (m *StickerMessage) XXX_Size() int {
return xxx_messageInfo_StickerMessage.Size(m)
}
func (m *StickerMessage) XXX_DiscardUnknown() {
xxx_messageInfo_StickerMessage.DiscardUnknown(m)
}
var xxx_messageInfo_StickerMessage proto.InternalMessageInfo
func (m *StickerMessage) GetHash() string {
if m != nil {
return m.Hash
}
return ""
}
func (m *StickerMessage) GetPack() int32 {
if m != nil {
return m.Pack
}
return 0
}
type ChatMessage struct {
// Lamport timestamp of the chat message
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
// Unix timestamps in milliseconds, currently not used as we use whisper as more reliable, but here
// so that we don't rely on it
Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// Text of the message
Text string `protobuf:"bytes,3,opt,name=text,proto3" json:"text,omitempty"`
// Id of the message that we are replying to
ResponseTo string `protobuf:"bytes,4,opt,name=response_to,json=responseTo,proto3" json:"response_to,omitempty"`
// Ens name of the sender
EnsName string `protobuf:"bytes,5,opt,name=ens_name,json=ensName,proto3" json:"ens_name,omitempty"`
// Chat id, this field is symmetric for public-chats and private group chats,
// but asymmetric in case of one-to-ones, as the sender will use the chat-id
// of the received, while the receiver will use the chat-id of the sender.
// Probably should be the concatenation of sender-pk & receiver-pk in alphabetical order
ChatId string `protobuf:"bytes,6,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
// The type of message (public/one-to-one/private-group-chat)
MessageType ChatMessage_MessageType `protobuf:"varint,7,opt,name=message_type,json=messageType,proto3,enum=protobuf.ChatMessage_MessageType" json:"message_type,omitempty"`
// The type of the content of the message
ContentType ChatMessage_ContentType `protobuf:"varint,8,opt,name=content_type,json=contentType,proto3,enum=protobuf.ChatMessage_ContentType" json:"content_type,omitempty"`
// Types that are valid to be assigned to Payload:
// *ChatMessage_Sticker
Payload isChatMessage_Payload `protobuf_oneof:"payload"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ChatMessage) Reset() { *m = ChatMessage{} }
func (m *ChatMessage) String() string { return proto.CompactTextString(m) }
func (*ChatMessage) ProtoMessage() {}
func (*ChatMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{1}
}
func (m *ChatMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChatMessage.Unmarshal(m, b)
}
func (m *ChatMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ChatMessage.Marshal(b, m, deterministic)
}
func (m *ChatMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ChatMessage.Merge(m, src)
}
func (m *ChatMessage) XXX_Size() int {
return xxx_messageInfo_ChatMessage.Size(m)
}
func (m *ChatMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ChatMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ChatMessage proto.InternalMessageInfo
func (m *ChatMessage) GetClock() uint64 {
if m != nil {
return m.Clock
}
return 0
}
func (m *ChatMessage) GetTimestamp() uint64 {
if m != nil {
return m.Timestamp
}
return 0
}
func (m *ChatMessage) GetText() string {
if m != nil {
return m.Text
}
return ""
}
func (m *ChatMessage) GetResponseTo() string {
if m != nil {
return m.ResponseTo
}
return ""
}
func (m *ChatMessage) GetEnsName() string {
if m != nil {
return m.EnsName
}
return ""
}
func (m *ChatMessage) GetChatId() string {
if m != nil {
return m.ChatId
}
return ""
}
func (m *ChatMessage) GetMessageType() ChatMessage_MessageType {
if m != nil {
return m.MessageType
}
return ChatMessage_ONE_TO_ONE
}
func (m *ChatMessage) GetContentType() ChatMessage_ContentType {
if m != nil {
return m.ContentType
}
return ChatMessage_TEXT_PLAIN
}
type isChatMessage_Payload interface {
isChatMessage_Payload()
}
type ChatMessage_Sticker struct {
Sticker *StickerMessage `protobuf:"bytes,9,opt,name=sticker,proto3,oneof"`
}
func (*ChatMessage_Sticker) isChatMessage_Payload() {}
func (m *ChatMessage) GetPayload() isChatMessage_Payload {
if m != nil {
return m.Payload
}
return nil
}
func (m *ChatMessage) GetSticker() *StickerMessage {
if x, ok := m.GetPayload().(*ChatMessage_Sticker); ok {
return x.Sticker
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*ChatMessage) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*ChatMessage_Sticker)(nil),
}
}
type ApplicationMetadataMessage struct {
// Signature of the payload field
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
// This is the encoded protobuf of the application level message, i.e ChatMessage
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
// The type of protobuf message sent
MessageType ApplicationMetadataMessage_MessageType `protobuf:"varint,3,opt,name=message_type,json=messageType,proto3,enum=protobuf.ApplicationMetadataMessage_MessageType" json:"message_type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ApplicationMetadataMessage) Reset() { *m = ApplicationMetadataMessage{} }
func (m *ApplicationMetadataMessage) String() string { return proto.CompactTextString(m) }
func (*ApplicationMetadataMessage) ProtoMessage() {}
func (*ApplicationMetadataMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{2}
}
func (m *ApplicationMetadataMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplicationMetadataMessage.Unmarshal(m, b)
}
func (m *ApplicationMetadataMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplicationMetadataMessage.Marshal(b, m, deterministic)
}
func (m *ApplicationMetadataMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplicationMetadataMessage.Merge(m, src)
}
func (m *ApplicationMetadataMessage) XXX_Size() int {
return xxx_messageInfo_ApplicationMetadataMessage.Size(m)
}
func (m *ApplicationMetadataMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ApplicationMetadataMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ApplicationMetadataMessage proto.InternalMessageInfo
func (m *ApplicationMetadataMessage) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func (m *ApplicationMetadataMessage) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
func (m *ApplicationMetadataMessage) GetMessageType() ApplicationMetadataMessage_MessageType {
if m != nil {
return m.MessageType
}
return ApplicationMetadataMessage_TEXT_MESSAGE
}
func init() {
proto.RegisterEnum("protobuf.ChatMessage_MessageType", ChatMessage_MessageType_name, ChatMessage_MessageType_value)
proto.RegisterEnum("protobuf.ChatMessage_ContentType", ChatMessage_ContentType_name, ChatMessage_ContentType_value)
proto.RegisterEnum("protobuf.ApplicationMetadataMessage_MessageType", ApplicationMetadataMessage_MessageType_name, ApplicationMetadataMessage_MessageType_value)
proto.RegisterType((*StickerMessage)(nil), "protobuf.StickerMessage")
proto.RegisterType((*ChatMessage)(nil), "protobuf.ChatMessage")
proto.RegisterType((*ApplicationMetadataMessage)(nil), "protobuf.ApplicationMetadataMessage")
}
func init() { proto.RegisterFile("message.proto", fileDescriptor_33c57e4bae7b9afd) }
var fileDescriptor_33c57e4bae7b9afd = []byte{
// 563 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x5f, 0x6f, 0xda, 0x3e,
0x14, 0x25, 0x10, 0xa0, 0xdc, 0xd0, 0xfe, 0x5c, 0xff, 0x36, 0x2d, 0x9b, 0x2a, 0x8d, 0xf1, 0xc4,
0x13, 0x9a, 0xba, 0x3d, 0xec, 0x35, 0x4d, 0xad, 0x36, 0x1b, 0xf9, 0x33, 0xdb, 0x4c, 0xeb, 0x93,
0xe5, 0x06, 0xaf, 0xa0, 0x96, 0x24, 0x22, 0xae, 0x34, 0xbe, 0xcf, 0x3e, 0xc9, 0x3e, 0xd9, 0x14,
0x07, 0x0a, 0x4c, 0xea, 0x9e, 0xec, 0x73, 0x7c, 0x7d, 0xee, 0xbd, 0xe7, 0x5e, 0x38, 0x5e, 0xaa,
0xb2, 0x94, 0x77, 0x6a, 0x5c, 0xac, 0x72, 0x9d, 0xe3, 0x23, 0x73, 0xdc, 0x3e, 0xfe, 0x18, 0x7e,
0x82, 0x13, 0xa6, 0x17, 0xe9, 0xbd, 0x5a, 0x85, 0x75, 0x04, 0xc6, 0x60, 0xcf, 0x65, 0x39, 0x77,
0xad, 0x81, 0x35, 0xea, 0x51, 0x73, 0xaf, 0xb8, 0x42, 0xa6, 0xf7, 0x6e, 0x73, 0x60, 0x8d, 0xda,
0xd4, 0xdc, 0x87, 0xbf, 0x6d, 0x70, 0xfc, 0xb9, 0xd4, 0xdb, 0x7f, 0x2f, 0xa0, 0x9d, 0x3e, 0xe4,
0xe9, 0xbd, 0xf9, 0x68, 0xd3, 0x1a, 0xe0, 0x33, 0xe8, 0xe9, 0xc5, 0x52, 0x95, 0x5a, 0x2e, 0x0b,
0xf3, 0xdd, 0xa6, 0x3b, 0xa2, 0xd2, 0xd5, 0xea, 0xa7, 0x76, 0x5b, 0x75, 0xae, 0xea, 0x8e, 0xdf,
0x82, 0xb3, 0x52, 0x65, 0x91, 0x67, 0xa5, 0x12, 0x3a, 0x77, 0x6d, 0xf3, 0x04, 0x5b, 0x8a, 0xe7,
0xf8, 0x35, 0x1c, 0xa9, 0xac, 0x14, 0x99, 0x5c, 0x2a, 0xb7, 0x6d, 0x5e, 0xbb, 0x2a, 0x2b, 0x23,
0xb9, 0x54, 0xf8, 0x15, 0x74, 0xd3, 0xb9, 0xd4, 0x62, 0x31, 0x73, 0x3b, 0xe6, 0xa5, 0x53, 0xc1,
0x60, 0x86, 0x2f, 0xa1, 0xbf, 0x71, 0x40, 0xe8, 0x75, 0xa1, 0xdc, 0xee, 0xc0, 0x1a, 0x9d, 0x9c,
0xbf, 0x1b, 0x6f, 0x7d, 0x18, 0xef, 0x75, 0x32, 0xde, 0x9c, 0x7c, 0x5d, 0x28, 0xea, 0x2c, 0x77,
0xa0, 0x52, 0x49, 0xf3, 0x4c, 0xab, 0x4c, 0xd7, 0x2a, 0x47, 0xff, 0x52, 0xf1, 0xeb, 0xc8, 0x5a,
0x25, 0xdd, 0x01, 0xfc, 0x11, 0xba, 0x65, 0x6d, 0xb9, 0xdb, 0x1b, 0x58, 0x23, 0xe7, 0xdc, 0xdd,
0x09, 0x1c, 0xce, 0xe2, 0xba, 0x41, 0xb7, 0xa1, 0xc3, 0x19, 0x38, 0x7b, 0x75, 0xe1, 0x13, 0x80,
0x38, 0x22, 0x82, 0xc7, 0x22, 0x8e, 0x08, 0x6a, 0x60, 0x04, 0xfd, 0x64, 0x7a, 0x31, 0x09, 0x7c,
0x71, 0x45, 0xe3, 0x69, 0x82, 0x2c, 0x7c, 0x0a, 0xc7, 0x09, 0x0d, 0xbe, 0x79, 0x9c, 0x6c, 0xa8,
0x26, 0x1e, 0xc0, 0x19, 0xbb, 0x61, 0x9c, 0x84, 0x22, 0x24, 0x8c, 0x79, 0x57, 0x44, 0x1c, 0x46,
0xb4, 0x86, 0x29, 0x38, 0x7b, 0x75, 0x57, 0x59, 0x38, 0xf9, 0xce, 0x45, 0x32, 0xf1, 0x82, 0x08,
0x35, 0xb0, 0x03, 0x5d, 0xc6, 0x03, 0xff, 0x0b, 0xa1, 0xc8, 0xc2, 0x00, 0x1d, 0xc6, 0x3d, 0x3e,
0x65, 0xa8, 0x89, 0x7b, 0xd0, 0x26, 0x61, 0xfc, 0x39, 0x40, 0xad, 0x2a, 0xc6, 0x8f, 0xc3, 0xd0,
0x8b, 0x2e, 0x91, 0x8d, 0xff, 0x87, 0xff, 0x36, 0x40, 0x50, 0xf2, 0x75, 0x4a, 0x18, 0x47, 0xed,
0x8b, 0x1e, 0x74, 0x0b, 0xb9, 0x7e, 0xc8, 0xe5, 0x6c, 0xf8, 0xab, 0x09, 0x6f, 0xbc, 0xa2, 0x78,
0x58, 0xa4, 0x52, 0x2f, 0xf2, 0x2c, 0x54, 0x5a, 0xce, 0xa4, 0x96, 0xdb, 0x9d, 0x3a, 0x83, 0x5e,
0xb9, 0xb8, 0xcb, 0xa4, 0x7e, 0x5c, 0x29, 0xb3, 0x57, 0x7d, 0xba, 0x23, 0xb0, 0xfb, 0xa4, 0x63,
0x36, 0xab, 0x4f, 0xb7, 0x10, 0xb3, 0xbf, 0xc6, 0xdd, 0x32, 0x83, 0x7a, 0xbf, 0xf3, 0xf9, 0xf9,
0x9c, 0xcf, 0x4e, 0x7f, 0xb8, 0x3e, 0x9c, 0x00, 0x82, 0xbe, 0xf1, 0x66, 0x63, 0x25, 0x6a, 0xd4,
0xcd, 0x46, 0xdc, 0xf3, 0xf9, 0x53, 0xb3, 0x16, 0x7e, 0x09, 0xa7, 0x21, 0x09, 0x2f, 0x08, 0x65,
0xd7, 0x41, 0x22, 0xa6, 0xc9, 0xa5, 0xc7, 0x09, 0x6a, 0x56, 0x74, 0xe2, 0x05, 0x54, 0x04, 0x11,
0xe3, 0xde, 0x64, 0xe2, 0xf1, 0x20, 0x8e, 0x50, 0xab, 0xa2, 0xd9, 0x4d, 0xe4, 0x1f, 0xd2, 0xf6,
0x6d, 0xc7, 0x14, 0xfe, 0xe1, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf6, 0xa4, 0x11, 0xfe, 0xc7,
0x03, 0x00, 0x00,
}

View file

@ -4,7 +4,7 @@ import (
"github.com/golang/protobuf/proto"
)
//go:generate protoc --go_out=. ./message.proto
//go:generate protoc --go_out=. ./chat_message.proto ./application_metadata_message.proto ./membership_update_message.proto
func Unmarshal(payload []byte) (*ApplicationMetadataMessage, error) {
var message ApplicationMetadataMessage

View file

@ -2,17 +2,17 @@ package protocol
import "time"
const clockBumpInMs = int64(time.Minute / time.Millisecond)
const clockBumpInMs = uint64(time.Minute / time.Millisecond)
// CalcMessageClock calculates a new clock value for Message.
// It is used to properly sort messages and accommodate the fact
// that time might be different on each device.
func CalcMessageClock(lastObservedValue int64, timeInMs TimestampInMs) int64 {
func CalcMessageClock(lastObservedValue uint64, timeInMs uint64) uint64 {
clock := lastObservedValue
if clock < int64(timeInMs) {
if clock < timeInMs {
// Added time should be larger than time skew tollerance for a message.
// Here, we use 1 minute which is larger than accepted message time skew by Whisper.
clock = int64(timeInMs) + clockBumpInMs
clock = timeInMs + clockBumpInMs
} else {
clock++
}

View file

@ -1,7 +1,6 @@
package protocol
import (
"container/list"
"errors"
"fmt"
"io"
@ -15,14 +14,12 @@ import (
func NewMessageDecoder(r io.Reader) *transit.Decoder {
decoder := transit.NewDecoder(r)
decoder.AddHandler(pairMessageTag, pairMessageHandler)
decoder.AddHandler(membershipUpdateTag, membershipUpdateMessageHandler)
return decoder
}
const (
messageTag = "c4"
pairMessageTag = "p2"
membershipUpdateTag = "g5"
messageTag = "c4"
pairMessageTag = "p2"
)
func pairMessageHandler(d transit.Decoder, value interface{}) (interface{}, error) {
@ -60,83 +57,6 @@ func pairMessageHandler(d transit.Decoder, value interface{}) (interface{}, erro
return pm, nil
}
func membershipUpdateMessageHandler(d transit.Decoder, value interface{}) (interface{}, error) {
taggedValue, ok := value.(transit.TaggedValue)
if !ok {
return nil, errors.New("not a tagged value")
}
values, ok := taggedValue.Value.([]interface{})
if !ok {
return nil, errors.New("tagged value does not contain values")
}
m := MembershipUpdateMessage{}
for idx, v := range values {
var ok bool
switch idx {
case 0:
m.ChatID, ok = v.(string)
case 1:
var updates *list.List
updates, ok = v.(*list.List)
if !ok {
break
}
for e := updates.Front(); e != nil; e = e.Next() {
var value map[interface{}]interface{}
value, ok = e.Value.(map[interface{}]interface{})
if !ok {
break
}
update := MembershipUpdate{}
update.ChatID, ok = value[transit.Keyword("chat-id")].(string)
if !ok {
break
}
update.Signature, ok = value[transit.Keyword("signature")].(string)
if !ok {
break
}
// parse events
var events []interface{}
events, ok = value[transit.Keyword("events")].([]interface{})
if !ok {
break
}
for _, item := range events {
var event map[interface{}]interface{}
event, ok = item.(map[interface{}]interface{})
if !ok {
break
}
var updateEvent MembershipUpdateEvent
updateEvent, ok = parseEvent(event)
if !ok {
break
}
update.Events = append(update.Events, updateEvent)
}
m.Updates = append(m.Updates, update)
}
default:
// skip any other values
ok = true
}
if !ok {
return nil, fmt.Errorf("invalid value for index: %d", idx)
}
}
return m, nil
}
func setToString(set *transit.Set) ([]string, bool) {
result := make([]string, 0, len(set.Contents))
for _, item := range set.Contents {
@ -148,43 +68,3 @@ func setToString(set *transit.Set) ([]string, bool) {
}
return result, true
}
func parseEvent(event map[interface{}]interface{}) (result MembershipUpdateEvent, ok bool) {
// Type is required
result.Type, ok = event[transit.Keyword("type")].(string)
if !ok {
return
}
// ClockValue is required
result.ClockValue, ok = event[transit.Keyword("clock-value")].(int64)
if !ok {
return
}
// Name is optional
if val, exists := event[transit.Keyword("name")]; exists {
result.Name, ok = val.(string)
if !ok {
return
}
}
// Member is optional
if val, exists := event[transit.Keyword("member")]; exists {
result.Member, ok = val.(string)
if !ok {
return
}
}
// Members is optional
if val, exists := event[transit.Keyword("members")]; exists {
var members *transit.Set
members, ok = val.(*transit.Set)
if !ok {
return
}
result.Members, ok = setToString(members)
if !ok {
return
}
}
return
}

View file

@ -1,7 +1,6 @@
package protocol
import (
"container/list"
"errors"
"io"
"reflect"
@ -10,8 +9,7 @@ import (
)
var (
pairMessageType = reflect.TypeOf(PairMessage{})
membershipUpdateType = reflect.TypeOf(MembershipUpdateMessage{})
pairMessageType = reflect.TypeOf(PairMessage{})
defaultMessageValueEncoder = &messageValueEncoder{}
)
@ -22,7 +20,6 @@ var (
func NewMessageEncoder(w io.Writer) *transit.Encoder {
encoder := transit.NewEncoder(w, false)
encoder.AddHandler(pairMessageType, defaultMessageValueEncoder)
encoder.AddHandler(membershipUpdateType, defaultMessageValueEncoder)
return encoder
}
@ -45,47 +42,6 @@ func (messageValueEncoder) Encode(e transit.Encoder, value reflect.Value, asStri
},
}
return e.EncodeInterface(taggedValue, false)
case MembershipUpdateMessage:
updatesList := list.New()
for _, update := range message.Updates {
var events []interface{}
for _, event := range update.Events {
eventMap := map[interface{}]interface{}{
transit.Keyword("type"): event.Type,
transit.Keyword("clock-value"): event.ClockValue,
}
if event.Name != "" {
eventMap[transit.Keyword("name")] = event.Name
}
if event.Member != "" {
eventMap[transit.Keyword("member")] = event.Member
}
if len(event.Members) > 0 {
members := make([]interface{}, len(event.Members))
for idx, m := range event.Members {
members[idx] = m
}
eventMap[transit.Keyword("members")] = transit.NewSet(members)
}
events = append(events, eventMap)
}
element := map[interface{}]interface{}{
transit.Keyword("chat-id"): update.ChatID,
transit.Keyword("events"): events,
transit.Keyword("signature"): update.Signature,
}
updatesList.PushBack(element)
}
value := []interface{}{
message.ChatID,
updatesList,
}
taggedValue := transit.TaggedValue{
Tag: membershipUpdateTag,
Value: value,
}
return e.EncodeInterface(taggedValue, false)
}
return errors.New("unknown message type to encode")

View file

@ -3,145 +3,147 @@ package protocol
import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"sort"
"strings"
"time"
"github.com/golang/protobuf/proto"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
const (
MembershipUpdateChatCreated = "chat-created"
MembershipUpdateNameChanged = "name-changed"
MembershipUpdateMembersAdded = "members-added"
MembershipUpdateMemberJoined = "member-joined"
MembershipUpdateMemberRemoved = "member-removed"
MembershipUpdateAdminsAdded = "admins-added"
MembershipUpdateAdminRemoved = "admin-removed"
"github.com/status-im/status-go/protocol/protobuf"
)
// MembershipUpdateMessage is a message used to propagate information
// about group membership changes.
// For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
type MembershipUpdateMessage struct {
ChatID string `json:"chatId"` // UUID concatenated with hex-encoded public key of the creator for the chat
Updates []MembershipUpdate `json:"updates"`
ChatID string `json:"chatId"` // UUID concatenated with hex-encoded public key of the creator for the chat
Events []MembershipUpdateEvent `json:"events"`
Message *protobuf.ChatMessage `json:"-"`
}
// Verify makes sure that the received update message has a valid signature.
// It also extracts public key from the signature available as From field.
// It does not verify the updates and their events. This should be done
// separately using Group struct.
func (m *MembershipUpdateMessage) Verify() error {
for idx, update := range m.Updates {
if err := update.extractFrom(); err != nil {
return errors.Wrapf(err, "failed to extract an author of %d update", idx)
}
m.Updates[idx] = update
const signatureLength = 65
func MembershipUpdateEventFromProtobuf(chatID string, raw []byte) (*MembershipUpdateEvent, error) {
if len(raw) <= signatureLength {
return nil, errors.New("invalid payload length")
}
return nil
}
decodedEvent := protobuf.MembershipUpdateEvent{}
signature := raw[:signatureLength]
encodedEvent := raw[signatureLength:]
// EncodeMembershipUpdateMessage encodes a MembershipUpdateMessage using Transit serialization.
func EncodeMembershipUpdateMessage(value MembershipUpdateMessage) ([]byte, error) {
var buf bytes.Buffer
encoder := NewMessageEncoder(&buf)
if err := encoder.Encode(value); err != nil {
signatureMaterial := append([]byte(chatID), encodedEvent...)
publicKey, err := crypto.ExtractSignature(signatureMaterial, signature)
if err != nil {
return nil, errors.Wrap(err, "failed to extract signature")
}
from := types.EncodeHex(crypto.FromECDSAPub(publicKey))
err = proto.Unmarshal(encodedEvent, &decodedEvent)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
return &MembershipUpdateEvent{
ClockValue: decodedEvent.Clock,
ChatID: chatID,
Members: decodedEvent.Members,
Name: decodedEvent.Name,
Type: decodedEvent.Type,
Signature: signature,
RawPayload: encodedEvent,
From: from,
}, nil
}
type MembershipUpdate struct {
ChatID string `json:"chatId"`
Signature string `json:"signature"` // hex-encoded without 0x prefix
Events []MembershipUpdateEvent `json:"events"`
From string `json:"from"` // hex-encoded with 0x prefix
func (m *MembershipUpdateMessage) ToProtobuf() *protobuf.MembershipUpdateMessage {
var rawEvents [][]byte
for _, e := range m.Events {
var encodedEvent []byte
encodedEvent = append(encodedEvent, e.Signature...)
encodedEvent = append(encodedEvent, e.RawPayload...)
rawEvents = append(rawEvents, encodedEvent)
}
return &protobuf.MembershipUpdateMessage{
ChatId: m.ChatID,
Events: rawEvents,
Message: m.Message,
}
}
// Sign creates a signature from MembershipUpdateEvents
// and updates MembershipUpdate's signature.
// It follows the algorithm describe in the spec:
// https://github.com/status-im/specs/blob/master/status-group-chats-spec.md#signature.
func (u *MembershipUpdate) Sign(identity *ecdsa.PrivateKey) error {
signature, err := createMembershipUpdateSignature(u.ChatID, u.Events, identity)
if err != nil {
return err
func MembershipUpdateMessageFromProtobuf(raw *protobuf.MembershipUpdateMessage) (*MembershipUpdateMessage, error) {
var events []MembershipUpdateEvent
for _, e := range raw.Events {
verifiedEvent, err := MembershipUpdateEventFromProtobuf(raw.ChatId, e)
if err != nil {
return nil, err
}
events = append(events, *verifiedEvent)
}
u.Signature = signature
return nil
return &MembershipUpdateMessage{
ChatID: raw.ChatId,
Events: events,
Message: raw.Message,
}, nil
}
func (u *MembershipUpdate) extractFrom() error {
content, err := stringifyMembershipUpdateEvents(u.ChatID, u.Events)
if err != nil {
return errors.Wrap(err, "failed to stringify events")
}
signatureBytes, err := hex.DecodeString(u.Signature)
if err != nil {
return errors.Wrap(err, "failed to decode signature")
}
publicKey, err := crypto.ExtractSignature(content, signatureBytes)
if err != nil {
return errors.Wrap(err, "failed to extract signature")
}
u.From = types.EncodeHex(crypto.FromECDSAPub(publicKey))
return nil
}
func (u *MembershipUpdate) Flat() []MembershipUpdateFlat {
result := make([]MembershipUpdateFlat, 0, len(u.Events))
for _, event := range u.Events {
result = append(result, MembershipUpdateFlat{
MembershipUpdateEvent: event,
ChatID: u.ChatID,
Signature: u.Signature,
From: u.From,
})
}
return result
// EncodeMembershipUpdateMessage encodes a MembershipUpdateMessage using protobuf serialization.
func EncodeMembershipUpdateMessage(value MembershipUpdateMessage) ([]byte, error) {
return proto.Marshal(value.ToProtobuf())
}
// MembershipUpdateEvent contains an event information.
// Member and Members are hex-encoded values with 0x prefix.
type MembershipUpdateEvent struct {
Type string `json:"type"`
ClockValue int64 `json:"clockValue"`
Member string `json:"member,omitempty"` // in "member-joined", "member-removed" and "admin-removed" events
Members []string `json:"members,omitempty"` // in "members-added" and "admins-added" events
Name string `json:"name,omitempty"` // name of the group chat
Type protobuf.MembershipUpdateEvent_EventType `json:"type"`
ClockValue uint64 `json:"clockValue"`
Members []string `json:"members,omitempty"` // in "members-added" and "admins-added" events
Name string `json:"name,omitempty"` // name of the group chat
From string
Signature []byte
ChatID string
RawPayload []byte
}
func (u MembershipUpdateEvent) Equal(update MembershipUpdateEvent) bool {
return u.Type == update.Type &&
u.ClockValue == update.ClockValue &&
u.Member == update.Member &&
stringSliceEquals(u.Members, update.Members) &&
u.Name == update.Name
func (u *MembershipUpdateEvent) Equal(update MembershipUpdateEvent) bool {
return bytes.Compare(u.Signature, update.Signature) == 0
}
type MembershipUpdateFlat struct {
MembershipUpdateEvent
ChatID string `json:"chatId"`
Signature string `json:"signature"`
From string `json:"from"`
func (u *MembershipUpdateEvent) Sign(key *ecdsa.PrivateKey) error {
if len(u.ChatID) == 0 {
return errors.New("can't sign with empty chatID")
}
encodedEvent, err := proto.Marshal(u.ToProtobuf())
if err != nil {
return err
}
u.RawPayload = encodedEvent
var signatureMaterial []byte
signatureMaterial = append(signatureMaterial, []byte(u.ChatID)...)
signatureMaterial = crypto.Keccak256(append(signatureMaterial, u.RawPayload...))
signature, err := crypto.Sign(signatureMaterial, key)
if err != nil {
return err
}
u.Signature = signature
u.From = types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey))
return nil
}
func (u MembershipUpdateFlat) Equal(update MembershipUpdateFlat) bool {
return u.ChatID == update.ChatID &&
u.Signature == update.Signature &&
u.From == update.From &&
u.MembershipUpdateEvent.Equal(update.MembershipUpdateEvent)
func (u *MembershipUpdateEvent) ToProtobuf() *protobuf.MembershipUpdateEvent {
return &protobuf.MembershipUpdateEvent{
Clock: u.ClockValue,
Name: u.Name,
Members: u.Members,
Type: u.Type,
}
}
func MergeFlatMembershipUpdates(dest []MembershipUpdateFlat, src []MembershipUpdateFlat) []MembershipUpdateFlat {
func MergeMembershipUpdateEvents(dest []MembershipUpdateEvent, src []MembershipUpdateEvent) []MembershipUpdateEvent {
for _, update := range src {
var exists bool
for _, existing := range dest {
@ -157,166 +159,101 @@ func MergeFlatMembershipUpdates(dest []MembershipUpdateFlat, src []MembershipUpd
return dest
}
func NewChatCreatedEvent(name string, admin string, clock int64) MembershipUpdateEvent {
func NewChatCreatedEvent(name string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateChatCreated,
Name: name,
Member: admin,
ClockValue: clock,
}
}
func NewNameChangedEvent(name string, clock int64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateNameChanged,
Type: protobuf.MembershipUpdateEvent_CHAT_CREATED,
Name: name,
ClockValue: clock,
}
}
func NewMembersAddedEvent(members []string, clock int64) MembershipUpdateEvent {
func NewNameChangedEvent(name string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateMembersAdded,
Type: protobuf.MembershipUpdateEvent_NAME_CHANGED,
Name: name,
ClockValue: clock,
}
}
func NewMembersAddedEvent(members []string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: protobuf.MembershipUpdateEvent_MEMBERS_ADDED,
Members: members,
ClockValue: clock,
}
}
func NewMemberJoinedEvent(member string, clock int64) MembershipUpdateEvent {
func NewMemberJoinedEvent(clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateMemberJoined,
Member: member,
Type: protobuf.MembershipUpdateEvent_MEMBER_JOINED,
ClockValue: clock,
}
}
func NewAdminsAddedEvent(admins []string, clock int64) MembershipUpdateEvent {
func NewAdminsAddedEvent(admins []string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateAdminsAdded,
Type: protobuf.MembershipUpdateEvent_ADMINS_ADDED,
Members: admins,
ClockValue: clock,
}
}
func NewMemberRemovedEvent(member string, clock int64) MembershipUpdateEvent {
func NewMemberRemovedEvent(member string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateMemberRemoved,
Member: member,
Type: protobuf.MembershipUpdateEvent_MEMBER_REMOVED,
Members: []string{member},
ClockValue: clock,
}
}
func NewAdminRemovedEvent(admin string, clock int64) MembershipUpdateEvent {
func NewAdminRemovedEvent(admin string, clock uint64) MembershipUpdateEvent {
return MembershipUpdateEvent{
Type: MembershipUpdateAdminRemoved,
Member: admin,
Type: protobuf.MembershipUpdateEvent_ADMIN_REMOVED,
Members: []string{admin},
ClockValue: clock,
}
}
func stringifyMembershipUpdateEvents(chatID string, events []MembershipUpdateEvent) ([]byte, error) {
sort.Slice(events, func(i, j int) bool {
return events[i].ClockValue < events[j].ClockValue
})
tuples := make([]interface{}, len(events))
for idx, event := range events {
tuples[idx] = tupleMembershipUpdateEvent(event)
}
structureToSign := []interface{}{
tuples,
chatID,
}
return json.Marshal(structureToSign)
}
func createMembershipUpdateSignature(chatID string, events []MembershipUpdateEvent, identity *ecdsa.PrivateKey) (string, error) {
data, err := stringifyMembershipUpdateEvents(chatID, events)
if err != nil {
return "", err
}
return crypto.SignBytesAsHex(data, identity)
}
var membershipUpdateEventFieldNamesCompat = map[string]string{
"ClockValue": "clock-value",
"Name": "name",
"Type": "type",
"Member": "member",
"Members": "members",
}
func tupleMembershipUpdateEvent(update MembershipUpdateEvent) [][]interface{} {
// Sort all slices first.
sort.Slice(update.Members, func(i, j int) bool {
return update.Members[i] < update.Members[j]
})
v := reflect.ValueOf(update)
result := make([][]interface{}, 0, v.NumField())
for i := 0; i < v.NumField(); i++ {
fieldName := v.Type().Field(i).Name
if name, exists := membershipUpdateEventFieldNamesCompat[fieldName]; exists {
fieldName = name
}
field := v.Field(i)
if !isZeroValue(field) {
result = append(result, []interface{}{fieldName, field.Interface()})
}
}
// Sort the result lexicographically.
// We know that the first item of a tuple is a string
// because it's a field name.
sort.Slice(result, func(i, j int) bool {
return result[i][0].(string) < result[j][0].(string)
})
return result
}
type Group struct {
chatID string
name string
updates []MembershipUpdateFlat
events []MembershipUpdateEvent
admins *stringSet
members *stringSet
joined *stringSet
}
func groupChatID(creator *ecdsa.PublicKey) string {
return uuid.New().String() + "-" + types.EncodeHex(crypto.FromECDSAPub(creator))
}
func NewGroupWithMembershipUpdates(chatID string, updates []MembershipUpdate) (*Group, error) {
flatten := make([]MembershipUpdateFlat, 0, len(updates))
for _, update := range updates {
flatten = append(flatten, update.Flat()...)
}
return newGroup(chatID, flatten)
func NewGroupWithEvents(chatID string, events []MembershipUpdateEvent) (*Group, error) {
return newGroup(chatID, events)
}
func NewGroupWithCreator(name string, creator *ecdsa.PrivateKey) (*Group, error) {
chatID := groupChatID(&creator.PublicKey)
creatorHex := publicKeyToString(&creator.PublicKey)
clock := TimestampInMsFromTime(time.Now())
chatCreated := NewChatCreatedEvent(name, creatorHex, int64(clock))
update := MembershipUpdate{
ChatID: chatID,
From: creatorHex,
Events: []MembershipUpdateEvent{chatCreated},
}
if err := update.Sign(creator); err != nil {
chatCreated := NewChatCreatedEvent(name, clock)
chatCreated.ChatID = chatID
err := chatCreated.Sign(creator)
if err != nil {
return nil, err
}
return newGroup(chatID, update.Flat())
return newGroup(chatID, []MembershipUpdateEvent{chatCreated})
}
func NewGroup(chatID string, updates []MembershipUpdateFlat) (*Group, error) {
return newGroup(chatID, updates)
func NewGroup(chatID string, events []MembershipUpdateEvent) (*Group, error) {
return newGroup(chatID, events)
}
func newGroup(chatID string, updates []MembershipUpdateFlat) (*Group, error) {
func newGroup(chatID string, events []MembershipUpdateEvent) (*Group, error) {
g := Group{
chatID: chatID,
updates: updates,
events: events,
admins: newStringSet(),
members: newStringSet(),
joined: newStringSet(),
}
if err := g.init(); err != nil {
return nil, err
@ -329,17 +266,17 @@ func (g *Group) init() error {
var chatID string
for _, update := range g.updates {
for _, event := range g.events {
if chatID == "" {
chatID = update.ChatID
} else if update.ChatID != chatID {
chatID = event.ChatID
} else if event.ChatID != chatID {
return errors.New("updates contain different chat IDs")
}
valid := g.validateEvent(update.From, update.MembershipUpdateEvent)
valid := g.validateEvent(event)
if !valid {
return fmt.Errorf("invalid event %#+v from %s", update.MembershipUpdateEvent, update.From)
return fmt.Errorf("invalid event %#+v from %s", event, event.From)
}
g.processEvent(update.From, update.MembershipUpdateEvent)
g.processEvent(event)
}
valid := g.validateChatID(g.chatID)
@ -357,8 +294,8 @@ func (g Group) ChatID() string {
return g.chatID
}
func (g Group) Updates() []MembershipUpdateFlat {
return g.updates
func (g Group) Events() []MembershipUpdateEvent {
return g.events
}
func (g Group) Name() string {
@ -374,18 +311,12 @@ func (g Group) Admins() []string {
}
func (g Group) Joined() []string {
var result []string
for _, update := range g.updates {
if update.Type == MembershipUpdateMemberJoined {
result = append(result, update.Member)
}
}
return result
return g.joined.List()
}
func (g *Group) ProcessEvents(from *ecdsa.PublicKey, events []MembershipUpdateEvent) error {
func (g *Group) ProcessEvents(events []MembershipUpdateEvent) error {
for _, event := range events {
err := g.ProcessEvent(from, event)
err := g.ProcessEvent(event)
if err != nil {
return err
}
@ -393,38 +324,33 @@ func (g *Group) ProcessEvents(from *ecdsa.PublicKey, events []MembershipUpdateEv
return nil
}
func (g *Group) ProcessEvent(from *ecdsa.PublicKey, event MembershipUpdateEvent) error {
fromHex := types.EncodeHex(crypto.FromECDSAPub(from))
if !g.validateEvent(fromHex, event) {
return fmt.Errorf("invalid event %#+v from %s", event, from)
func (g *Group) ProcessEvent(event MembershipUpdateEvent) error {
if !g.validateEvent(event) {
return fmt.Errorf("invalid event %#+v", event)
}
update := MembershipUpdate{
ChatID: g.chatID,
From: fromHex,
Events: []MembershipUpdateEvent{event},
}
g.updates = append(g.updates, update.Flat()...)
g.processEvent(fromHex, event)
// Check if exists
g.events = append(g.events, event)
g.processEvent(event)
return nil
}
func (g Group) LastClockValue() int64 {
if len(g.updates) == 0 {
func (g Group) LastClockValue() uint64 {
if len(g.events) == 0 {
return 0
}
return g.updates[len(g.updates)-1].ClockValue
return g.events[len(g.events)-1].ClockValue
}
func (g Group) NextClockValue() int64 {
func (g Group) NextClockValue() uint64 {
return g.LastClockValue() + 1
}
func (g Group) creator() (string, error) {
if len(g.updates) == 0 {
if len(g.events) == 0 {
return "", errors.New("no events in the group")
}
first := g.updates[0]
if first.Type != MembershipUpdateChatCreated {
first := g.events[0]
if first.Type != protobuf.MembershipUpdateEvent_CHAT_CREATED {
return "", fmt.Errorf("expected first event to be 'chat-created', got %s", first.Type)
}
return first.From, nil
@ -440,53 +366,63 @@ func (g Group) validateChatID(chatID string) bool {
return strings.HasSuffix(chatID, creator) && chatID != creator
}
func (g Group) IsMember(id string) bool {
return g.members.Has(id)
}
// validateEvent returns true if a given event is valid.
func (g Group) validateEvent(from string, event MembershipUpdateEvent) bool {
func (g Group) validateEvent(event MembershipUpdateEvent) bool {
if len(event.From) == 0 {
return false
}
switch event.Type {
case MembershipUpdateChatCreated:
case protobuf.MembershipUpdateEvent_CHAT_CREATED:
return g.admins.Empty() && g.members.Empty()
case MembershipUpdateNameChanged:
return g.admins.Has(from) && len(event.Name) > 0
case MembershipUpdateMembersAdded:
return g.admins.Has(from)
case MembershipUpdateMemberJoined:
return g.members.Has(from) && from == event.Member
case MembershipUpdateMemberRemoved:
case protobuf.MembershipUpdateEvent_NAME_CHANGED:
return g.admins.Has(event.From) && len(event.Name) > 0
case protobuf.MembershipUpdateEvent_MEMBERS_ADDED:
return g.admins.Has(event.From)
case protobuf.MembershipUpdateEvent_MEMBER_JOINED:
return g.members.Has(event.From)
case protobuf.MembershipUpdateEvent_MEMBER_REMOVED:
// Member can remove themselves or admin can remove a member.
return from == event.Member || (g.admins.Has(from) && !g.admins.Has(event.Member))
case MembershipUpdateAdminsAdded:
return g.admins.Has(from) && stringSliceSubset(event.Members, g.members.List())
case MembershipUpdateAdminRemoved:
return g.admins.Has(from) && from == event.Member
return len(event.Members) == 1 && (event.From == event.Members[0] || (g.admins.Has(event.From) && !g.admins.Has(event.Members[0])))
case protobuf.MembershipUpdateEvent_ADMINS_ADDED:
return g.admins.Has(event.From) && stringSliceSubset(event.Members, g.members.List())
case protobuf.MembershipUpdateEvent_ADMIN_REMOVED:
return len(event.Members) == 1 && g.admins.Has(event.From) && event.From == event.Members[0]
default:
return false
}
}
func (g *Group) processEvent(from string, event MembershipUpdateEvent) {
func (g *Group) processEvent(event MembershipUpdateEvent) {
switch event.Type {
case MembershipUpdateChatCreated:
case protobuf.MembershipUpdateEvent_CHAT_CREATED:
g.name = event.Name
g.members.Add(event.Member)
g.admins.Add(event.Member)
case MembershipUpdateNameChanged:
g.members.Add(event.From)
g.joined.Add(event.From)
g.admins.Add(event.From)
case protobuf.MembershipUpdateEvent_NAME_CHANGED:
g.name = event.Name
case MembershipUpdateAdminsAdded:
case protobuf.MembershipUpdateEvent_ADMINS_ADDED:
g.admins.Add(event.Members...)
case MembershipUpdateAdminRemoved:
g.admins.Remove(event.Member)
case MembershipUpdateMembersAdded:
case protobuf.MembershipUpdateEvent_ADMIN_REMOVED:
g.admins.Remove(event.Members[0])
case protobuf.MembershipUpdateEvent_MEMBERS_ADDED:
g.members.Add(event.Members...)
case MembershipUpdateMemberRemoved:
g.members.Remove(event.Member)
case MembershipUpdateMemberJoined:
g.members.Add(event.Member)
case protobuf.MembershipUpdateEvent_MEMBER_REMOVED:
g.admins.Remove(event.Members[0])
g.joined.Remove(event.Members[0])
g.members.Remove(event.Members[0])
case protobuf.MembershipUpdateEvent_MEMBER_JOINED:
g.joined.Add(event.From)
}
}
func (g *Group) sortEvents() {
sort.Slice(g.updates, func(i, j int) bool {
return g.updates[i].ClockValue < g.updates[j].ClockValue
sort.Slice(g.events, func(i, j int) bool {
return g.events[i].ClockValue < g.events[j].ClockValue
})
}

View file

@ -17,34 +17,11 @@ var (
ErrInvalidDecodedValue = errors.New("invalid decoded value type")
)
// TimestampInMs is a timestamp in milliseconds.
type TimestampInMs int64
// Time returns a time.Time instance.
func (t TimestampInMs) Time() time.Time {
ts := int64(t)
seconds := ts / 1000
return time.Unix(seconds, (ts%1000)*int64(time.Millisecond))
}
// TimestampInMsFromTime returns a TimestampInMs from a time.Time instance.
func TimestampInMsFromTime(t time.Time) TimestampInMs {
return TimestampInMs(t.UnixNano() / int64(time.Millisecond))
func TimestampInMsFromTime(t time.Time) uint64 {
return uint64(t.UnixNano() / int64(time.Millisecond))
}
// Flags define various boolean properties of a message.
type Flags uint64
func (f *Flags) Set(val Flags) { *f = *f | val }
func (f *Flags) Clear(val Flags) { *f = *f &^ val }
func (f *Flags) Toggle(val Flags) { *f = *f ^ val }
func (f Flags) Has(val Flags) bool { return f&val != 0 }
// A list of Message flags. By default, a message is unread.
const (
MessageRead Flags = 1 << iota
)
// MessageID calculates the messageID from author's compressed public key
// and not encrypted but encoded payload.
func MessageID(author *ecdsa.PublicKey, data []byte) types.HexBytes {
@ -53,7 +30,7 @@ func MessageID(author *ecdsa.PublicKey, data []byte) types.HexBytes {
}
// WrapMessageV1 wraps a payload into a protobuf message and signs it if an identity is provided
func WrapMessageV1(payload []byte, identity *ecdsa.PrivateKey) ([]byte, error) {
func WrapMessageV1(payload []byte, messageType protobuf.ApplicationMetadataMessage_Type, identity *ecdsa.PrivateKey) ([]byte, error) {
var signature []byte
if identity != nil {
var err error
@ -65,6 +42,7 @@ func WrapMessageV1(payload []byte, identity *ecdsa.PrivateKey) ([]byte, error) {
message := &protobuf.ApplicationMetadataMessage{
Signature: signature,
Type: messageType,
Payload: payload,
}
return proto.Marshal(message)

View file

@ -17,18 +17,12 @@ import (
type StatusMessageT int
const (
MessageT StatusMessageT = iota + 1
MembershipUpdateMessageT
PairMessageT
)
// StatusMessage is any Status Protocol message.
type StatusMessage struct {
// TransportMessage is the parsed message received from the transport layer, i.e the input
TransportMessage *types.Message `json:"transportMessage"`
// MessageType is the type of application message contained
MessageType StatusMessageT `json:"-"`
// Type is the type of application message contained
Type protobuf.ApplicationMetadataMessage_Type `json:"-"`
// ParsedMessage is the parsed message by the application layer, i.e the output
ParsedMessage interface{} `json:"-"`
@ -157,23 +151,37 @@ func (m *StatusMessage) HandleApplicationMetadata() error {
// Calculate ID using the wrapped record
m.ID = MessageID(recoveredKey, m.DecryptedPayload)
m.DecryptedPayload = message.Payload
m.Type = message.Type
return nil
}
func (m *StatusMessage) HandleApplication() error {
// Try protobuf first
var message protobuf.ChatMessage
switch m.Type {
case protobuf.ApplicationMetadataMessage_CHAT_MESSAGE:
var message protobuf.ChatMessage
err := proto.Unmarshal(m.DecryptedPayload, &message)
if err != nil {
m.ParsedMessage = nil
log.Printf("[message::DecodeMessage] could not decode protobuf message: %#x, err: %v", m.Hash, err.Error())
} else {
m.MessageType = MessageT
m.ParsedMessage = message
err := proto.Unmarshal(m.DecryptedPayload, &message)
if err != nil {
m.ParsedMessage = nil
log.Printf("[message::DecodeMessage] could not decode ChatMessage: %#x, err: %v", m.Hash, err.Error())
} else {
m.ParsedMessage = message
return nil
return nil
}
case protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE:
var message protobuf.MembershipUpdateMessage
err := proto.Unmarshal(m.DecryptedPayload, &message)
if err != nil {
m.ParsedMessage = nil
log.Printf("[message::DecodeMessage] could not decode MembershipUpdateMessage: %#x, err: %v", m.Hash, err.Error())
} else {
m.ParsedMessage = message
return nil
}
}
return nil
}

159
vendor/golang.org/x/crypto/blowfish/block.go generated vendored Normal file
View file

@ -0,0 +1,159 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package blowfish
// getNextWord returns the next big-endian uint32 value from the byte slice
// at the given position in a circular manner, updating the position.
func getNextWord(b []byte, pos *int) uint32 {
var w uint32
j := *pos
for i := 0; i < 4; i++ {
w = w<<8 | uint32(b[j])
j++
if j >= len(b) {
j = 0
}
}
*pos = j
return w
}
// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
// pi and substitution tables for calls to Encrypt. This is used, primarily,
// by the bcrypt package to reuse the Blowfish key schedule during its
// set up. It's unlikely that you need to use this directly.
func ExpandKey(key []byte, c *Cipher) {
j := 0
for i := 0; i < 18; i++ {
// Using inlined getNextWord for performance.
var d uint32
for k := 0; k < 4; k++ {
d = d<<8 | uint32(key[j])
j++
if j >= len(key) {
j = 0
}
}
c.p[i] ^= d
}
var l, r uint32
for i := 0; i < 18; i += 2 {
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
}
}
// This is similar to ExpandKey, but folds the salt during the key
// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
// and specializing it here is useful.
func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
j := 0
for i := 0; i < 18; i++ {
c.p[i] ^= getNextWord(key, &j)
}
j = 0
var l, r uint32
for i := 0; i < 18; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
}
}
func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[0]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
xr ^= c.p[17]
return xr, xl
}
func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[17]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
xr ^= c.p[0]
return xr, xl
}

99
vendor/golang.org/x/crypto/blowfish/cipher.go generated vendored Normal file
View file

@ -0,0 +1,99 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
//
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package blowfish // import "golang.org/x/crypto/blowfish"
// The code is a port of Bruce Schneier's C implementation.
// See https://www.schneier.com/blowfish.html.
import "strconv"
// The Blowfish block size in bytes.
const BlockSize = 8
// A Cipher is an instance of Blowfish encryption using a particular key.
type Cipher struct {
p [18]uint32
s0, s1, s2, s3 [256]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a Cipher.
// The key argument should be the Blowfish key, from 1 to 56 bytes.
func NewCipher(key []byte) (*Cipher, error) {
var result Cipher
if k := len(key); k < 1 || k > 56 {
return nil, KeySizeError(k)
}
initCipher(&result)
ExpandKey(key, &result)
return &result, nil
}
// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
// sufficient and desirable. For bcrypt compatibility, the key can be over 56
// bytes.
func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
if len(salt) == 0 {
return NewCipher(key)
}
var result Cipher
if k := len(key); k < 1 {
return nil, KeySizeError(k)
}
initCipher(&result)
expandKeyWithSalt(key, salt, &result)
return &result, nil
}
// BlockSize returns the Blowfish block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8-byte buffer src using the key k
// and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = encryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
// Decrypt decrypts the 8-byte buffer src using the key k
// and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = decryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
func initCipher(c *Cipher) {
copy(c.p[0:], p[0:])
copy(c.s0[0:], s0[0:])
copy(c.s1[0:], s1[0:])
copy(c.s2[0:], s2[0:])
copy(c.s3[0:], s3[0:])
}

199
vendor/golang.org/x/crypto/blowfish/const.go generated vendored Normal file
View file

@ -0,0 +1,199 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The startup permutation array and substitution boxes.
// They are the hexadecimal digits of PI; see:
// https://www.schneier.com/code/constants.txt.
package blowfish
var s0 = [256]uint32{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
}
var s1 = [256]uint32{
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
}
var s2 = [256]uint32{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
}
var s3 = [256]uint32{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
}
var p = [18]uint32{
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
}

22
vendor/modules.txt vendored
View file

@ -28,7 +28,7 @@ github.com/davecgh/go-spew/spew
github.com/deckarep/golang-set
# github.com/edsrzf/mmap-go v1.0.0
github.com/edsrzf/mmap-go
# github.com/elastic/gosigar v0.10.5
# github.com/elastic/gosigar v0.10.4
github.com/elastic/gosigar
github.com/elastic/gosigar/sys/windows
# github.com/ethereum/go-ethereum v1.9.5 => github.com/status-im/go-ethereum v1.9.5-status.7
@ -109,7 +109,7 @@ github.com/ethereum/go-ethereum/trie
# github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a
github.com/fjl/memsize
github.com/fjl/memsize/memsizeui
# github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08
# github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/gballet/go-libpcsclite
# github.com/go-playground/locales v0.13.0
github.com/go-playground/locales
@ -121,7 +121,7 @@ github.com/go-stack/stack
# github.com/gogo/protobuf v1.3.0
github.com/gogo/protobuf/io
github.com/gogo/protobuf/proto
# github.com/golang-migrate/migrate/v4 v4.7.0
# github.com/golang-migrate/migrate/v4 v4.6.2
github.com/golang-migrate/migrate/v4
github.com/golang-migrate/migrate/v4/database
github.com/golang-migrate/migrate/v4/internal/url
@ -133,7 +133,7 @@ github.com/golang/protobuf/proto
github.com/golang/protobuf/protoc-gen-go/descriptor
# github.com/golang/snappy v0.0.1
github.com/golang/snappy
# github.com/gomarkdown/markdown v0.0.0-20191113114344-af599402d015 => github.com/status-im/markdown v0.0.0-20191113114344-af599402d015
# github.com/gomarkdown/markdown v0.0.0-20191209105822-e3ba6c6109ba => github.com/status-im/markdown v0.0.0-20191209105822-e3ba6c6109ba
github.com/gomarkdown/markdown
github.com/gomarkdown/markdown/ast
github.com/gomarkdown/markdown/parser
@ -178,7 +178,7 @@ github.com/jbenet/goprocess/periodic
github.com/jbenet/goprocess/ratelimit
# github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
github.com/jinzhu/copier
# github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9
# github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8
github.com/karalabe/usb
# github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b
github.com/koron/go-ssdp
@ -357,7 +357,7 @@ github.com/spaolacci/murmur3
github.com/status-im/doubleratchet
# github.com/status-im/go-multiaddr-ethv4 v1.2.0
github.com/status-im/go-multiaddr-ethv4
# github.com/status-im/keycard-go v0.0.0-20191119114148-6dd40a46baa0
# github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48
github.com/status-im/keycard-go/derivationpath
# github.com/status-im/migrate/v4 v4.6.2-status.2
github.com/status-im/migrate/v4
@ -369,7 +369,7 @@ github.com/status-im/migrate/v4/source/go_bindata
github.com/status-im/rendezvous
github.com/status-im/rendezvous/protocol
github.com/status-im/rendezvous/server
# github.com/status-im/status-go/eth-node v0.0.0-20191126161717-86bc127b3d0a => ./eth-node
# github.com/status-im/status-go/eth-node v1.0.0 => ./eth-node
github.com/status-im/status-go/eth-node/bridge/geth
github.com/status-im/status-go/eth-node/bridge/geth/ens
github.com/status-im/status-go/eth-node/crypto
@ -378,7 +378,7 @@ github.com/status-im/status-go/eth-node/types
github.com/status-im/status-go/eth-node/types/ens
# github.com/status-im/status-go/extkeys v1.0.0 => ./extkeys
github.com/status-im/status-go/extkeys
# github.com/status-im/status-go/protocol v0.5.2 => ./protocol
# github.com/status-im/status-go/protocol v1.0.1 => ./protocol
github.com/status-im/status-go/protocol
github.com/status-im/status-go/protocol/datasync
github.com/status-im/status-go/protocol/datasync/peer
@ -396,7 +396,7 @@ github.com/status-im/status-go/protocol/transport/whisper
github.com/status-im/status-go/protocol/transport/whisper/migrations
github.com/status-im/status-go/protocol/v1
github.com/status-im/status-go/protocol/zaputil
# github.com/status-im/status-go/whisper/v6 v6.0.0 => ./whisper
# github.com/status-im/status-go/whisper/v6 v6.0.1 => ./whisper
github.com/status-im/status-go/whisper/v6
# github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501
github.com/status-im/tcp-shaker
@ -500,7 +500,7 @@ golang.org/x/crypto/ssh/terminal
# golang.org/x/lint v0.0.0-20190930215403-16217165b5de
golang.org/x/lint
golang.org/x/lint/golint
# golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3
# golang.org/x/net v0.0.0-20190620200207-3b0461eec859
golang.org/x/net/bpf
golang.org/x/net/context
golang.org/x/net/html
@ -510,7 +510,7 @@ golang.org/x/net/idna
golang.org/x/net/internal/iana
golang.org/x/net/internal/socket
golang.org/x/net/ipv4
# golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
# golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sync/syncmap
# golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056
golang.org/x/sys/cpu