Make shhext and protocol work with Waku (#1777)

This change makes shhext and protocol submodule work with Waku and Whisper.
This commit is contained in:
Adam Babik 2020-01-13 20:17:30 +01:00 committed by GitHub
parent 330d177de6
commit 44aa313981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
104 changed files with 4300 additions and 806 deletions

View File

@ -163,7 +163,7 @@ setup-build: lint-install release-install gomobile-install ##@other Prepare proj
setup: setup-build setup-dev tidy ##@other Prepare project for development and building
generate: ##@other Regenerate assets and other auto-generated stuff
go generate ./static ./static/mailserver_db_migrations ./t ./multiaccounts/... ./appdatabase/...
go generate ./static ./static/mailserver_db_migrations ./t ./multiaccounts/... ./appdatabase/...
prepare-release: clean-release
mkdir -p $(RELEASE_DIR)

View File

@ -90,7 +90,7 @@ func _0001_appDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_app.down.sql", size: 387, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "0001_app.down.sql", size: 387, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbc, 0x9c, 0xd2, 0xe1, 0x1d, 0x8, 0x34, 0x6a, 0xc8, 0x37, 0x13, 0xb3, 0x9f, 0x26, 0x23, 0x33, 0xd4, 0x25, 0x8, 0xed, 0x53, 0xe6, 0xd, 0x46, 0xc9, 0xf4, 0x24, 0xf8, 0x1, 0x1f, 0xf5, 0xc8}}
return a, nil
}
@ -110,7 +110,7 @@ func _0001_appUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_app.up.sql", size: 3088, mode: os.FileMode(0644), modTime: time.Unix(1576661249, 0)}
info := bindataFileInfo{name: "0001_app.up.sql", size: 3088, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x93, 0xb8, 0x68, 0x17, 0x49, 0x51, 0xc0, 0xe8, 0xbc, 0x36, 0xa4, 0x29, 0xc9, 0x93, 0x6c, 0x3e, 0xdf, 0x3d, 0x23, 0x22, 0xab, 0x18, 0x49, 0xbd, 0x6, 0xf, 0xc5, 0xec, 0xf8, 0xcf, 0x1b, 0x6a}}
return a, nil
}
@ -130,7 +130,7 @@ func _0002_tokensDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0002_tokens.down.sql", size: 19, mode: os.FileMode(0644), modTime: time.Unix(1576226192, 0)}
info := bindataFileInfo{name: "0002_tokens.down.sql", size: 19, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0x31, 0x2, 0xcc, 0x2f, 0x38, 0x90, 0xf7, 0x58, 0x37, 0x47, 0xf4, 0x18, 0xf7, 0x72, 0x74, 0x67, 0x14, 0x7e, 0xf3, 0xb1, 0xd6, 0x5f, 0xb0, 0xd5, 0xe7, 0x91, 0xf4, 0x26, 0x77, 0x8e, 0x68}}
return a, nil
}
@ -150,7 +150,7 @@ func _0002_tokensUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0002_tokens.up.sql", size: 248, mode: os.FileMode(0644), modTime: time.Unix(1576226192, 0)}
info := bindataFileInfo{name: "0002_tokens.up.sql", size: 248, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xcc, 0xd6, 0xde, 0xd3, 0x7b, 0xee, 0x92, 0x11, 0x38, 0xa4, 0xeb, 0x84, 0xca, 0xcb, 0x37, 0x75, 0x5, 0x77, 0x7f, 0x14, 0x39, 0xee, 0xa1, 0x8b, 0xd4, 0x5c, 0x6e, 0x55, 0x6, 0x50, 0x16, 0xd4}}
return a, nil
}
@ -170,7 +170,7 @@ func _0003_settingsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0003_settings.down.sql", size: 118, mode: os.FileMode(0644), modTime: time.Unix(1578050942, 0)}
info := bindataFileInfo{name: "0003_settings.down.sql", size: 118, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0xa6, 0xf5, 0xc0, 0x60, 0x64, 0x77, 0xe2, 0xe7, 0x3c, 0x9b, 0xb1, 0x52, 0xa9, 0x95, 0x16, 0xf8, 0x60, 0x2f, 0xa5, 0xeb, 0x46, 0xb9, 0xb9, 0x8f, 0x4c, 0xf4, 0xfd, 0xbb, 0xe7, 0xe5, 0xe5}}
return a, nil
}
@ -190,7 +190,7 @@ func _0003_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0003_settings.up.sql", size: 1311, mode: os.FileMode(0644), modTime: time.Unix(1578050942, 0)}
info := bindataFileInfo{name: "0003_settings.up.sql", size: 1311, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x35, 0x0, 0xeb, 0xe2, 0x33, 0x68, 0xb9, 0xf4, 0xf6, 0x8e, 0x9e, 0x10, 0xe9, 0x58, 0x68, 0x28, 0xb, 0xcd, 0xec, 0x74, 0x71, 0xa7, 0x9a, 0x5a, 0x77, 0x59, 0xb1, 0x13, 0x1c, 0xa1, 0x5b}}
return a, nil
}
@ -210,7 +210,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 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

@ -2,11 +2,25 @@ package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
"github.com/status-im/status-go/whisper/v6"
)
// NewGethEnvelopeErrorWrapper returns a types.EnvelopeError object that mimics Geth's EnvelopeError
func NewGethEnvelopeErrorWrapper(envelopeError *whisper.EnvelopeError) *types.EnvelopeError {
// NewWhisperEnvelopeErrorWrapper returns a types.EnvelopeError object that mimics Geth's EnvelopeError
func NewWhisperEnvelopeErrorWrapper(envelopeError *whisper.EnvelopeError) *types.EnvelopeError {
if envelopeError == nil {
panic("envelopeError should not be nil")
}
return &types.EnvelopeError{
Hash: types.Hash(envelopeError.Hash),
Code: mapGethErrorCode(envelopeError.Code),
Description: envelopeError.Description,
}
}
// NewWakuEnvelopeErrorWrapper returns a types.EnvelopeError object that mimics Geth's EnvelopeError
func NewWakuEnvelopeErrorWrapper(envelopeError *waku.EnvelopeError) *types.EnvelopeError {
if envelopeError == nil {
panic("envelopeError should not be nil")
}
@ -21,8 +35,10 @@ func NewGethEnvelopeErrorWrapper(envelopeError *whisper.EnvelopeError) *types.En
func mapGethErrorCode(code uint) uint {
switch code {
case whisper.EnvelopeTimeNotSynced:
case waku.EnvelopeTimeNotSynced:
return types.EnvelopeTimeNotSynced
case whisper.EnvelopeOtherError:
case waku.EnvelopeOtherError:
return types.EnvelopeOtherError
}
return types.EnvelopeOtherError

View File

@ -2,11 +2,12 @@ package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
"github.com/status-im/status-go/whisper/v6"
)
// NewGethEnvelopeEventWrapper returns a types.EnvelopeEvent object that mimics Geth's EnvelopeEvent
func NewGethEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.EnvelopeEvent {
// NewWhisperEnvelopeEventWrapper returns a types.EnvelopeEvent object that mimics Geth's EnvelopeEvent
func NewWhisperEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.EnvelopeEvent {
if envelopeEvent == nil {
panic("envelopeEvent should not be nil")
}
@ -16,10 +17,10 @@ func NewGethEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.En
case []whisper.EnvelopeError:
wrappedData := make([]types.EnvelopeError, len(data))
for index, envError := range data {
wrappedData[index] = *NewGethEnvelopeErrorWrapper(&envError)
wrappedData[index] = *NewWhisperEnvelopeErrorWrapper(&envError)
}
case *whisper.MailServerResponse:
wrappedData = NewGethMailServerResponseWrapper(data)
wrappedData = NewWhisperMailServerResponseWrapper(data)
case whisper.SyncEventResponse:
wrappedData = NewGethSyncEventResponseWrapper(data)
}
@ -31,3 +32,28 @@ func NewGethEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.En
Data: wrappedData,
}
}
// NewWakuEnvelopeEventWrapper returns a types.EnvelopeEvent object that mimics Geth's EnvelopeEvent
func NewWakuEnvelopeEventWrapper(envelopeEvent *waku.EnvelopeEvent) *types.EnvelopeEvent {
if envelopeEvent == nil {
panic("envelopeEvent should not be nil")
}
wrappedData := envelopeEvent.Data
switch data := envelopeEvent.Data.(type) {
case []waku.EnvelopeError:
wrappedData := make([]types.EnvelopeError, len(data))
for index, envError := range data {
wrappedData[index] = *NewWakuEnvelopeErrorWrapper(&envError)
}
case *waku.MailServerResponse:
wrappedData = NewWakuMailServerResponseWrapper(data)
}
return &types.EnvelopeEvent{
Event: types.EventType(envelopeEvent.Event),
Hash: types.Hash(envelopeEvent.Hash),
Batch: types.Hash(envelopeEvent.Batch),
Peer: types.EnodeID(envelopeEvent.Peer),
Data: wrappedData,
}
}

View File

@ -1,33 +0,0 @@
package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/whisper/v6"
)
type gethFilterWrapper struct {
filter *whisper.Filter
id string
}
// NewGethFilterWrapper returns an object that wraps Geth's Filter in a types interface
func NewGethFilterWrapper(f *whisper.Filter, id string) types.Filter {
if f.Messages == nil {
panic("Messages should not be nil")
}
return &gethFilterWrapper{
filter: f,
id: id,
}
}
// GetGethFilterFrom retrieves the underlying whisper Filter struct from a wrapped Filter interface
func GetGethFilterFrom(f types.Filter) *whisper.Filter {
return f.(*gethFilterWrapper).filter
}
// ID returns the filter ID
func (w *gethFilterWrapper) ID() string {
return w.id
}

View File

@ -2,11 +2,25 @@ package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
"github.com/status-im/status-go/whisper/v6"
)
// NewGethMailServerResponseWrapper returns a types.MailServerResponse object that mimics Geth's MailServerResponse
func NewGethMailServerResponseWrapper(mailServerResponse *whisper.MailServerResponse) *types.MailServerResponse {
// NewWhisperMailServerResponseWrapper returns a types.MailServerResponse object that mimics Geth's MailServerResponse
func NewWhisperMailServerResponseWrapper(mailServerResponse *whisper.MailServerResponse) *types.MailServerResponse {
if mailServerResponse == nil {
panic("mailServerResponse should not be nil")
}
return &types.MailServerResponse{
LastEnvelopeHash: types.Hash(mailServerResponse.LastEnvelopeHash),
Cursor: mailServerResponse.Cursor,
Error: mailServerResponse.Error,
}
}
// NewWakuMailServerResponseWrapper returns a types.MailServerResponse object that mimics Geth's MailServerResponse
func NewWakuMailServerResponseWrapper(mailServerResponse *waku.MailServerResponse) *types.MailServerResponse {
if mailServerResponse == nil {
panic("mailServerResponse should not be nil")
}

View File

@ -1,6 +1,9 @@
package gethbridge
import (
"errors"
"github.com/status-im/status-go/waku"
"go.uber.org/zap"
"github.com/ethereum/go-ethereum/node"
@ -41,12 +44,35 @@ func (w *gethNodeWrapper) GetWhisper(ctx interface{}) (types.Whisper, error) {
}
}
if nativeWhisper == nil {
panic("Whisper service is not available")
return nil, errors.New("whisper service is not available")
}
return NewGethWhisperWrapper(nativeWhisper), nil
}
func (w *gethNodeWrapper) GetWaku(ctx interface{}) (types.Waku, error) {
var nativeWaku *waku.Waku
if ctx == nil || ctx == w {
err := w.stack.Service(&nativeWaku)
if err != nil {
return nil, err
}
} else {
switch serviceProvider := ctx.(type) {
case *node.ServiceContext:
err := serviceProvider.Service(&nativeWaku)
if err != nil {
return nil, err
}
}
}
if nativeWaku == nil {
return nil, errors.New("waku service is not available")
}
return NewGethWakuWrapper(nativeWaku), nil
}
func (w *gethNodeWrapper) AddPeer(url string) error {
parsedNode, err := enode.ParseV4(url)
if err != nil {

View File

@ -0,0 +1,103 @@
package gethbridge
import (
"context"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
)
type gethPublicWakuAPIWrapper struct {
api *waku.PublicWakuAPI
}
// NewGethPublicWakuAPIWrapper returns an object that wraps Geth's PublicWakuAPI in a types interface
func NewGethPublicWakuAPIWrapper(api *waku.PublicWakuAPI) types.PublicWakuAPI {
if api == nil {
panic("PublicWakuAPI cannot be nil")
}
return &gethPublicWakuAPIWrapper{
api: api,
}
}
// AddPrivateKey imports the given private key.
func (w *gethPublicWakuAPIWrapper) AddPrivateKey(ctx context.Context, privateKey types.HexBytes) (string, error) {
return w.api.AddPrivateKey(ctx, hexutil.Bytes(privateKey))
}
// GenerateSymKeyFromPassword derives a key from the given password, stores it, and returns its ID.
func (w *gethPublicWakuAPIWrapper) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) {
return w.api.GenerateSymKeyFromPassword(ctx, passwd)
}
// DeleteKeyPair removes the key with the given key if it exists.
func (w *gethPublicWakuAPIWrapper) DeleteKeyPair(ctx context.Context, key string) (bool, error) {
return w.api.DeleteKeyPair(ctx, key)
}
// NewMessageFilter creates a new filter that can be used to poll for
// (new) messages that satisfy the given criteria.
func (w *gethPublicWakuAPIWrapper) NewMessageFilter(req types.Criteria) (string, error) {
topics := make([]waku.TopicType, len(req.Topics))
for index, tt := range req.Topics {
topics[index] = waku.TopicType(tt)
}
criteria := waku.Criteria{
SymKeyID: req.SymKeyID,
PrivateKeyID: req.PrivateKeyID,
Sig: req.Sig,
MinPow: req.MinPow,
Topics: topics,
AllowP2P: req.AllowP2P,
}
return w.api.NewMessageFilter(criteria)
}
// GetFilterMessages returns the messages that match the filter criteria and
// are received between the last poll and now.
func (w *gethPublicWakuAPIWrapper) GetFilterMessages(id string) ([]*types.Message, error) {
msgs, err := w.api.GetFilterMessages(id)
if err != nil {
return nil, err
}
wrappedMsgs := make([]*types.Message, len(msgs))
for index, msg := range msgs {
wrappedMsgs[index] = &types.Message{
Sig: msg.Sig,
TTL: msg.TTL,
Timestamp: msg.Timestamp,
Topic: types.TopicType(msg.Topic),
Payload: msg.Payload,
Padding: msg.Padding,
PoW: msg.PoW,
Hash: msg.Hash,
Dst: msg.Dst,
P2P: msg.P2P,
}
}
return wrappedMsgs, nil
}
// Post posts a message on the network.
// returns the hash of the message in case of success.
func (w *gethPublicWakuAPIWrapper) Post(ctx context.Context, req types.NewMessage) ([]byte, error) {
msg := waku.NewMessage{
SymKeyID: req.SymKeyID,
PublicKey: req.PublicKey,
Sig: req.SigID, // Sig is really a SigID
TTL: req.TTL,
Topic: waku.TopicType(req.Topic),
Payload: req.Payload,
Padding: req.Padding,
PowTime: req.PowTime,
PowTarget: req.PowTarget,
TargetPeer: req.TargetPeer,
}
return w.api.Post(ctx, msg)
}

View File

@ -0,0 +1,197 @@
package gethbridge
import (
"crypto/ecdsa"
"time"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
)
type gethWakuWrapper struct {
waku *waku.Waku
}
// NewGethWakuWrapper returns an object that wraps Geth's Waku in a types interface
func NewGethWakuWrapper(w *waku.Waku) types.Waku {
if w == nil {
panic("waku cannot be nil")
}
return &gethWakuWrapper{
waku: w,
}
}
// GetGethWhisperFrom retrieves the underlying whisper Whisper struct from a wrapped Whisper interface
func GetGethWakuFrom(m types.Waku) *waku.Waku {
return m.(*gethWakuWrapper).waku
}
func (w *gethWakuWrapper) PublicWakuAPI() types.PublicWakuAPI {
return NewGethPublicWakuAPIWrapper(waku.NewPublicWakuAPI(w.waku))
}
// MinPow returns the PoW value required by this node.
func (w *gethWakuWrapper) MinPow() float64 {
return w.waku.MinPow()
}
// BloomFilter returns the aggregated bloom filter for all the topics of interest.
// The nodes are required to send only messages that match the advertised bloom filter.
// If a message does not match the bloom, it will tantamount to spam, and the peer will
// be disconnected.
func (w *gethWakuWrapper) BloomFilter() []byte {
return w.waku.BloomFilter()
}
// GetCurrentTime returns current time.
func (w *gethWakuWrapper) GetCurrentTime() time.Time {
return w.waku.CurrentTime()
}
// SetTimeSource assigns a particular source of time to a whisper object.
func (w *gethWakuWrapper) SetTimeSource(timesource func() time.Time) {
w.waku.SetTimeSource(timesource)
}
func (w *gethWakuWrapper) SubscribeEnvelopeEvents(eventsProxy chan<- types.EnvelopeEvent) types.Subscription {
events := make(chan waku.EnvelopeEvent, 100) // must be buffered to prevent blocking whisper
go func() {
for e := range events {
eventsProxy <- *NewWakuEnvelopeEventWrapper(&e)
}
}()
return NewGethSubscriptionWrapper(w.waku.SubscribeEnvelopeEvents(events))
}
func (w *gethWakuWrapper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
return w.waku.GetPrivateKey(id)
}
// AddKeyPair imports a asymmetric private key and returns a deterministic identifier.
func (w *gethWakuWrapper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
return w.waku.AddKeyPair(key)
}
// DeleteKeyPair deletes the key with the specified ID if it exists.
func (w *gethWakuWrapper) DeleteKeyPair(keyID string) bool {
return w.waku.DeleteKeyPair(keyID)
}
func (w *gethWakuWrapper) AddSymKeyDirect(key []byte) (string, error) {
return w.waku.AddSymKeyDirect(key)
}
func (w *gethWakuWrapper) AddSymKeyFromPassword(password string) (string, error) {
return w.waku.AddSymKeyFromPassword(password)
}
func (w *gethWakuWrapper) DeleteSymKey(id string) bool {
return w.waku.DeleteSymKey(id)
}
func (w *gethWakuWrapper) GetSymKey(id string) ([]byte, error) {
return w.waku.GetSymKey(id)
}
func (w *gethWakuWrapper) Subscribe(opts *types.SubscriptionOptions) (string, error) {
var (
err error
keyAsym *ecdsa.PrivateKey
keySym []byte
)
if opts.SymKeyID != "" {
keySym, err = w.GetSymKey(opts.SymKeyID)
if err != nil {
return "", err
}
}
if opts.PrivateKeyID != "" {
keyAsym, err = w.GetPrivateKey(opts.PrivateKeyID)
if err != nil {
return "", err
}
}
f, err := w.createFilterWrapper("", keyAsym, keySym, opts.PoW, opts.Topics)
if err != nil {
return "", err
}
id, err := w.waku.Subscribe(GetWakuFilterFrom(f))
if err != nil {
return "", err
}
f.(*wakuFilterWrapper).id = id
return id, nil
}
func (w *gethWakuWrapper) GetFilter(id string) types.Filter {
return NewWakuFilterWrapper(w.waku.GetFilter(id), id)
}
func (w *gethWakuWrapper) Unsubscribe(id string) error {
return w.waku.Unsubscribe(id)
}
func (w *gethWakuWrapper) createFilterWrapper(id string, keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (types.Filter, error) {
return NewWakuFilterWrapper(&waku.Filter{
KeyAsym: keyAsym,
KeySym: keySym,
PoW: pow,
AllowP2P: true,
Topics: topics,
Messages: waku.NewMemoryMessageStore(),
}, id), nil
}
func (w *gethWakuWrapper) SendMessagesRequest(peerID []byte, r types.MessagesRequest) error {
return w.waku.SendMessagesRequest(peerID, waku.MessagesRequest{
ID: r.ID,
From: r.From,
To: r.To,
Limit: r.Limit,
Cursor: r.Cursor,
Bloom: r.Bloom,
})
}
// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer,
// which is known to implement MailServer interface, and is supposed to process this
// request and respond with a number of peer-to-peer messages (possibly expired),
// which are not supposed to be forwarded any further.
// The whisper protocol is agnostic of the format and contents of envelope.
func (w *gethWakuWrapper) RequestHistoricMessagesWithTimeout(peerID []byte, envelope types.Envelope, timeout time.Duration) error {
return w.waku.RequestHistoricMessagesWithTimeout(peerID, MustUnwrapWakuEnvelope(envelope), timeout)
}
type wakuFilterWrapper struct {
filter *waku.Filter
id string
}
// NewWakuFilterWrapper returns an object that wraps Geth's Filter in a types interface
func NewWakuFilterWrapper(f *waku.Filter, id string) types.Filter {
if f.Messages == nil {
panic("Messages should not be nil")
}
return &wakuFilterWrapper{
filter: f,
id: id,
}
}
// GetWakuFilterFrom retrieves the underlying whisper Filter struct from a wrapped Filter interface
func GetWakuFilterFrom(f types.Filter) *waku.Filter {
return f.(*wakuFilterWrapper).filter
}
// ID returns the filter ID
func (w *wakuFilterWrapper) ID() string {
return w.id
}

View File

@ -59,7 +59,7 @@ func (w *gethWhisperWrapper) SubscribeEnvelopeEvents(eventsProxy chan<- types.En
events := make(chan whisper.EnvelopeEvent, 100) // must be buffered to prevent blocking whisper
go func() {
for e := range events {
eventsProxy <- *NewGethEnvelopeEventWrapper(&e)
eventsProxy <- *NewWhisperEnvelopeEventWrapper(&e)
}
}()
@ -121,17 +121,17 @@ func (w *gethWhisperWrapper) Subscribe(opts *types.SubscriptionOptions) (string,
return "", err
}
id, err := w.whisper.Subscribe(GetGethFilterFrom(f))
id, err := w.whisper.Subscribe(GetWhisperFilterFrom(f))
if err != nil {
return "", err
}
f.(*gethFilterWrapper).id = id
f.(*whisperFilterWrapper).id = id
return id, nil
}
func (w *gethWhisperWrapper) GetFilter(id string) types.Filter {
return NewGethFilterWrapper(w.whisper.GetFilter(id), id)
return NewWhisperFilterWrapper(w.whisper.GetFilter(id), id)
}
func (w *gethWhisperWrapper) Unsubscribe(id string) error {
@ -139,7 +139,7 @@ func (w *gethWhisperWrapper) Unsubscribe(id string) error {
}
func (w *gethWhisperWrapper) createFilterWrapper(id string, keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (types.Filter, error) {
return NewGethFilterWrapper(&whisper.Filter{
return NewWhisperFilterWrapper(&whisper.Filter{
KeyAsym: keyAsym,
KeySym: keySym,
PoW: pow,
@ -173,3 +173,30 @@ func (w *gethWhisperWrapper) RequestHistoricMessagesWithTimeout(peerID []byte, e
func (w *gethWhisperWrapper) SyncMessages(peerID []byte, req types.SyncMailRequest) error {
return w.whisper.SyncMessages(peerID, *GetGethSyncMailRequestFrom(&req))
}
type whisperFilterWrapper struct {
filter *whisper.Filter
id string
}
// NewWhisperFilterWrapper returns an object that wraps Geth's Filter in a types interface
func NewWhisperFilterWrapper(f *whisper.Filter, id string) types.Filter {
if f.Messages == nil {
panic("Messages should not be nil")
}
return &whisperFilterWrapper{
filter: f,
id: id,
}
}
// GetWhisperFilterFrom retrieves the underlying whisper Filter struct from a wrapped Filter interface
func GetWhisperFilterFrom(f types.Filter) *whisper.Filter {
return f.(*whisperFilterWrapper).filter
}
// ID returns the filter ID
func (w *whisperFilterWrapper) ID() string {
return w.id
}

8
eth-node/types/const.go Normal file
View File

@ -0,0 +1,8 @@
package types
const (
// PubKeyLength represents the length (in bytes) of an uncompressed public key
PubKeyLength = 512 / 8
// AesKeyLength represents the length (in bytes) of an private key
AesKeyLength = 256 / 8
)

View File

@ -19,6 +19,7 @@ func (n EnodeID) String() string {
type Node interface {
NewENSVerifier(logger *zap.Logger) enstypes.ENSVerifier
GetWhisper(ctx interface{}) (Whisper, error)
GetWaku(ctx interface{}) (Waku, error)
AddPeer(url string) error
RemovePeer(url string) error
}

View File

@ -63,3 +63,25 @@ type PublicWhisperAPI interface {
// are received between the last poll and now.
GetFilterMessages(id string) ([]*Message, error)
}
// PublicWakuAPI provides the waku RPC service that can be
// use publicly without security implications.
type PublicWakuAPI interface {
// AddPrivateKey imports the given private key.
AddPrivateKey(ctx context.Context, privateKey HexBytes) (string, error)
// GenerateSymKeyFromPassword derives a key from the given password, stores it, and returns its ID.
GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error)
// DeleteKeyPair removes the key with the given key if it exists.
DeleteKeyPair(ctx context.Context, key string) (bool, error)
// Post posts a message on the Whisper network.
// returns the hash of the message in case of success.
Post(ctx context.Context, req NewMessage) ([]byte, error)
// NewMessageFilter creates a new filter that can be used to poll for
// (new) messages that satisfy the given criteria.
NewMessageFilter(req Criteria) (string, error)
// GetFilterMessages returns the messages that match the filter criteria and
// are received between the last poll and now.
GetFilterMessages(id string) ([]*Message, error)
}

View File

@ -0,0 +1,10 @@
package types
// SubscriptionOptions represents the parameters passed to Subscribe()
// to customize the subscription behavior.
type SubscriptionOptions struct {
PrivateKeyID string
SymKeyID string
PoW float64
Topics [][]byte
}

53
eth-node/types/waku.go Normal file
View File

@ -0,0 +1,53 @@
package types
import (
"crypto/ecdsa"
"time"
)
// Whisper represents a dark communication interface through the Ethereum
// network, using its very own P2P communication layer.
type Waku interface {
PublicWakuAPI() PublicWakuAPI
// MinPow returns the PoW value required by this node.
MinPow() float64
// BloomFilter returns the aggregated bloom filter for all the topics of interest.
// The nodes are required to send only messages that match the advertised bloom filter.
// If a message does not match the bloom, it will tantamount to spam, and the peer will
// be disconnected.
BloomFilter() []byte
// SetTimeSource assigns a particular source of time to a whisper object.
SetTimeSource(timesource func() time.Time)
// GetCurrentTime returns current time.
GetCurrentTime() time.Time
// GetPrivateKey retrieves the private key of the specified identity.
GetPrivateKey(id string) (*ecdsa.PrivateKey, error)
SubscribeEnvelopeEvents(events chan<- EnvelopeEvent) Subscription
// AddKeyPair imports a asymmetric private key and returns a deterministic identifier.
AddKeyPair(key *ecdsa.PrivateKey) (string, error)
// DeleteKeyPair deletes the key with the specified ID if it exists.
DeleteKeyPair(keyID string) bool
AddSymKeyDirect(key []byte) (string, error)
AddSymKeyFromPassword(password string) (string, error)
DeleteSymKey(id string) bool
GetSymKey(id string) ([]byte, error)
Subscribe(opts *SubscriptionOptions) (string, error)
GetFilter(id string) Filter
Unsubscribe(id string) error
// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer,
// which is known to implement MailServer interface, and is supposed to process this
// request and respond with a number of peer-to-peer messages (possibly expired),
// which are not supposed to be forwarded any further.
// The whisper protocol is agnostic of the format and contents of envelope.
// A timeout of 0 never expires.
RequestHistoricMessagesWithTimeout(peerID []byte, envelope Envelope, timeout time.Duration) error
// SendMessagesRequest sends a MessagesRequest. This is an equivalent to RequestHistoricMessages
// in terms of the functionality.
SendMessagesRequest(peerID []byte, request MessagesRequest) error
}

View File

@ -5,22 +5,6 @@ import (
"time"
)
const (
// PubKeyLength represents the length (in bytes) of an uncompressed public key
PubKeyLength = 512 / 8
// AesKeyLength represents the length (in bytes) of an private key
AesKeyLength = 256 / 8
)
// SubscriptionOptions represents the parameters passed to Whisper.Subscribe
// to customize the subscription behavior
type SubscriptionOptions struct {
PrivateKeyID string
SymKeyID string
PoW float64
Topics [][]byte
}
// Whisper represents a dark communication interface through the Ethereum
// network, using its very own P2P communication layer.
type Whisper interface {

View File

@ -86,7 +86,7 @@ func _1557732988_initialize_dbDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1557732988_initialize_db.down.sql", size: 72, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "1557732988_initialize_db.down.sql", size: 72, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0x40, 0x78, 0xb7, 0x71, 0x3c, 0x20, 0x3b, 0xc9, 0xb, 0x2f, 0x49, 0xe4, 0xff, 0x1c, 0x84, 0x54, 0xa1, 0x30, 0xe3, 0x90, 0xf8, 0x73, 0xda, 0xb0, 0x2a, 0xea, 0x8e, 0xf1, 0x82, 0xe7, 0xd2}}
return a, nil
}
@ -106,7 +106,7 @@ func _1557732988_initialize_dbUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1557732988_initialize_db.up.sql", size: 234, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "1557732988_initialize_db.up.sql", size: 234, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8f, 0xa, 0x31, 0xf, 0x94, 0xe, 0xd7, 0xd6, 0xaa, 0x22, 0xd6, 0x6c, 0x7a, 0xbc, 0xad, 0x6a, 0xed, 0x2e, 0x7a, 0xf0, 0x24, 0x81, 0x87, 0x14, 0xe, 0x1c, 0x8a, 0xf1, 0x45, 0xaf, 0x9e, 0x85}}
return a, nil
}
@ -126,7 +126,7 @@ func staticGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static.go", size: 178, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "static.go", size: 178, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xab, 0x8a, 0xf4, 0x27, 0x24, 0x9d, 0x2a, 0x1, 0x7b, 0x54, 0xea, 0xae, 0x4a, 0x35, 0x40, 0x92, 0xb5, 0xf9, 0xb3, 0x54, 0x3e, 0x3a, 0x1a, 0x2b, 0xae, 0xfb, 0x9e, 0x82, 0xeb, 0x4c, 0xf, 0x6}}
return a, nil
}

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(1573806410, 0)}
info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 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(1575903446, 0)}
info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 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(1573806410, 0)}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 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

@ -363,7 +363,7 @@ func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb
if err := ctx.Service(&ethnode); err != nil {
return nil, err
}
return shhext.New(ethnode.Node, ctx, shhext.EnvelopeSignalHandler{}, db, config.ShhextConfig), nil
return shhext.New(ethnode.Node, ctx, "shhext", shhext.EnvelopeSignalHandler{}, db, config.ShhextConfig), nil
})
}
@ -381,9 +381,14 @@ func activateWakuService(stack *node.Node, config *params.NodeConfig, db *leveld
return
}
// TODO: what to do with shhext?
return nil
// TODO(dshulyak) add a config option to enable it by default, but disable if app is started from statusd
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
var ethnode *nodebridge.NodeService
if err := ctx.Service(&ethnode); err != nil {
return nil, err
}
return shhext.New(ethnode.Node, ctx, "wakuext", shhext.EnvelopeSignalHandler{}, db, config.ShhextConfig), nil
})
}
func createShhService(ctx *node.ServiceContext, whisperConfig *params.WhisperConfig, clusterConfig *params.ClusterConfig) (*whisper.Whisper, error) {

View File

@ -5,9 +5,8 @@ package applicationmetadata
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

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

View File

@ -5,9 +5,8 @@ package encryption
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -697,6 +697,7 @@ 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-20190912160710-24e19bdeb0f2 h1:4dVFTC832rPn4pomLSz1vA+are2+dU19w1H8OngV7nc=
golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/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=

View File

@ -19,7 +19,7 @@ import (
"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"
"github.com/status-im/status-go/protocol/transport"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
@ -34,7 +34,7 @@ type messageProcessor struct {
identity *ecdsa.PrivateKey
datasync *datasync.DataSync
protocol *encryption.Protocol
transport *transport.WhisperServiceTransport
transport transport.Transport
logger *zap.Logger
featureFlags featureFlags
@ -44,7 +44,7 @@ func newMessageProcessor(
identity *ecdsa.PrivateKey,
database *sql.DB,
enc *encryption.Protocol,
transport *transport.WhisperServiceTransport,
transport transport.Transport,
logger *zap.Logger,
features featureFlags,
) (*messageProcessor, error) {

View File

@ -23,7 +23,9 @@ import (
"github.com/status-im/status-go/protocol/identity/identicon"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/sqlite"
transport "github.com/status-im/status-go/protocol/transport/whisper"
"github.com/status-im/status-go/protocol/transport"
wakutransp "github.com/status-im/status-go/protocol/transport/waku"
shhtransp "github.com/status-im/status-go/protocol/transport/whisper"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
@ -47,7 +49,7 @@ type Messenger struct {
node types.Node
identity *ecdsa.PrivateKey
persistence *sqlitePersistence
transport *transport.WhisperServiceTransport
transport transport.Transport
encryptor *encryption.Protocol
processor *messageProcessor
handler *MessageHandler
@ -195,11 +197,6 @@ func NewMessenger(
) (*Messenger, error) {
var messenger *Messenger
shh, err := node.GetWhisper(nil)
if err != nil {
return nil, err
}
c := config{}
for _, opt := range opts {
@ -279,22 +276,42 @@ func NewMessenger(
}
// Apply migrations for all components.
err = sqlite.Migrate(database)
err := sqlite.Migrate(database)
if err != nil {
return nil, errors.Wrap(err, "failed to apply migrations")
}
// Initialize transport layer.
t, err := transport.NewWhisperServiceTransport(
shh,
identity,
database,
nil,
c.envelopesMonitorConfig,
logger,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create a WhisperServiceTransport")
var transp transport.Transport
if shh, err := node.GetWhisper(nil); err == nil {
transp, err = shhtransp.NewWhisperServiceTransport(
shh,
identity,
database,
nil,
c.envelopesMonitorConfig,
logger,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create WhisperServiceTransport")
}
} else if err != nil {
logger.Info("failed to find Whisper service; trying Waku", zap.Error(err))
waku, err := node.GetWaku(nil)
if err != nil {
return nil, errors.Wrap(err, "failed to find Whisper and Waku services")
}
transp, err = wakutransp.NewWakuServiceTransport(
waku,
identity,
database,
nil,
c.envelopesMonitorConfig,
logger,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create WakuServiceTransport")
}
}
// Initialize encryption layer.
@ -311,7 +328,7 @@ func NewMessenger(
identity,
database,
encryptionProtocol,
t,
transp,
logger,
c.featureFlags,
)
@ -325,7 +342,7 @@ func NewMessenger(
node: node,
identity: identity,
persistence: &sqlitePersistence{db: database},
transport: t,
transport: transp,
encryptor: encryptionProtocol,
processor: processor,
handler: handler,
@ -340,8 +357,8 @@ func NewMessenger(
verifyTransactionClient: c.verifyTransactionClient,
shutdownTasks: []func() error{
database.Close,
t.Reset,
t.Stop,
transp.ResetFilters,
transp.Stop,
func() error { processor.Stop(); return nil },
// Currently this often fails, seems like it's safe to ignore them
// https://github.com/uber-go/zap/issues/328

View File

@ -1,65 +0,0 @@
package protocol
import (
"strings"
"github.com/pkg/errors"
encryptmigrations "github.com/status-im/status-go/protocol/encryption/migrations"
appmigrations "github.com/status-im/status-go/protocol/migrations"
transpmigrations "github.com/status-im/status-go/protocol/transport/whisper/migrations"
)
type getter func(string) ([]byte, error)
type migrationsWithGetter struct {
Names []string
Getter getter
}
var defaultMigrations = []migrationsWithGetter{
{
Names: transpmigrations.AssetNames(),
Getter: transpmigrations.Asset,
},
{
Names: encryptmigrations.AssetNames(),
Getter: encryptmigrations.Asset,
},
{
Names: appmigrations.AssetNames(),
Getter: appmigrations.Asset,
},
}
func prepareMigrations(migrations []migrationsWithGetter) ([]string, getter, error) {
var allNames []string
nameToGetter := make(map[string]getter)
for _, m := range migrations {
for _, name := range m.Names {
if !validateName(name) {
continue
}
if _, ok := nameToGetter[name]; ok {
return nil, nil, errors.Errorf("migration with name %s already exists", name)
}
allNames = append(allNames, name)
nameToGetter[name] = m.Getter
}
}
return allNames, func(name string) ([]byte, error) {
getter, ok := nameToGetter[name]
if !ok {
return nil, errors.Errorf("no migration for name %s", name)
}
return getter(name)
}, nil
}
// validateName verifies that only *.sql files are taken into consideration.
func validateName(name string) bool {
return strings.HasSuffix(name, ".sql")
}

View File

@ -1,7 +1,7 @@
// Code generated by go-bindata. DO NOT EDIT.
// sources:
// 000001_init.down.db.sql (65B)
// 000001_init.up.db.sql (2.693kB)
// 000001_init.up.db.sql (2.719kB)
// doc.go (377B)
package migrations
@ -86,12 +86,12 @@ func _000001_initDownDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1577718673, 0)}
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1578756765, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5e, 0xbb, 0x3f, 0x1, 0x75, 0x19, 0x70, 0x86, 0xa7, 0x34, 0x40, 0x17, 0x34, 0x3e, 0x18, 0x51, 0x79, 0xd4, 0x22, 0xad, 0x8f, 0x80, 0xcc, 0xa6, 0xcc, 0x6, 0x2b, 0x62, 0x2, 0x47, 0xba, 0xf9}}
return a, nil
}
var __000001_initUpDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x56\x51\x6f\xe3\x36\x0c\x7e\xf7\xaf\x20\xb0\x87\xb6\x80\x3b\xdc\x80\xdb\x6d\x40\x9f\xd2\x9e\xbb\x05\xcb\x92\x43\xea\x0e\xbd\x27\x81\x91\xd8\x58\x88\x2d\x19\x12\x9d\x5c\x80\xfb\xf1\x83\x9c\x38\xb1\x12\xa7\xbd\x61\x7d\x28\x5a\x52\x24\xc5\x8f\xfc\x3e\xf9\x61\x9e\x8d\xf2\x0c\xf2\xd1\xfd\x24\x83\xf1\x23\x4c\x67\x39\x64\x2f\xe3\xa7\xfc\x09\x64\x81\xec\xe1\x3a\xd1\x0a\xfe\x19\xcd\x1f\xfe\x1c\xcd\xe1\xcb\x7c\xfc\xf7\x68\xfe\x15\xfe\xca\xbe\xc2\x6c\x0a\x0f\xb3\xe9\xe3\x64\xfc\x90\xc3\x3c\xfb\x32\x19\x3d\x64\x69\x62\xb0\xa2\xc3\xe9\x90\x6b\xfa\x3c\x99\xa4\x89\xb4\xa5\x75\x67\x76\xf8\x9c\x3d\x8e\x9e\x27\x39\x5c\xfd\x84\xbf\xfc\xfe\x9b\xfa\xf5\x2a\x4d\x78\x5b\x13\x8c\xa7\x79\x2f\x18\x25\xeb\x35\xc1\xfd\x6c\x36\xc9\x46\xd3\xf3\xe8\x7c\xfe\x9c\xa5\x09\xeb\x8a\x3c\x63\x55\x9f\x44\x2b\x2a\x89\x49\x09\x64\x21\x4b\x2b\x57\x62\x8d\x65\x13\x97\x38\x64\xfa\x90\x26\x75\xb3\x28\xb5\x14\x2b\xda\xc2\xfd\x64\x76\x9f\x26\x8d\x59\x6b\xda\x90\x12\x15\x79\x8f\x4b\x12\xd2\x36\x86\x2f\xc6\x97\xe8\x7f\xac\x50\x7b\x70\x9f\x73\x5f\xaa\xa2\x6a\x41\xce\xc7\xff\x15\xba\x16\x4d\xad\x90\x69\xe7\x48\x6e\xee\x92\x24\x9a\x9a\xb4\x86\x51\xb6\xa3\x02\xd0\x0a\xf2\xec\x25\x7f\x7f\x52\x00\xa8\x94\x23\xef\x77\xe7\x8f\x80\x01\xb4\x43\x3c\xb3\x92\xf1\x62\x4d\x4e\xbf\x6a\x52\x87\x61\x74\x0d\x3d\x8e\x26\x4f\xd9\xe9\x29\x81\x97\x71\x02\xc0\x52\xe3\x40\x71\xad\xc8\xb0\x96\xd6\x9c\xbb\xea\xc2\xb2\x3d\x37\xb7\x48\xee\x20\x52\x6f\xd4\xf3\x5b\xcf\x54\x09\xc6\x65\x87\x30\x80\xa2\xb5\x96\x24\xb4\x79\xb5\x07\x1b\x3b\xbd\x68\x98\x04\x5b\xc1\x58\xae\xe2\x7a\x2d\xfa\xb7\xb7\x30\xe6\x2b\x0f\xba\xaa\xad\x63\x34\x0c\x5c\x60\xf8\xa5\x3d\x30\x2e\x4a\x82\x02\x3d\x38\xbb\xd1\x0a\xd0\xc3\x86\xc0\x51\xb9\x05\x6b\x40\x73\x08\xde\x14\x64\x42\x70\x49\x55\xe8\xd5\x2c\x41\x9b\x57\x6d\x34\xd3\xad\x97\xce\x96\xe5\xcf\xc9\x1b\xb4\x6c\x3c\xb9\x6e\x71\x76\x33\x6f\xa7\xfe\xc3\x14\x0d\xe7\x37\x85\xf6\x35\x39\x11\x91\x26\xfb\x23\x9b\x47\xc0\x02\x78\xdb\x38\x39\xb0\x0b\x01\x39\xcf\xda\x20\x6b\x6b\x0e\xc8\x01\x30\x7d\xe3\x01\xfa\x07\x57\xd8\x52\x32\x2c\x06\x08\x1e\xdc\xa1\xab\xbe\x78\xec\xf3\x5d\x20\x75\x9b\xb0\x40\x16\xbd\xc6\x63\x6f\x69\x25\x96\xe2\xed\x33\x85\x56\x74\x79\x93\x01\x1c\xf9\xda\x1a\x1f\x56\x21\xbe\x56\x27\x05\x5d\x2f\xfb\x0b\x5d\x60\xfd\x1e\x4a\x22\x73\x59\xc3\x7a\x55\x6d\xc3\x4b\xab\xcd\x52\x78\x46\x6e\x7c\x5c\xb9\x46\xe7\x49\x89\x16\xe7\x23\xec\x0e\x37\xa2\xc6\x6d\x69\x51\xf5\xac\x9e\xb5\x5c\x91\x13\x35\xca\xd5\xf1\x96\x9d\xb5\x40\x5f\xc4\xb9\xa5\xad\x2a\x34\xaa\x87\x57\x6c\xdf\x75\x36\xe8\xea\xa4\x64\xd0\xf9\xea\x6c\x35\xec\x09\x3b\xe1\x50\xf2\xb0\x97\x1d\x1a\x1f\xc4\xdf\x9a\x37\x6e\xeb\xf5\xd2\x20\x37\x8e\x7a\x9d\x1f\x7c\x8c\xdc\xce\xa2\x2f\x9a\xe3\xe9\xe7\xec\x05\xb4\xfa\x26\xf6\xdb\x3d\x9b\xc6\x9c\xba\xde\xd9\x6f\xee\x06\x22\x08\x9d\x2c\xc4\x62\x7b\xd8\xac\xd9\x14\x4e\xa2\x77\x28\x37\x0b\xcf\xee\xfa\xea\xc3\xff\xfc\xb9\x82\xef\xdf\xfb\x8b\x95\xc2\xed\xa7\x8f\x29\x7c\xfa\x78\x13\x1c\x5a\xa5\x1d\x0d\xd2\x76\x9b\xcf\x1f\x87\x58\x3b\xc2\xa2\x44\xd2\xf1\xdf\x84\xe3\x7d\x52\xb5\x5a\xec\xe9\xe4\x81\x6c\xe5\x97\xda\x81\x9f\xbe\x9d\x7b\x17\x5f\xe6\xa1\xa3\x36\x14\x1b\xb6\x15\xb2\x96\x58\x96\xdb\xcb\xa7\x87\xa8\xe9\x48\xea\x5a\x93\xe1\xa3\xf0\xf7\xd9\xf2\x0e\x66\x21\x23\x99\x65\x50\xcb\xe3\x42\xfa\xf0\x3c\xac\xb1\xd4\xe1\xd5\x69\x91\xec\x0a\xc7\xec\x39\xe7\x54\xd4\xf9\xa5\x15\xef\x0f\x63\xd7\x01\xbb\xed\x11\xbd\x60\x7a\xd5\xae\x85\x9a\x4c\x67\x89\x99\x10\xd7\xe9\x5d\xf6\x14\xba\xdd\xe7\x13\xc0\xc9\x97\xcf\x20\x63\x06\xb1\x88\xa0\x08\x7c\x78\x1f\xb1\xeb\xde\xdf\x37\x77\xc9\xbf\x01\x00\x00\xff\xff\xc7\x20\x3e\x09\x85\x0a\x00\x00")
var __000001_initUpDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x56\xd1\x6f\xe2\xb8\x13\x7e\xe7\xaf\x18\xe9\xf7\x40\x2b\xd1\x9f\xf6\xa4\xbd\xbd\x93\xfa\x44\xd9\xf4\x0e\x1d\x07\x2b\x9a\x9e\xba\x4f\xd6\xe0\x0c\xc4\xc2\xb1\x23\x7b\x02\x8b\xb4\x7f\xfc\xc9\x81\x40\x0c\x81\xee\xea\xfa\x50\xb5\x33\xe3\x19\xcf\x37\xf3\x7d\xce\x68\x9e\x0c\xd3\x04\xd2\xe1\xd3\x24\x81\xf1\x33\x4c\x67\x29\x24\x6f\xe3\x97\xf4\x05\x64\x8e\xec\xe1\xae\x07\xa0\x32\xf8\x67\x38\x1f\xfd\x39\x9c\xc3\x97\xf9\xf8\xef\xe1\xfc\x2b\xfc\x95\x7c\x85\xd9\x14\x46\xb3\xe9\xf3\x64\x3c\x4a\x61\x9e\x7c\x99\x0c\x47\xc9\xa0\x07\x60\xb0\xa0\x63\x7c\xc8\x37\x7d\x9d\x4c\x82\x43\x5a\x6d\xdd\x85\x07\x3e\x27\xcf\xc3\xd7\x49\x0a\xfd\xff\xe1\x2f\xbf\xff\x96\xfd\xda\x0f\xb1\xbc\x2b\x09\xc6\xd3\x34\x4a\x80\x92\xd5\x86\xe0\x69\x36\x9b\x24\xc3\xe9\x65\x86\x74\xfe\x5a\xdf\x80\x55\x41\x9e\xb1\x28\x2f\x32\x64\xa4\x89\x29\x13\xc8\x42\x6a\x2b\xd7\x62\x83\xba\x8a\x0b\x1d\xb3\x7d\x08\x07\xca\x6a\xa1\x95\x14\x6b\xda\xc1\xd3\x64\xf6\x14\x4c\x95\xd9\x28\xda\x52\x26\x0a\xf2\x1e\x57\x24\xa4\xad\x0c\xdf\xc8\xa1\xd1\xff\x68\xb9\x3a\xf4\x90\xf7\x58\xb0\xa0\x62\x41\xce\x9f\xff\x9f\xab\x52\x54\x65\x86\x4c\x7b\x57\xef\xfe\xb1\xd7\x8b\xe6\x29\xad\x61\x94\xa7\x21\xa6\xc9\x5b\xfa\x23\x13\xc4\x2c\x73\xe4\xfd\x3e\xbe\x0d\x5f\x3d\xda\x0b\x2b\x19\x2f\x36\xe4\xd4\x52\x51\x76\x1c\x4e\xd3\xd6\xf3\x70\xf2\x92\x9c\x47\x09\xbc\x85\x17\x6a\x85\x1d\xc5\x55\x46\x86\x95\xb4\xe6\xd2\x55\xe6\x96\xed\xa5\xb9\x46\x73\x0f\x51\x76\xa3\x9e\xdf\x79\xa6\x42\x30\xae\x4e\x18\x67\xb4\x51\x92\x84\x32\x4b\x7b\xb4\xb1\x53\x8b\x8a\x49\xb0\x15\x8c\x7a\x1d\xd7\xab\xd1\x7f\x78\x80\x31\xf7\x3d\xa8\xa2\xb4\x8e\xd1\x30\x70\x8e\xe1\x97\xf2\xc0\xb8\xd0\x04\x39\x7a\x70\x76\xab\x32\x40\x0f\x5b\x02\x47\x7a\x07\xd6\x80\xe2\x70\x78\x9b\x93\x09\x87\x35\x15\xa1\x57\xb3\x02\x65\x96\xca\x28\xa6\x07\x2f\x9d\xd5\xfa\xff\xbd\x1b\x84\xad\x3c\xb9\x66\x79\xf6\x33\xff\x59\xea\x02\x6c\x73\xe5\x4b\x72\x22\xa2\x50\xf2\x47\x12\x33\x19\xc0\xdb\xca\xc9\x8e\x5d\x08\xc8\x79\x56\x06\x59\x59\x73\x44\x0e\x80\xe9\x1b\x77\x8a\x02\xd4\x5b\x4a\x86\x45\x27\xe5\xa1\xee\xaa\x2d\x29\x87\x7c\x57\x29\x0e\xb5\x70\x89\x56\xe3\xb1\x57\x5b\x89\x5a\xdc\x8e\xc9\x55\x46\xd7\x37\x19\xc0\x91\x2f\xad\xf1\x61\x15\xe2\x6b\x35\x92\xd0\xf4\x72\xb8\xd0\x15\xee\x1f\xa0\x24\x32\xd7\x35\xad\x55\xd5\x56\xbc\xb2\xca\xac\x84\x67\xe4\xca\xc7\x95\x4b\x74\x9e\x32\x51\xe3\x7c\x82\xdd\xe1\x56\x94\xb8\xd3\x16\xb3\x96\xd5\xb3\x92\x6b\x72\xa2\x44\xb9\x3e\xdd\xb2\xb1\xe6\xe8\xf3\x38\xb7\xb4\x45\x81\x26\x6b\xe1\x15\xdb\xf7\x9d\x75\xba\x1a\x29\xe9\x74\x2e\x9d\x2d\xba\x3d\x61\x27\x1c\x4a\xee\xf6\xb2\x43\xe3\xc3\x63\x60\xcd\x8d\xdb\x7a\xb5\x32\xc8\x95\xa3\x56\xe7\x47\x1f\x23\xd7\xb3\x68\x8b\xe6\x78\xfa\x39\x79\x03\x95\x7d\x13\x87\xed\x9e\x4d\x63\x4e\xdd\xed\xed\xf7\x8f\x1d\x27\x08\x9d\xcc\xc5\x62\x77\xdc\xac\xd9\x14\xce\x4e\xef\x51\xae\x16\x9e\xdd\x5d\xff\xc3\x7f\xfc\xe9\xc3\xf7\xef\xed\xc5\x1a\xc0\xc3\xa7\x8f\x03\xf8\xf4\xf1\x3e\x38\x54\x36\x68\x68\x30\xa8\xb7\xf9\xf2\x71\x88\xb5\x23\x2c\x4a\x24\x1d\x3f\x27\x1c\xef\x93\xaa\xd6\x62\x4f\x67\x0f\x65\x2d\xbf\x54\x0f\xfc\xfc\x0d\x3d\xb8\xf8\x3a\x0f\x1d\xd5\x47\xb1\x62\x5b\x20\x2b\x89\x5a\xef\xae\x47\x77\x51\xd3\x91\x54\xa5\x22\xc3\x27\xe1\x6f\xb3\xe5\x1d\xcc\x42\x46\x32\xab\xa0\x96\xa7\x85\xf4\xe1\x79\xd8\xa0\x56\xe1\xd5\xa9\x91\x6c\x0a\xc7\xec\xb9\xe4\x54\xd4\xf9\xb5\x15\x6f\x0f\x63\xdf\x01\xbb\xdd\x09\xbd\x60\x5a\x2a\x57\x43\x4d\xa6\xb1\xc4\x4c\x88\xeb\xb4\x2e\x7b\x0e\x5d\xf3\x39\x75\xf6\x0d\xd4\xc9\x98\x4e\x2c\x22\x28\x02\x1f\xde\x47\xec\xae\xf5\xf7\xfd\x63\xef\xdf\x00\x00\x00\xff\xff\xd7\x95\x8b\x6b\x9f\x0a\x00\x00")
func _000001_initUpDbSqlBytes() ([]byte, error) {
return bindataRead(
@ -106,8 +106,8 @@ func _000001_initUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2693, mode: os.FileMode(0644), modTime: time.Unix(1577718868, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0x9f, 0x6, 0x64, 0xcf, 0x97, 0xbe, 0xa8, 0xa2, 0x2f, 0xda, 0xc5, 0x9d, 0x26, 0x3, 0x65, 0x98, 0x8a, 0x7a, 0x6a, 0xc3, 0xd, 0x3f, 0x25, 0xfe, 0x4c, 0x5, 0xdb, 0x98, 0xa9, 0xf9, 0xf}}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(0644), modTime: time.Unix(1578756765, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0xdc, 0xeb, 0xe, 0xc2, 0x4f, 0x75, 0xa, 0xf6, 0x3e, 0xc7, 0xc4, 0x4, 0xe2, 0xe1, 0xa4, 0x73, 0x2f, 0x4a, 0xad, 0x1a, 0x0, 0xc3, 0x93, 0x9d, 0x77, 0x3e, 0x31, 0x91, 0x77, 0x2e, 0xc8}}
return a, nil
}
@ -126,7 +126,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1574354941, 0)}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xef, 0xaf, 0xdf, 0xcf, 0x65, 0xae, 0x19, 0xfc, 0x9d, 0x29, 0xc1, 0x91, 0xaf, 0xb5, 0xd5, 0xb1, 0x56, 0xf3, 0xee, 0xa8, 0xba, 0x13, 0x65, 0xdb, 0xab, 0xcf, 0x4e, 0xac, 0x92, 0xe9, 0x60, 0xf1}}
return a, nil
}

View File

@ -5,9 +5,8 @@ package protobuf
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -5,9 +5,8 @@ package protobuf
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -5,9 +5,8 @@ package protobuf
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -7,7 +7,8 @@ import (
encryptmigrations "github.com/status-im/status-go/protocol/encryption/migrations"
appmigrations "github.com/status-im/status-go/protocol/migrations"
transpmigrations "github.com/status-im/status-go/protocol/transport/whisper/migrations"
wakumigrations "github.com/status-im/status-go/protocol/transport/waku/migrations"
whispermigrations "github.com/status-im/status-go/protocol/transport/whisper/migrations"
)
type getter func(string) ([]byte, error)
@ -19,8 +20,12 @@ type migrationsWithGetter struct {
var defaultMigrations = []migrationsWithGetter{
{
Names: transpmigrations.AssetNames(),
Getter: transpmigrations.Asset,
Names: whispermigrations.AssetNames(),
Getter: whispermigrations.Asset,
},
{
Names: wakumigrations.AssetNames(),
Getter: wakumigrations.Asset,
},
{
Names: encryptmigrations.AssetNames(),

View File

@ -1,4 +1,4 @@
package protocol
package sqlite
import (
"testing"

View File

@ -0,0 +1,22 @@
package transport
import (
"github.com/status-im/status-go/eth-node/types"
"go.uber.org/zap"
)
type EnvelopesMonitorConfig struct {
EnvelopeEventsHandler EnvelopeEventsHandler
MaxAttempts int
MailserverConfirmationsEnabled bool
IsMailserver func(types.EnodeID) bool
Logger *zap.Logger
}
// EnvelopeEventsHandler used for two different event types.
type EnvelopeEventsHandler interface {
EnvelopeSent([][]byte)
EnvelopeExpired([][]byte, error)
MailServerRequestCompleted(types.Hash, types.Hash, []byte, error)
MailServerRequestExpired(types.Hash)
}

View File

@ -0,0 +1,30 @@
package transport
import "github.com/status-im/status-go/eth-node/types"
// TODO: revise fields encoding/decoding. Some are encoded using hexutil and some using encoding/hex.
type Filter struct {
// ChatID is the identifier of the chat
ChatID string `json:"chatId"`
// FilterID the whisper filter id generated
FilterID string `json:"filterId"`
// SymKeyID is the symmetric key id used for symmetric filters
SymKeyID string `json:"symKeyId"`
// OneToOne tells us if we need to use asymmetric encryption for this chat
OneToOne bool `json:"oneToOne"`
// Identity is the public key of the other recipient for non-public filters.
// It's encoded using encoding/hex.
Identity string `json:"identity"`
// Topic is the whisper topic
Topic types.TopicType `json:"topic"`
// Discovery is whether this is a discovery topic
Discovery bool `json:"discovery"`
// Negotiated tells us whether is a negotiated topic
Negotiated bool `json:"negotiated"`
// Listen is whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic
Listen bool `json:"listen"`
}
func (c *Filter) IsPublic() bool {
return !c.OneToOne
}

View File

@ -1,66 +1,47 @@
package whisper
package transport
import (
"crypto/ecdsa"
"database/sql"
"encoding/hex"
"math/big"
"strconv"
"sync"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
const (
discoveryTopic = "contact-discovery"
minPow = 0.0
)
var (
// The number of partitions.
nPartitions = big.NewInt(5000)
minPow = 0.0
)
type whisperFilter struct {
type RawFilter struct {
FilterID string
Topic types.TopicType
SymKeyID string
}
// TODO: revise fields encoding/decoding. Some are encoded using hexutil and some using encoding/hex.
type Filter struct {
// ChatID is the identifier of the chat
ChatID string `json:"chatId"`
// FilterID the whisper filter id generated
FilterID string `json:"filterId"`
// SymKeyID is the symmetric key id used for symmetric filters
SymKeyID string `json:"symKeyId"`
// OneToOne tells us if we need to use asymmetric encryption for this chat
OneToOne bool `json:"oneToOne"`
// Identity is the public key of the other recipient for non-public filters.
// It's encoded using encoding/hex.
Identity string `json:"identity"`
// Topic is the whisper topic
Topic types.TopicType `json:"topic"`
// Discovery is whether this is a discovery topic
Discovery bool `json:"discovery"`
// Negotiated tells us whether is a negotiated topic
Negotiated bool `json:"negotiated"`
// Listen is whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic
Listen bool `json:"listen"`
type KeysPersistence interface {
All() (map[string][]byte, error)
Add(chatID string, key []byte) error
}
func (c *Filter) IsPublic() bool {
return !c.OneToOne
type FiltersService interface {
AddKeyPair(key *ecdsa.PrivateKey) (string, error)
DeleteKeyPair(keyID string) bool
AddSymKeyDirect(key []byte) (string, error)
AddSymKeyFromPassword(password string) (string, error)
GetSymKey(id string) ([]byte, error)
DeleteSymKey(id string) bool
Subscribe(opts *types.SubscriptionOptions) (string, error)
Unsubscribe(id string) error
}
type filtersManager struct {
whisper types.Whisper
persistence *sqlitePersistence
type FiltersManager struct {
service FiltersService
persistence KeysPersistence
privateKey *ecdsa.PrivateKey
keys map[string][]byte // a cache of symmetric manager derived from passwords
logger *zap.Logger
@ -71,22 +52,20 @@ type filtersManager struct {
filters map[string]*Filter
}
// newFiltersManager returns a new filtersManager.
func newFiltersManager(db *sql.DB, w types.Whisper, privateKey *ecdsa.PrivateKey, logger *zap.Logger) (*filtersManager, error) {
// NewFiltersManager returns a new filtersManager.
func NewFiltersManager(persistence KeysPersistence, service FiltersService, privateKey *ecdsa.PrivateKey, logger *zap.Logger) (*FiltersManager, error) {
if logger == nil {
logger = zap.NewNop()
}
persistence := newSQLitePersistence(db)
keys, err := persistence.All()
if err != nil {
return nil, err
}
return &filtersManager{
return &FiltersManager{
privateKey: privateKey,
whisper: w,
service: service,
persistence: persistence,
keys: keys,
filters: make(map[string]*Filter),
@ -94,7 +73,7 @@ func newFiltersManager(db *sql.DB, w types.Whisper, privateKey *ecdsa.PrivateKey
}, nil
}
func (s *filtersManager) Init(
func (s *FiltersManager) Init(
chatIDs []string,
publicKeys []*ecdsa.PublicKey,
) ([]*Filter, error) {
@ -146,7 +125,7 @@ func (s *filtersManager) Init(
}
// DEPRECATED
func (s *filtersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
func (s *FiltersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
var (
chatIDs []string
publicKeys []*ecdsa.PublicKey
@ -154,7 +133,7 @@ func (s *filtersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
for _, filter := range filters {
if filter.Identity != "" && filter.OneToOne {
publicKey, err := strToPublicKey(filter.Identity)
publicKey, err := StrToPublicKey(filter.Identity)
if err != nil {
return nil, err
}
@ -167,7 +146,7 @@ func (s *filtersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
return s.Init(chatIDs, publicKeys)
}
func (s *filtersManager) Reset() error {
func (s *FiltersManager) Reset() error {
var filters []*Filter
s.mutex.Lock()
@ -179,7 +158,7 @@ func (s *filtersManager) Reset() error {
return s.Remove(filters...)
}
func (s *filtersManager) Filters() (result []*Filter) {
func (s *FiltersManager) Filters() (result []*Filter) {
s.mutex.Lock()
defer s.mutex.Unlock()
@ -190,14 +169,14 @@ func (s *filtersManager) Filters() (result []*Filter) {
return
}
func (s *filtersManager) Filter(chatID string) *Filter {
func (s *FiltersManager) Filter(chatID string) *Filter {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.filters[chatID]
}
// FilterByFilterID returns a Filter with a given Whisper filter ID.
func (s *filtersManager) FilterByFilterID(filterID string) *Filter {
func (s *FiltersManager) FilterByFilterID(filterID string) *Filter {
s.mutex.Lock()
defer s.mutex.Unlock()
for _, f := range s.filters {
@ -208,11 +187,11 @@ func (s *filtersManager) FilterByFilterID(filterID string) *Filter {
return nil
}
func (s *filtersManager) FiltersByPublicKey(publicKey *ecdsa.PublicKey) (result []*Filter) {
func (s *FiltersManager) FiltersByPublicKey(publicKey *ecdsa.PublicKey) (result []*Filter) {
s.mutex.Lock()
defer s.mutex.Unlock()
identityStr := publicKeyToStr(publicKey)
identityStr := PublicKeyToStr(publicKey)
for _, f := range s.filters {
if f.Identity == identityStr {
@ -224,16 +203,16 @@ func (s *filtersManager) FiltersByPublicKey(publicKey *ecdsa.PublicKey) (result
}
// Remove remove all the filters associated with a chat/identity
func (s *filtersManager) Remove(filters ...*Filter) error {
func (s *FiltersManager) Remove(filters ...*Filter) error {
s.mutex.Lock()
defer s.mutex.Unlock()
for _, f := range filters {
if err := s.whisper.Unsubscribe(f.FilterID); err != nil {
if err := s.service.Unsubscribe(f.FilterID); err != nil {
return err
}
if f.SymKeyID != "" {
s.whisper.DeleteSymKey(f.SymKeyID)
s.service.DeleteSymKey(f.SymKeyID)
}
delete(s.filters, f.ChatID)
}
@ -242,19 +221,19 @@ func (s *filtersManager) Remove(filters ...*Filter) error {
}
// LoadPartitioned creates a filter for a partitioned topic.
func (s *filtersManager) LoadPartitioned(publicKey *ecdsa.PublicKey) (*Filter, error) {
func (s *FiltersManager) LoadPartitioned(publicKey *ecdsa.PublicKey) (*Filter, error) {
return s.loadPartitioned(publicKey, false)
}
func (s *filtersManager) loadMyPartitioned() (*Filter, error) {
func (s *FiltersManager) loadMyPartitioned() (*Filter, error) {
return s.loadPartitioned(&s.privateKey.PublicKey, true)
}
func (s *filtersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool) (*Filter, error) {
func (s *FiltersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
chatID := partitionedTopic(publicKey)
chatID := PartitionedTopic(publicKey)
if _, ok := s.filters[chatID]; ok {
return s.filters[chatID], nil
}
@ -270,7 +249,7 @@ func (s *filtersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool
ChatID: chatID,
FilterID: filter.FilterID,
Topic: filter.Topic,
Identity: publicKeyToStr(publicKey),
Identity: PublicKeyToStr(publicKey),
Listen: listen,
OneToOne: true,
}
@ -281,11 +260,11 @@ func (s *filtersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool
}
// LoadNegotiated loads a negotiated secret as a filter.
func (s *filtersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter, error) {
func (s *FiltersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
chatID := negotiatedTopic(secret.PublicKey)
chatID := NegotiatedTopic(secret.PublicKey)
if _, ok := s.filters[chatID]; ok {
return s.filters[chatID], nil
@ -302,7 +281,7 @@ func (s *filtersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter,
Topic: filter.Topic,
SymKeyID: filter.SymKeyID,
FilterID: filter.FilterID,
Identity: publicKeyToStr(secret.PublicKey),
Identity: PublicKeyToStr(secret.PublicKey),
Negotiated: true,
Listen: true,
OneToOne: true,
@ -315,11 +294,11 @@ func (s *filtersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter,
// LoadDiscovery adds 1 discovery filter
// for the personal discovery topic.
func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
func (s *FiltersManager) LoadDiscovery() ([]*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
personalDiscoveryTopic := personalDiscoveryTopic(&s.privateKey.PublicKey)
personalDiscoveryTopic := PersonalDiscoveryTopic(&s.privateKey.PublicKey)
// Check if filters are already loaded.
var result []*Filter
@ -334,9 +313,7 @@ func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
return result, nil
}
var discoveryResponse *whisperFilter
var err error
identityStr := publicKeyToStr(&s.privateKey.PublicKey)
identityStr := PublicKeyToStr(&s.privateKey.PublicKey)
// Load personal discovery
personalDiscoveryChat := &Filter{
@ -347,7 +324,7 @@ func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
OneToOne: true,
}
discoveryResponse, err = s.addAsymmetric(personalDiscoveryChat.ChatID, true)
discoveryResponse, err := s.addAsymmetric(personalDiscoveryChat.ChatID, true)
if err != nil {
return nil, err
}
@ -361,7 +338,7 @@ func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
}
// LoadPublic adds a filter for a public chat.
func (s *filtersManager) LoadPublic(chatID string) (*Filter, error) {
func (s *FiltersManager) LoadPublic(chatID string) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
@ -389,11 +366,11 @@ func (s *filtersManager) LoadPublic(chatID string) (*Filter, error) {
}
// LoadContactCode creates a filter for the advertise topic for a given public key.
func (s *filtersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, error) {
func (s *FiltersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
chatID := contactCodeTopic(pubKey)
chatID := ContactCodeTopic(pubKey)
if _, ok := s.filters[chatID]; ok {
return s.filters[chatID], nil
@ -409,7 +386,7 @@ func (s *filtersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, erro
FilterID: contactCodeFilter.FilterID,
Topic: contactCodeFilter.Topic,
SymKeyID: contactCodeFilter.SymKeyID,
Identity: publicKeyToStr(pubKey),
Identity: PublicKeyToStr(pubKey),
Listen: true,
}
@ -418,25 +395,25 @@ func (s *filtersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, erro
}
// addSymmetric adds a symmetric key filter
func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
func (s *FiltersManager) addSymmetric(chatID string) (*RawFilter, error) {
var symKeyID string
var err error
topic := toTopic(chatID)
topic := ToTopic(chatID)
topics := [][]byte{topic}
symKey, ok := s.keys[chatID]
if ok {
symKeyID, err = s.whisper.AddSymKeyDirect(symKey)
symKeyID, err = s.service.AddSymKeyDirect(symKey)
if err != nil {
return nil, err
}
} else {
symKeyID, err = s.whisper.AddSymKeyFromPassword(chatID)
symKeyID, err = s.service.AddSymKeyFromPassword(chatID)
if err != nil {
return nil, err
}
if symKey, err = s.whisper.GetSymKey(symKeyID); err != nil {
if symKey, err = s.service.GetSymKey(symKeyID); err != nil {
return nil, err
}
s.keys[chatID] = symKey
@ -447,7 +424,7 @@ func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
}
}
id, err := s.whisper.Subscribe(&types.SubscriptionOptions{
id, err := s.service.Subscribe(&types.SubscriptionOptions{
SymKeyID: symKeyID,
PoW: minPow,
Topics: topics,
@ -456,7 +433,7 @@ func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
return nil, err
}
return &whisperFilter{
return &RawFilter{
FilterID: id,
SymKeyID: symKeyID,
Topic: types.BytesToTopic(topic),
@ -465,7 +442,7 @@ func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
// addAsymmetricFilter adds a filter with our private key
// and set minPow according to the listen parameter.
func (s *filtersManager) addAsymmetric(chatID string, listen bool) (*whisperFilter, error) {
func (s *FiltersManager) addAsymmetric(chatID string, listen bool) (*RawFilter, error) {
var (
err error
pow = 1.0 // use PoW high enough to discard all messages for the filter
@ -475,15 +452,15 @@ func (s *filtersManager) addAsymmetric(chatID string, listen bool) (*whisperFilt
pow = minPow
}
topic := toTopic(chatID)
topic := ToTopic(chatID)
topics := [][]byte{topic}
privateKeyID, err := s.whisper.AddKeyPair(s.privateKey)
privateKeyID, err := s.service.AddKeyPair(s.privateKey)
if err != nil {
return nil, err
}
id, err := s.whisper.Subscribe(&types.SubscriptionOptions{
id, err := s.service.Subscribe(&types.SubscriptionOptions{
PrivateKeyID: privateKeyID,
PoW: pow,
Topics: topics,
@ -491,58 +468,13 @@ func (s *filtersManager) addAsymmetric(chatID string, listen bool) (*whisperFilt
if err != nil {
return nil, err
}
return &whisperFilter{FilterID: id, Topic: types.BytesToTopic(topic)}, nil
return &RawFilter{FilterID: id, Topic: types.BytesToTopic(topic)}, nil
}
// GetNegotiated returns a negotiated chat given an identity
func (s *filtersManager) GetNegotiated(identity *ecdsa.PublicKey) *Filter {
func (s *FiltersManager) GetNegotiated(identity *ecdsa.PublicKey) *Filter {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.filters[negotiatedTopic(identity)]
}
func toTopic(s string) []byte {
return crypto.Keccak256([]byte(s))[:types.TopicLength]
}
// ToTopic converts a string to a whisper topic.
func ToTopic(s string) []byte {
return toTopic(s)
}
func strToPublicKey(str string) (*ecdsa.PublicKey, error) {
publicKeyBytes, err := hex.DecodeString(str)
if err != nil {
return nil, err
}
return crypto.UnmarshalPubkey(publicKeyBytes)
}
func publicKeyToStr(publicKey *ecdsa.PublicKey) string {
return hex.EncodeToString(crypto.FromECDSAPub(publicKey))
}
func personalDiscoveryTopic(publicKey *ecdsa.PublicKey) string {
return "contact-discovery-" + publicKeyToStr(publicKey)
}
// partitionedTopic returns the associated partitioned topic string
// with the given public key.
func partitionedTopic(publicKey *ecdsa.PublicKey) string {
partition := big.NewInt(0)
partition.Mod(publicKey.X, nPartitions)
return "contact-discovery-" + strconv.FormatInt(partition.Int64(), 10)
}
func ContactCodeTopic(publicKey *ecdsa.PublicKey) string {
return contactCodeTopic(publicKey)
}
func contactCodeTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + publicKeyToStr(publicKey) + "-contact-code"
}
func negotiatedTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + publicKeyToStr(publicKey) + "-negotiated"
return s.filters[NegotiatedTopic(identity)]
}

View File

@ -1,4 +1,4 @@
package whisper
package transport
import (
"crypto/ecdsa"
@ -26,7 +26,7 @@ func TestFiltersManagerSuite(t *testing.T) {
type FiltersManagerSuite struct {
suite.Suite
chats *filtersManager
chats *FiltersManager
dbPath string
manager []*testKey
logger *zap.Logger
@ -77,7 +77,7 @@ func (s *FiltersManagerSuite) SetupTest() {
whisper := gethbridge.NewGethWhisperWrapper(whisper.New(nil))
s.chats, err = newFiltersManager(db, whisper, s.manager[0].privateKey, s.logger)
s.chats, err = NewFiltersManager(db, whisper, s.manager[0].privateKey, s.logger)
s.Require().NoError(err)
}

View File

@ -0,0 +1,13 @@
package transport
import "github.com/status-im/status-go/eth-node/types"
func DefaultMessage() types.NewMessage {
msg := types.NewMessage{}
msg.TTL = 10
msg.PowTarget = 0.002
msg.PowTime = 1
return msg
}

View File

@ -0,0 +1,59 @@
package transport
import (
"crypto/ecdsa"
"encoding/hex"
"math/big"
"strconv"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
const discoveryTopic = "contact-discovery"
var (
// The number of partitions.
nPartitions = big.NewInt(5000)
)
// ToTopic converts a string to a whisper topic.
func ToTopic(s string) []byte {
return crypto.Keccak256([]byte(s))[:types.TopicLength]
}
func StrToPublicKey(str string) (*ecdsa.PublicKey, error) {
publicKeyBytes, err := hex.DecodeString(str)
if err != nil {
return nil, err
}
return crypto.UnmarshalPubkey(publicKeyBytes)
}
func PublicKeyToStr(publicKey *ecdsa.PublicKey) string {
return hex.EncodeToString(crypto.FromECDSAPub(publicKey))
}
func PersonalDiscoveryTopic(publicKey *ecdsa.PublicKey) string {
return "contact-discovery-" + PublicKeyToStr(publicKey)
}
// PartitionedTopic returns the associated partitioned topic string
// with the given public key.
func PartitionedTopic(publicKey *ecdsa.PublicKey) string {
partition := big.NewInt(0)
partition.Mod(publicKey.X, nPartitions)
return "contact-discovery-" + strconv.FormatInt(partition.Int64(), 10)
}
func ContactCodeTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + PublicKeyToStr(publicKey) + "-contact-code"
}
func NegotiatedTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + PublicKeyToStr(publicKey) + "-negotiated"
}
func DiscoveryTopic() string {
return discoveryTopic
}

View File

@ -0,0 +1,38 @@
package transport
import (
"context"
"crypto/ecdsa"
"github.com/status-im/status-go/eth-node/types"
)
type Transport interface {
Stop() error
JoinPrivate(publicKey *ecdsa.PublicKey) error
LeavePrivate(publicKey *ecdsa.PublicKey) error
JoinGroup(publicKeys []*ecdsa.PublicKey) error
LeaveGroup(publicKeys []*ecdsa.PublicKey) error
JoinPublic(chatID string) error
LeavePublic(chatID string) error
SendPublic(ctx context.Context, newMessage *types.NewMessage, chatName string) ([]byte, error)
SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error)
SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error)
SendMessagesRequest(
ctx context.Context,
peerID []byte,
from, to uint32,
previousCursor []byte,
) (cursor []byte, err error)
Track(identifiers [][]byte, hash []byte, newMessage *types.NewMessage)
InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*Filter, error)
LoadFilters(filters []*Filter) ([]*Filter, error)
RemoveFilters(filters []*Filter) error
ResetFilters() error
ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*Filter, error)
RetrieveRawAll() (map[Filter][]*types.Message, error)
}

View File

@ -0,0 +1,310 @@
package waku
import (
"context"
"errors"
"sync"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/transport"
)
// EnvelopeState in local tracker
type EnvelopeState int
const (
// NotRegistered returned if asked hash wasn't registered in the tracker.
NotRegistered EnvelopeState = -1
// EnvelopePosted is set when envelope was added to a local waku queue.
EnvelopePosted EnvelopeState = iota
// EnvelopeSent is set when envelope is sent to at least one peer.
EnvelopeSent
)
// EnvelopeEventsHandler used for two different event types.
type EnvelopeEventsHandler interface {
EnvelopeSent([][]byte)
EnvelopeExpired([][]byte, error)
MailServerRequestCompleted(types.Hash, types.Hash, []byte, error)
MailServerRequestExpired(types.Hash)
}
// NewEnvelopesMonitor returns a pointer to an instance of the EnvelopesMonitor.
func NewEnvelopesMonitor(w types.Waku, config transport.EnvelopesMonitorConfig) *EnvelopesMonitor {
logger := config.Logger
if logger == nil {
logger = zap.NewNop()
}
var api types.PublicWakuAPI
if w != nil {
api = w.PublicWakuAPI()
}
return &EnvelopesMonitor{
w: w,
api: api,
handler: config.EnvelopeEventsHandler,
mailServerConfirmation: config.MailserverConfirmationsEnabled,
maxAttempts: config.MaxAttempts,
isMailserver: config.IsMailserver,
logger: logger.With(zap.Namespace("EnvelopesMonitor")),
// key is envelope hash (event.Hash)
envelopes: map[types.Hash]EnvelopeState{},
messages: map[types.Hash]*types.NewMessage{},
attempts: map[types.Hash]int{},
identifiers: make(map[types.Hash][][]byte),
// key is hash of the batch (event.Batch)
batches: map[types.Hash]map[types.Hash]struct{}{},
}
}
// EnvelopesMonitor is responsible for monitoring waku envelopes state.
type EnvelopesMonitor struct {
w types.Waku
api types.PublicWakuAPI
handler EnvelopeEventsHandler
mailServerConfirmation bool
maxAttempts int
mu sync.Mutex
envelopes map[types.Hash]EnvelopeState
batches map[types.Hash]map[types.Hash]struct{}
messages map[types.Hash]*types.NewMessage
attempts map[types.Hash]int
identifiers map[types.Hash][][]byte
wg sync.WaitGroup
quit chan struct{}
isMailserver func(peer types.EnodeID) bool
logger *zap.Logger
}
// Start processing events.
func (m *EnvelopesMonitor) Start() {
m.quit = make(chan struct{})
m.wg.Add(1)
go func() {
m.handleEnvelopeEvents()
m.wg.Done()
}()
}
// Stop process events.
func (m *EnvelopesMonitor) Stop() {
close(m.quit)
m.wg.Wait()
}
// Add hash to a tracker.
func (m *EnvelopesMonitor) Add(identifiers [][]byte, envelopeHash types.Hash, message types.NewMessage) {
m.mu.Lock()
defer m.mu.Unlock()
m.envelopes[envelopeHash] = EnvelopePosted
m.identifiers[envelopeHash] = identifiers
m.messages[envelopeHash] = &message
m.attempts[envelopeHash] = 1
}
func (m *EnvelopesMonitor) GetState(hash types.Hash) EnvelopeState {
m.mu.Lock()
defer m.mu.Unlock()
state, exist := m.envelopes[hash]
if !exist {
return NotRegistered
}
return state
}
// handleEnvelopeEvents processes waku envelope events
func (m *EnvelopesMonitor) handleEnvelopeEvents() {
events := make(chan types.EnvelopeEvent, 100) // must be buffered to prevent blocking waku
sub := m.w.SubscribeEnvelopeEvents(events)
defer func() {
close(events)
sub.Unsubscribe()
}()
for {
select {
case <-m.quit:
return
case event := <-events:
m.handleEvent(event)
}
}
}
// handleEvent based on type of the event either triggers
// confirmation handler or removes hash from tracker
func (m *EnvelopesMonitor) handleEvent(event types.EnvelopeEvent) {
handlers := map[types.EventType]func(types.EnvelopeEvent){
types.EventEnvelopeSent: m.handleEventEnvelopeSent,
types.EventEnvelopeExpired: m.handleEventEnvelopeExpired,
types.EventBatchAcknowledged: m.handleAcknowledgedBatch,
types.EventEnvelopeReceived: m.handleEventEnvelopeReceived,
}
if handler, ok := handlers[event.Event]; ok {
handler(event)
}
}
func (m *EnvelopesMonitor) handleEventEnvelopeSent(event types.EnvelopeEvent) {
if m.mailServerConfirmation {
if !m.isMailserver(event.Peer) {
return
}
}
m.mu.Lock()
defer m.mu.Unlock()
state, ok := m.envelopes[event.Hash]
// if we didn't send a message using extension - skip it
// if message was already confirmed - skip it
if !ok || state == EnvelopeSent {
return
}
m.logger.Debug("envelope is sent", zap.String("hash", event.Hash.String()), zap.String("peer", event.Peer.String()))
if event.Batch != (types.Hash{}) {
if _, ok := m.batches[event.Batch]; !ok {
m.batches[event.Batch] = map[types.Hash]struct{}{}
}
m.batches[event.Batch][event.Hash] = struct{}{}
m.logger.Debug("waiting for a confirmation", zap.String("batch", event.Batch.String()))
} else {
m.envelopes[event.Hash] = EnvelopeSent
if m.handler != nil {
m.handler.EnvelopeSent(m.identifiers[event.Hash])
}
}
}
func (m *EnvelopesMonitor) handleAcknowledgedBatch(event types.EnvelopeEvent) {
if m.mailServerConfirmation {
if !m.isMailserver(event.Peer) {
return
}
}
m.mu.Lock()
defer m.mu.Unlock()
envelopes, ok := m.batches[event.Batch]
if !ok {
m.logger.Debug("batch is not found", zap.String("batch", event.Batch.String()))
}
m.logger.Debug("received a confirmation", zap.String("batch", event.Batch.String()), zap.String("peer", event.Peer.String()))
envelopeErrors, ok := event.Data.([]types.EnvelopeError)
if event.Data != nil && !ok {
m.logger.Error("received unexpected data in the the confirmation event", zap.String("batch", event.Batch.String()))
}
failedEnvelopes := map[types.Hash]struct{}{}
for i := range envelopeErrors {
envelopeError := envelopeErrors[i]
_, exist := m.envelopes[envelopeError.Hash]
if exist {
m.logger.Warn("envelope that was posted by us is discarded", zap.String("hash", envelopeError.Hash.String()), zap.String("peer", event.Peer.String()), zap.String("error", envelopeError.Description))
var err error
switch envelopeError.Code {
case types.EnvelopeTimeNotSynced:
err = errors.New("envelope wasn't delivered due to time sync issues")
}
m.handleEnvelopeFailure(envelopeError.Hash, err)
}
failedEnvelopes[envelopeError.Hash] = struct{}{}
}
for hash := range envelopes {
if _, exist := failedEnvelopes[hash]; exist {
continue
}
state, ok := m.envelopes[hash]
if !ok || state == EnvelopeSent {
continue
}
m.envelopes[hash] = EnvelopeSent
if m.handler != nil {
m.handler.EnvelopeSent(m.identifiers[hash])
}
}
delete(m.batches, event.Batch)
}
func (m *EnvelopesMonitor) handleEventEnvelopeExpired(event types.EnvelopeEvent) {
m.mu.Lock()
defer m.mu.Unlock()
m.handleEnvelopeFailure(event.Hash, errors.New("envelope expired due to connectivity issues"))
}
// handleEnvelopeFailure is a common code path for processing envelopes failures. not thread safe, lock
// must be used on a higher level.
func (m *EnvelopesMonitor) handleEnvelopeFailure(hash types.Hash, err error) {
if state, ok := m.envelopes[hash]; ok {
message, exist := m.messages[hash]
if !exist {
m.logger.Error("message was deleted erroneously", zap.String("envelope hash", hash.String()))
}
attempt := m.attempts[hash]
identifiers := m.identifiers[hash]
m.clearMessageState(hash)
if state == EnvelopeSent {
return
}
if attempt < m.maxAttempts {
m.logger.Debug("retrying to send a message", zap.String("hash", hash.String()), zap.Int("attempt", attempt+1))
hex, err := m.api.Post(context.TODO(), *message)
if err != nil {
m.logger.Error("failed to retry sending message", zap.String("hash", hash.String()), zap.Int("attempt", attempt+1), zap.Error(err))
if m.handler != nil {
m.handler.EnvelopeExpired(identifiers, err)
}
}
envelopeID := types.BytesToHash(hex)
m.envelopes[envelopeID] = EnvelopePosted
m.messages[envelopeID] = message
m.attempts[envelopeID] = attempt + 1
m.identifiers[envelopeID] = identifiers
} else {
m.logger.Debug("envelope expired", zap.String("hash", hash.String()))
if m.handler != nil {
m.handler.EnvelopeExpired(identifiers, err)
}
}
}
}
func (m *EnvelopesMonitor) handleEventEnvelopeReceived(event types.EnvelopeEvent) {
if m.mailServerConfirmation {
if !m.isMailserver(event.Peer) {
return
}
}
m.mu.Lock()
defer m.mu.Unlock()
state, ok := m.envelopes[event.Hash]
if !ok || state != EnvelopePosted {
return
}
m.logger.Debug("expected envelope received", zap.String("hash", event.Hash.String()), zap.String("peer", event.Peer.String()))
m.envelopes[event.Hash] = EnvelopeSent
if m.handler != nil {
m.handler.EnvelopeSent(m.identifiers[event.Hash])
}
}
// clearMessageState removes all message and envelope state.
// not thread-safe, should be protected on a higher level.
func (m *EnvelopesMonitor) clearMessageState(envelopeID types.Hash) {
delete(m.envelopes, envelopeID)
delete(m.messages, envelopeID)
delete(m.attempts, envelopeID)
delete(m.identifiers, envelopeID)
}

View File

@ -0,0 +1,120 @@
package waku
import (
"testing"
"go.uber.org/zap"
"github.com/stretchr/testify/suite"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
var (
testHash = types.Hash{0x01}
testIDs = [][]byte{[]byte("id")}
)
type EnvelopesMonitorSuite struct {
suite.Suite
monitor *EnvelopesMonitor
}
func TestEnvelopesMonitorSuite(t *testing.T) {
suite.Run(t, new(EnvelopesMonitorSuite))
}
func (s *EnvelopesMonitorSuite) SetupTest() {
s.monitor = NewEnvelopesMonitor(
nil,
EnvelopesMonitorConfig{
EnvelopeEventsHandler: nil,
MaxAttempts: 0,
MailserverConfirmationsEnabled: false,
IsMailserver: func(types.EnodeID) bool { return false },
Logger: zap.NewNop(),
},
)
}
func (s *EnvelopesMonitorSuite) TestConfirmed() {
s.monitor.Add(testIDs, testHash, types.NewMessage{})
s.Contains(s.monitor.envelopes, testHash)
s.Equal(EnvelopePosted, s.monitor.envelopes[testHash])
s.monitor.handleEvent(types.EnvelopeEvent{
Event: types.EventEnvelopeSent,
Hash: testHash,
})
s.Contains(s.monitor.envelopes, testHash)
s.Equal(EnvelopeSent, s.monitor.envelopes[testHash])
}
func (s *EnvelopesMonitorSuite) TestConfirmedWithAcknowledge() {
testBatch := types.Hash{1}
pkey, err := crypto.GenerateKey()
s.Require().NoError(err)
node := enode.NewV4(&pkey.PublicKey, nil, 0, 0)
s.monitor.Add(testIDs, testHash, types.NewMessage{})
s.Contains(s.monitor.envelopes, testHash)
s.Equal(EnvelopePosted, s.monitor.envelopes[testHash])
s.monitor.handleEvent(types.EnvelopeEvent{
Event: types.EventEnvelopeSent,
Hash: testHash,
Batch: testBatch,
})
s.Equal(EnvelopePosted, s.monitor.envelopes[testHash])
s.monitor.handleEvent(types.EnvelopeEvent{
Event: types.EventBatchAcknowledged,
Batch: testBatch,
Peer: types.EnodeID(node.ID()),
})
s.Contains(s.monitor.envelopes, testHash)
s.Equal(EnvelopeSent, s.monitor.envelopes[testHash])
}
func (s *EnvelopesMonitorSuite) TestIgnored() {
s.monitor.handleEvent(types.EnvelopeEvent{
Event: types.EventEnvelopeSent,
Hash: testHash,
})
s.NotContains(s.monitor.envelopes, testHash)
}
func (s *EnvelopesMonitorSuite) TestRemoved() {
s.monitor.Add(testIDs, testHash, types.NewMessage{})
s.Contains(s.monitor.envelopes, testHash)
s.monitor.handleEvent(types.EnvelopeEvent{
Event: types.EventEnvelopeExpired,
Hash: testHash,
})
s.NotContains(s.monitor.envelopes, testHash)
}
func (s *EnvelopesMonitorSuite) TestIgnoreNotFromMailserver() {
// enables filter in the tracker to drop confirmations from non-mailserver peers
s.monitor.mailServerConfirmation = true
s.monitor.Add(testIDs, testHash, types.NewMessage{})
s.monitor.handleEvent(types.EnvelopeEvent{
Event: types.EventEnvelopeSent,
Hash: testHash,
Peer: types.EnodeID{1}, // could be empty, doesn't impact test behaviour
})
s.Require().Equal(EnvelopePosted, s.monitor.GetState(testHash))
}
func (s *EnvelopesMonitorSuite) TestReceived() {
s.monitor.isMailserver = func(peer types.EnodeID) bool {
return true
}
s.monitor.Add(testIDs, testHash, types.NewMessage{})
s.Contains(s.monitor.envelopes, testHash)
s.monitor.handleEvent(types.EnvelopeEvent{
Event: types.EventEnvelopeReceived,
Hash: testHash,
})
s.Require().Equal(EnvelopeSent, s.monitor.GetState(testHash))
}

View File

@ -0,0 +1,38 @@
package waku
import (
"encoding/hex"
"math/big"
"github.com/google/uuid"
"github.com/status-im/status-go/eth-node/types"
)
func createMessagesRequest(from, to uint32, cursor []byte, topics []types.TopicType) types.MessagesRequest {
aUUID := uuid.New()
// uuid is 16 bytes, converted to hex it's 32 bytes as expected by types.MessagesRequest
id := []byte(hex.EncodeToString(aUUID[:]))
return types.MessagesRequest{
ID: id,
From: from,
To: to,
Limit: 100,
Cursor: cursor,
Bloom: topicsToBloom(topics...),
}
}
func topicsToBloom(topics ...types.TopicType) []byte {
i := new(big.Int)
for _, topic := range topics {
bloom := types.TopicToBloom(topic)
i.Or(i, new(big.Int).SetBytes(bloom[:]))
}
combined := make([]byte, types.BloomFilterSize)
data := i.Bytes()
copy(combined[types.BloomFilterSize-len(data):], data[:])
return combined
}

View File

@ -0,0 +1,319 @@
// Code generated by go-bindata. DO NOT EDIT.
// sources:
// 1561059284_add_waku_keys.down.sql (22B)
// 1561059284_add_waku_keys.up.sql (109B)
// doc.go (373B)
package sqlite
import (
"bytes"
"compress/gzip"
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
}
if clErr != nil {
return nil, err
}
return buf.Bytes(), nil
}
type asset struct {
bytes []byte
info os.FileInfo
digest [sha256.Size]byte
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
func (fi bindataFileInfo) Name() string {
return fi.name
}
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
func (fi bindataFileInfo) IsDir() bool {
return false
}
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
var __1561059284_add_waku_keysDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x28\x4f\xcc\x2e\x8d\xcf\x4e\xad\x2c\xb6\xe6\x02\x04\x00\x00\xff\xff\x4f\x00\xe6\x8e\x16\x00\x00\x00")
func _1561059284_add_waku_keysDownSqlBytes() ([]byte, error) {
return bindataRead(
__1561059284_add_waku_keysDownSql,
"1561059284_add_waku_keys.down.sql",
)
}
func _1561059284_add_waku_keysDownSql() (*asset, error) {
bytes, err := _1561059284_add_waku_keysDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1561059284_add_waku_keys.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1578604329, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0x2a, 0x7e, 0x9, 0xa3, 0xdd, 0xc6, 0x3, 0xfa, 0xaa, 0x98, 0xa0, 0x26, 0x5e, 0x67, 0x43, 0xe6, 0x20, 0xfd, 0x10, 0xfd, 0x60, 0x89, 0x17, 0x13, 0x87, 0x1b, 0x44, 0x36, 0x79, 0xb6, 0x60}}
return a, nil
}
var __1561059284_add_waku_keysUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x04\xc0\xb1\x0a\xc2\x40\x0c\x06\xe0\xfd\x9e\xe2\x1f\x15\x7c\x03\xa7\xbb\x33\x6a\x30\x26\x12\x52\x6a\xa7\x52\xb4\xa0\xdc\xa8\x22\x7d\xfb\x7e\xd5\x29\x07\x21\x72\x11\xc2\x7f\x6a\xbf\xb1\xcd\xcb\x07\x9b\x04\x3c\x5e\xd3\x77\x7c\x3f\x11\x74\x0f\xdc\x9c\xaf\xd9\x07\x5c\x68\x80\x29\xaa\xe9\x51\xb8\x06\xf8\xa4\xe6\xb4\x4b\x40\x9b\x17\x14\xb1\x02\xb5\x80\x76\x22\x69\x8b\x9e\xe3\x6c\x5d\xc0\xad\xe7\xc3\x3e\xad\x01\x00\x00\xff\xff\xbc\x45\x31\x54\x6d\x00\x00\x00")
func _1561059284_add_waku_keysUpSqlBytes() ([]byte, error) {
return bindataRead(
__1561059284_add_waku_keysUpSql,
"1561059284_add_waku_keys.up.sql",
)
}
func _1561059284_add_waku_keysUpSql() (*asset, error) {
bytes, err := _1561059284_add_waku_keysUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1561059284_add_waku_keys.up.sql", size: 109, mode: os.FileMode(0644), modTime: time.Unix(1578604337, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x5c, 0x8, 0x32, 0xef, 0x12, 0x88, 0x21, 0xd, 0x7a, 0x42, 0x4d, 0xe7, 0x2d, 0x6c, 0x99, 0xb6, 0x1, 0xf1, 0xba, 0x2c, 0x40, 0x8d, 0xa9, 0x4b, 0xe6, 0xc4, 0x21, 0xec, 0x47, 0x6b, 0xf7}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\x3d\x72\xeb\x30\x0c\x84\x7b\x9d\x62\xc7\x8d\x9b\x27\xb2\x79\x55\xba\x94\xe9\x73\x01\x98\x5a\x91\x18\x4b\xa4\x42\xc0\x7f\xb7\xcf\xc8\xe3\xc2\x5d\xda\x1d\x7c\x1f\x76\x63\xc4\x77\x51\xc3\xac\x0b\xa1\x86\xca\x44\x33\xe9\x0f\x9c\x98\xe4\x62\xc4\x21\xab\x97\xcb\x29\xa4\xb6\x46\x73\xf1\x8b\x8d\xba\xc6\x55\x73\x17\x67\xbc\xfe\x3f\x0c\x31\x22\x49\x3d\x3a\x8a\xd4\x69\xe1\xd3\x65\x30\x97\xee\x5a\x33\x6e\xea\x05\x82\xad\x73\xd6\x7b\xc0\xa7\x63\xa1\x98\xc3\x8b\xf8\xd1\xe0\x85\x48\x62\xdc\x35\x73\xeb\xc8\x6d\x3c\x69\x9d\xc4\x25\xec\xd1\xd7\xfc\x96\xec\x0d\x93\x2c\x0b\x27\xcc\xbd\xad\x4f\xd6\x64\x25\x26\xed\x4c\xde\xfa\xe3\x1f\xc4\x8c\x8e\x2a\x2b\x6d\xe7\x8b\x5c\x89\xda\x5e\xef\x21\x75\xfa\x7b\x11\x6e\xad\x9f\x0d\x62\xe0\x7d\x63\x72\x4e\x61\x18\x36\x49\x67\xc9\x84\xfd\x2c\xea\x1c\x86\x18\x73\xfb\xc8\xac\xdc\xa9\xf7\x8e\xe3\x76\xce\xaf\x2b\x8c\x0d\x21\xbc\xd4\xda\xaa\x85\xdc\x10\x86\xdf\x00\x00\x00\xff\xff\x21\xa5\x75\x05\x75\x01\x00\x00")
func docGoBytes() ([]byte, error) {
return bindataRead(
_docGo,
"doc.go",
)
}
func docGo() (*asset, error) {
bytes, err := docGoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1578604293, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x23, 0x6a, 0xc1, 0xce, 0x94, 0xf6, 0xef, 0xf1, 0x97, 0x95, 0xb, 0x35, 0xaf, 0x5f, 0xe7, 0x5f, 0xac, 0x6e, 0xb8, 0xab, 0xba, 0xb5, 0x35, 0x97, 0x22, 0x36, 0x11, 0xce, 0x44, 0xfc, 0xfa, 0xac}}
return a, nil
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}
return a.bytes, nil
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// AssetString returns the asset contents as a string (instead of a []byte).
func AssetString(name string) (string, error) {
data, err := Asset(name)
return string(data), err
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
a, err := Asset(name)
if err != nil {
panic("asset: Asset(" + name + "): " + err.Error())
}
return a
}
// MustAssetString is like AssetString but panics when Asset would return an
// error. It simplifies safe initialization of global variables.
func MustAssetString(name string) string {
return string(MustAsset(name))
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}
return a.info, nil
}
return nil, fmt.Errorf("AssetInfo %s not found", name)
}
// AssetDigest returns the digest of the file with the given name. It returns an
// error if the asset could not be found or the digest could not be loaded.
func AssetDigest(name string) ([sha256.Size]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err)
}
return a.digest, nil
}
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name)
}
// Digests returns a map of all known files and their checksums.
func Digests() (map[string][sha256.Size]byte, error) {
mp := make(map[string][sha256.Size]byte, len(_bindata))
for name := range _bindata {
a, err := _bindata[name]()
if err != nil {
return nil, err
}
mp[name] = a.digest
}
return mp, nil
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"1561059284_add_waku_keys.down.sql": _1561059284_add_waku_keysDownSql,
"1561059284_add_waku_keys.up.sql": _1561059284_add_waku_keysUpSql,
"doc.go": docGo,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"},
// AssetDir("data/img") would return []string{"a.png", "b.png"},
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
canonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(canonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for childName := range node.Children {
rv = append(rv, childName)
}
return rv, nil
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"1561059284_add_waku_keys.down.sql": &bintree{_1561059284_add_waku_keysDownSql, map[string]*bintree{}},
"1561059284_add_waku_keys.up.sql": &bintree{_1561059284_add_waku_keysUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory.
func RestoreAsset(dir, name string) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}
return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
}
// RestoreAssets restores an asset under the given directory recursively.
func RestoreAssets(dir, name string) error {
children, err := AssetDir(name)
// File
if err != nil {
return RestoreAsset(dir, name)
}
// Dir
for _, child := range children {
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil {
return err
}
}
return nil
}
func _filePath(dir, name string) string {
canonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
}

View File

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

View File

@ -0,0 +1,4 @@
CREATE TABLE waku_keys (
chat_id TEXT PRIMARY KEY ON CONFLICT IGNORE,
key BLOB NOT NULL
) WITHOUT ROWID;

View File

@ -0,0 +1,9 @@
// This file is necessary because "github.com/status-im/migrate/v4"
// can't handle files starting with a prefix. At least that's the case
// for go-bindata.
// If go-bindata is called from the same directory, asset names
// have no prefix and "github.com/status-im/migrate/v4" works as expected.
package sqlite
//go:generate go-bindata -pkg sqlite -o ../migrations.go .

View File

@ -0,0 +1,57 @@
package waku
import (
"database/sql"
)
type sqlitePersistence struct {
db *sql.DB
}
func newSQLitePersistence(db *sql.DB) *sqlitePersistence {
return &sqlitePersistence{db: db}
}
func (s *sqlitePersistence) Add(chatID string, key []byte) error {
statement := "INSERT INTO waku_keys(chat_id, key) VALUES(?, ?)"
stmt, err := s.db.Prepare(statement)
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(chatID, key)
return err
}
func (s *sqlitePersistence) All() (map[string][]byte, error) {
keys := make(map[string][]byte)
statement := "SELECT chat_id, key FROM waku_keys"
stmt, err := s.db.Prepare(statement)
if err != nil {
return nil, err
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil && err != sql.ErrNoRows {
return nil, err
}
for rows.Next() {
var (
chatID string
key []byte
)
err := rows.Scan(&chatID, &key)
if err != nil {
return nil, err
}
keys[chatID] = key
}
return keys, nil
}

View File

@ -0,0 +1,13 @@
package waku
import (
"github.com/status-im/status-go/eth-node/types"
)
type RequestOptions struct {
Topics []types.TopicType
Password string
Limit int
From int64 // in seconds
To int64 // in seconds
}

View File

@ -0,0 +1,426 @@
package waku
import (
"bytes"
"context"
"crypto/ecdsa"
"database/sql"
"sync"
"github.com/pkg/errors"
"go.uber.org/zap"
"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/transport"
)
var (
// ErrNoMailservers returned if there is no configured mailservers that can be used.
ErrNoMailservers = errors.New("no configured mailservers")
)
type wakuServiceKeysManager struct {
waku types.Waku
// Identity of the current user.
privateKey *ecdsa.PrivateKey
passToSymKeyMutex sync.RWMutex
passToSymKeyCache map[string]string
}
func (m *wakuServiceKeysManager) AddOrGetKeyPair(priv *ecdsa.PrivateKey) (string, error) {
// caching is handled in waku
return m.waku.AddKeyPair(priv)
}
func (m *wakuServiceKeysManager) AddOrGetSymKeyFromPassword(password string) (string, error) {
m.passToSymKeyMutex.Lock()
defer m.passToSymKeyMutex.Unlock()
if val, ok := m.passToSymKeyCache[password]; ok {
return val, nil
}
id, err := m.waku.AddSymKeyFromPassword(password)
if err != nil {
return id, err
}
m.passToSymKeyCache[password] = id
return id, nil
}
func (m *wakuServiceKeysManager) RawSymKey(id string) ([]byte, error) {
return m.waku.GetSymKey(id)
}
type Option func(*WakuServiceTransport) error
// WakuServiceTransport is a transport based on Whisper service.
type WakuServiceTransport struct {
waku types.Waku
api types.PublicWakuAPI // only PublicWakuAPI implements logic to send messages
keysManager *wakuServiceKeysManager
filters *transport.FiltersManager
logger *zap.Logger
mailservers []string
envelopesMonitor *EnvelopesMonitor
}
// NewWakuServiceTransport returns a new WakuServiceTransport.
// TODO: leaving a chat should verify that for a given public key
// there are no other chats. It may happen that we leave a private chat
// but still have a public chat for a given public key.
func NewWakuServiceTransport(
waku types.Waku,
privateKey *ecdsa.PrivateKey,
db *sql.DB,
mailservers []string,
envelopesMonitorConfig *transport.EnvelopesMonitorConfig,
logger *zap.Logger,
opts ...Option,
) (*WakuServiceTransport, error) {
filtersManager, err := transport.NewFiltersManager(newSQLitePersistence(db), waku, privateKey, logger)
if err != nil {
return nil, err
}
var envelopesMonitor *EnvelopesMonitor
if envelopesMonitorConfig != nil {
envelopesMonitor = NewEnvelopesMonitor(waku, *envelopesMonitorConfig)
envelopesMonitor.Start()
}
var api types.PublicWhisperAPI
if waku != nil {
api = waku.PublicWakuAPI()
}
t := &WakuServiceTransport{
waku: waku,
api: api,
envelopesMonitor: envelopesMonitor,
keysManager: &wakuServiceKeysManager{
waku: waku,
privateKey: privateKey,
passToSymKeyCache: make(map[string]string),
},
filters: filtersManager,
mailservers: mailservers,
logger: logger.With(zap.Namespace("WakuServiceTransport")),
}
for _, opt := range opts {
if err := opt(t); err != nil {
return nil, err
}
}
return t, nil
}
func (a *WakuServiceTransport) InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) {
return a.filters.Init(chatIDs, publicKeys)
}
func (a *WakuServiceTransport) Filters() []*transport.Filter {
return a.filters.Filters()
}
// DEPRECATED
func (a *WakuServiceTransport) LoadFilters(filters []*transport.Filter) ([]*transport.Filter, error) {
return a.filters.InitWithFilters(filters)
}
// DEPRECATED
func (a *WakuServiceTransport) RemoveFilters(filters []*transport.Filter) error {
return a.filters.Remove(filters...)
}
func (a *WakuServiceTransport) ResetFilters() error {
return a.filters.Reset()
}
func (a *WakuServiceTransport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*transport.Filter, error) {
filter, err := a.filters.LoadNegotiated(secret)
if err != nil {
return nil, err
}
return filter, nil
}
func (a *WakuServiceTransport) JoinPublic(chatID string) error {
_, err := a.filters.LoadPublic(chatID)
return err
}
func (a *WakuServiceTransport) LeavePublic(chatID string) error {
chat := a.filters.Filter(chatID)
if chat != nil {
return nil
}
return a.filters.Remove(chat)
}
func (a *WakuServiceTransport) JoinPrivate(publicKey *ecdsa.PublicKey) error {
_, err := a.filters.LoadDiscovery()
if err != nil {
return err
}
_, err = a.filters.LoadContactCode(publicKey)
return err
}
func (a *WakuServiceTransport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
filters := a.filters.FiltersByPublicKey(publicKey)
return a.filters.Remove(filters...)
}
func (a *WakuServiceTransport) JoinGroup(publicKeys []*ecdsa.PublicKey) error {
_, err := a.filters.LoadDiscovery()
if err != nil {
return err
}
for _, pk := range publicKeys {
_, err = a.filters.LoadContactCode(pk)
if err != nil {
return err
}
}
return nil
}
func (a *WakuServiceTransport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error {
for _, publicKey := range publicKeys {
filters := a.filters.FiltersByPublicKey(publicKey)
if err := a.filters.Remove(filters...); err != nil {
return err
}
}
return nil
}
type Message struct {
Message *types.Message
Public bool
}
func (a *WakuServiceTransport) RetrieveAllMessages() ([]Message, error) {
var messages []Message
for _, filter := range a.filters.Filters() {
filterMsgs, err := a.api.GetFilterMessages(filter.FilterID)
if err != nil {
return nil, err
}
for _, m := range filterMsgs {
messages = append(messages, Message{
Message: m,
Public: filter.IsPublic(),
})
}
}
return messages, nil
}
func (a *WakuServiceTransport) RetrievePublicMessages(chatID string) ([]*types.Message, error) {
filter, err := a.filters.LoadPublic(chatID)
if err != nil {
return nil, err
}
return a.api.GetFilterMessages(filter.FilterID)
}
func (a *WakuServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]*types.Message, error) {
chats := a.filters.FiltersByPublicKey(publicKey)
discoveryChats, err := a.filters.Init(nil, nil)
if err != nil {
return nil, err
}
var result []*types.Message
for _, chat := range append(chats, discoveryChats...) {
filterMsgs, err := a.api.GetFilterMessages(chat.FilterID)
if err != nil {
return nil, err
}
result = append(result, filterMsgs...)
}
return result, nil
}
func (a *WakuServiceTransport) RetrieveRawAll() (map[transport.Filter][]*types.Message, error) {
result := make(map[transport.Filter][]*types.Message)
allFilters := a.filters.Filters()
for _, filter := range allFilters {
msgs, err := a.api.GetFilterMessages(filter.FilterID)
if err != nil {
continue
}
result[*filter] = append(result[*filter], msgs...)
}
return result, nil
}
// SendPublic sends a new message using the Whisper service.
// For public filters, chat name is used as an ID as well as
// a topic.
func (a *WakuServiceTransport) SendPublic(ctx context.Context, newMessage *types.NewMessage, chatName string) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
filter, err := a.filters.LoadPublic(chatName)
if err != nil {
return nil, err
}
newMessage.SymKeyID = filter.SymKeyID
newMessage.Topic = filter.Topic
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
filter, err := a.filters.LoadNegotiated(types.NegotiatedSecret{
PublicKey: publicKey,
Key: secret,
})
if err != nil {
return nil, err
}
newMessage.SymKeyID = filter.SymKeyID
newMessage.Topic = filter.Topic
newMessage.PublicKey = nil
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
filter, err := a.filters.LoadPartitioned(publicKey)
if err != nil {
return nil, err
}
newMessage.Topic = filter.Topic
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) SendPrivateOnDiscovery(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
// There is no need to load any chat
// because listening on the discovery topic
// is done automatically.
// TODO: change this anyway, it should be explicit
// and idempotent.
newMessage.Topic = types.BytesToTopic(transport.ToTopic(transport.DiscoveryTopic()))
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) addSig(newMessage *types.NewMessage) error {
sigID, err := a.keysManager.AddOrGetKeyPair(a.keysManager.privateKey)
if err != nil {
return err
}
newMessage.SigID = sigID
return nil
}
func (a *WakuServiceTransport) Track(identifiers [][]byte, hash []byte, newMessage *types.NewMessage) {
if a.envelopesMonitor != nil {
a.envelopesMonitor.Add(identifiers, types.BytesToHash(hash), *newMessage)
}
}
func (a *WakuServiceTransport) Stop() error {
if a.envelopesMonitor != nil {
a.envelopesMonitor.Stop()
}
return nil
}
// RequestHistoricMessages requests historic messages for all registered filters.
func (a *WakuServiceTransport) SendMessagesRequest(
ctx context.Context,
peerID []byte,
from, to uint32,
previousCursor []byte,
) (cursor []byte, err error) {
topics := make([]types.TopicType, len(a.Filters()))
for _, f := range a.Filters() {
topics = append(topics, f.Topic)
}
r := createMessagesRequest(from, to, previousCursor, topics)
r.SetDefaults(a.waku.GetCurrentTime())
events := make(chan types.EnvelopeEvent, 10)
sub := a.waku.SubscribeEnvelopeEvents(events)
defer sub.Unsubscribe()
err = a.waku.SendMessagesRequest(peerID, r)
if err != nil {
return
}
resp, err := a.waitForRequestCompleted(ctx, r.ID, events)
if err == nil && resp != nil && resp.Error != nil {
err = resp.Error
} else if err == nil && resp != nil {
cursor = resp.Cursor
}
return
}
func (a *WakuServiceTransport) waitForRequestCompleted(ctx context.Context, requestID []byte, events chan types.EnvelopeEvent) (*types.MailServerResponse, error) {
for {
select {
case ev := <-events:
a.logger.Debug(
"waiting for request completed and received an event",
zap.Binary("requestID", requestID),
zap.Any("event", ev),
)
if !bytes.Equal(ev.Hash.Bytes(), requestID) {
continue
}
if ev.Event != types.EventMailServerRequestCompleted {
continue
}
data, ok := ev.Data.(*types.MailServerResponse)
if ok {
return data, nil
}
case <-ctx.Done():
return nil, ctx.Err()
}
}
}

View File

@ -0,0 +1,28 @@
package waku
import (
"io/ioutil"
"os"
"testing"
"github.com/status-im/status-go/protocol/sqlite"
"github.com/stretchr/testify/require"
"github.com/status-im/status-go/protocol/tt"
)
func TestNewWakuServiceTransport(t *testing.T) {
dbPath, err := ioutil.TempFile("", "transport.sql")
require.NoError(t, err)
defer os.Remove(dbPath.Name())
db, err := sqlite.Open(dbPath.Name(), "some-key")
require.NoError(t, err)
logger := tt.MustCreateTestLogger()
require.NoError(t, err)
defer func() { _ = logger.Sync() }()
_, err = NewWakuServiceTransport(nil, nil, db, nil, nil, logger)
require.NoError(t, err)
}

View File

@ -5,6 +5,8 @@ import (
"errors"
"sync"
"github.com/status-im/status-go/protocol/transport"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/types"
@ -18,18 +20,10 @@ const (
NotRegistered EnvelopeState = -1
// EnvelopePosted is set when envelope was added to a local whisper queue.
EnvelopePosted EnvelopeState = iota
// EnvelopeSent is set when envelope is sent to atleast one peer.
// EnvelopeSent is set when envelope is sent to at least one peer.
EnvelopeSent
)
type EnvelopesMonitorConfig struct {
EnvelopeEventsHandler EnvelopeEventsHandler
MaxAttempts int
MailserverConfirmationsEnabled bool
IsMailserver func(types.EnodeID) bool
Logger *zap.Logger
}
// EnvelopeEventsHandler used for two different event types.
type EnvelopeEventsHandler interface {
EnvelopeSent([][]byte)
@ -39,7 +33,7 @@ type EnvelopeEventsHandler interface {
}
// NewEnvelopesMonitor returns a pointer to an instance of the EnvelopesMonitor.
func NewEnvelopesMonitor(w types.Whisper, config EnvelopesMonitorConfig) *EnvelopesMonitor {
func NewEnvelopesMonitor(w types.Whisper, config transport.EnvelopesMonitorConfig) *EnvelopesMonitor {
logger := config.Logger
if logger == nil {

View File

@ -9,8 +9,6 @@ import (
"github.com/status-im/status-go/eth-node/types"
)
const defaultMessagesRequestLimit = 100
func createMessagesRequest(from, to uint32, cursor []byte, topics []types.TopicType) types.MessagesRequest {
aUUID := uuid.New()
// uuid is 16 bytes, converted to hex it's 32 bytes as expected by types.MessagesRequest
@ -19,7 +17,7 @@ func createMessagesRequest(from, to uint32, cursor []byte, topics []types.TopicT
ID: id,
From: from,
To: to,
Limit: defaultMessagesRequestLimit,
Limit: 100,
Cursor: cursor,
Bloom: topicsToBloom(topics...),
}

View File

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

View File

@ -11,17 +11,3 @@ type RequestOptions struct {
From int64 // in seconds
To int64 // in seconds
}
const (
defaultPowTime = 1
)
func DefaultWhisperMessage() types.NewMessage {
msg := types.NewMessage{}
msg.TTL = 10
msg.PowTarget = 0.002
msg.PowTime = defaultPowTime
return msg
}

View File

@ -12,6 +12,7 @@ import (
"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/transport"
)
var (
@ -63,7 +64,7 @@ type WhisperServiceTransport struct {
shh types.Whisper
shhAPI types.PublicWhisperAPI // only PublicWhisperAPI implements logic to send messages
keysManager *whisperServiceKeysManager
filters *filtersManager
filters *transport.FiltersManager
logger *zap.Logger
mailservers []string
@ -79,11 +80,11 @@ func NewWhisperServiceTransport(
privateKey *ecdsa.PrivateKey,
db *sql.DB,
mailservers []string,
envelopesMonitorConfig *EnvelopesMonitorConfig,
envelopesMonitorConfig *transport.EnvelopesMonitorConfig,
logger *zap.Logger,
opts ...Option,
) (*WhisperServiceTransport, error) {
filtersManager, err := newFiltersManager(db, shh, privateKey, logger)
filtersManager, err := transport.NewFiltersManager(newSQLitePersistence(db), shh, privateKey, logger)
if err != nil {
return nil, err
}
@ -121,29 +122,29 @@ func NewWhisperServiceTransport(
return t, nil
}
func (a *WhisperServiceTransport) InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*Filter, error) {
func (a *WhisperServiceTransport) InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) {
return a.filters.Init(chatIDs, publicKeys)
}
func (a *WhisperServiceTransport) Filters() []*Filter {
func (a *WhisperServiceTransport) Filters() []*transport.Filter {
return a.filters.Filters()
}
// DEPRECATED
func (a *WhisperServiceTransport) LoadFilters(filters []*Filter) ([]*Filter, error) {
func (a *WhisperServiceTransport) LoadFilters(filters []*transport.Filter) ([]*transport.Filter, error) {
return a.filters.InitWithFilters(filters)
}
// DEPRECATED
func (a *WhisperServiceTransport) RemoveFilters(filters []*Filter) error {
func (a *WhisperServiceTransport) RemoveFilters(filters []*transport.Filter) error {
return a.filters.Remove(filters...)
}
func (a *WhisperServiceTransport) Reset() error {
func (a *WhisperServiceTransport) ResetFilters() error {
return a.filters.Reset()
}
func (a *WhisperServiceTransport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*Filter, error) {
func (a *WhisperServiceTransport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*transport.Filter, error) {
filter, err := a.filters.LoadNegotiated(secret)
if err != nil {
return nil, err
@ -257,8 +258,8 @@ func (a *WhisperServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.Publi
return result, nil
}
func (a *WhisperServiceTransport) RetrieveRawAll() (map[Filter][]*types.Message, error) {
result := make(map[Filter][]*types.Message)
func (a *WhisperServiceTransport) RetrieveRawAll() (map[transport.Filter][]*types.Message, error) {
result := make(map[transport.Filter][]*types.Message)
allFilters := a.filters.Filters()
for _, filter := range allFilters {
@ -338,9 +339,7 @@ func (a *WhisperServiceTransport) SendPrivateOnDiscovery(ctx context.Context, ne
// TODO: change this anyway, it should be explicit
// and idempotent.
newMessage.Topic = types.BytesToTopic(
ToTopic(discoveryTopic),
)
newMessage.Topic = types.BytesToTopic(transport.ToTopic(transport.DiscoveryTopic()))
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
return a.shhAPI.Post(ctx, *newMessage)

View File

@ -21,7 +21,7 @@ import (
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
statustransp "github.com/status-im/status-go/protocol/transport/whisper"
"github.com/status-im/status-go/protocol/transport"
)
const (
@ -429,7 +429,7 @@ func (s *Service) addressString() string {
// postPing publishes a whisper message
func (s *Service) postPing() (types.HexBytes, error) {
msg := statustransp.DefaultWhisperMessage()
msg := transport.DefaultMessage()
msg.Topic = toWhisperTopic(defaultTopic)

View File

@ -24,7 +24,7 @@ import (
enstypes "github.com/status-im/status-go/eth-node/types/ens"
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/encryption/multidevice"
statustransp "github.com/status-im/status-go/protocol/transport/whisper"
"github.com/status-im/status-go/protocol/transport"
)
const (
@ -601,7 +601,7 @@ func (api *PublicAPI) CompleteRequest(parent context.Context, hex string) (err e
return err
}
func (api *PublicAPI) LoadFilters(parent context.Context, chats []*statustransp.Filter) ([]*statustransp.Filter, error) {
func (api *PublicAPI) LoadFilters(parent context.Context, chats []*transport.Filter) ([]*transport.Filter, error) {
return api.service.messenger.LoadFilters(chats)
}
@ -631,7 +631,7 @@ func (api *PublicAPI) Contacts(parent context.Context) []*protocol.Contact {
return api.service.messenger.Contacts()
}
func (api *PublicAPI) RemoveFilters(parent context.Context, chats []*statustransp.Filter) error {
func (api *PublicAPI) RemoveFilters(parent context.Context, chats []*transport.Filter) error {
return api.service.messenger.RemoveFilters(chats)
}
@ -752,6 +752,7 @@ func makeEnvelop(
pow float64,
now time.Time,
) (types.Envelope, error) {
// TODO: replace with an types.Envelope creator passed to the API struct
params := whisper.MessageParams{
PoW: pow,
Payload: payload,

View File

@ -32,8 +32,8 @@ import (
coretypes "github.com/status-im/status-go/eth-node/core/types"
"github.com/status-im/status-go/eth-node/types"
protocol "github.com/status-im/status-go/protocol"
protocolwhisper "github.com/status-im/status-go/protocol/transport/whisper"
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/transport"
)
const (
@ -53,10 +53,10 @@ type EnvelopeEventsHandler interface {
// Service is a service that provides some additional Whisper API.
type Service struct {
messenger *protocol.Messenger
identity *ecdsa.PrivateKey
cancelMessenger chan struct{}
apiName string
messenger *protocol.Messenger
identity *ecdsa.PrivateKey
cancelMessenger chan struct{}
storage db.TransactionalStorage
n types.Node
w types.Whisper
@ -77,7 +77,7 @@ type Service struct {
var _ node.Service = (*Service)(nil)
// New returns a new shhext Service.
func New(n types.Node, ctx interface{}, handler EnvelopeEventsHandler, ldb *leveldb.DB, config params.ShhextConfig) *Service {
func New(n types.Node, ctx interface{}, apiName string, handler EnvelopeEventsHandler, ldb *leveldb.DB, config params.ShhextConfig) *Service {
w, err := n.GetWhisper(ctx)
if err != nil {
panic(err)
@ -97,6 +97,7 @@ func New(n types.Node, ctx interface{}, handler EnvelopeEventsHandler, ldb *leve
requestsRegistry: requestsRegistry,
}
return &Service{
apiName: apiName,
storage: db.NewLevelDBStorage(ldb),
n: n,
w: w,
@ -137,7 +138,7 @@ func (s *Service) InitProtocol(identity *ecdsa.PrivateKey, db *sql.DB) error { /
return err
}
envelopesMonitorConfig := &protocolwhisper.EnvelopesMonitorConfig{
envelopesMonitorConfig := &transport.EnvelopesMonitorConfig{
MaxAttempts: s.config.MaxMessageDeliveryAttempts,
MailserverConfirmationsEnabled: s.config.MailServerConfirmations,
IsMailserver: func(peer types.EnodeID) bool {
@ -297,7 +298,7 @@ func (s *Service) Protocols() []p2p.Protocol {
func (s *Service) APIs() []rpc.API {
apis := []rpc.API{
{
Namespace: "shhext",
Namespace: s.apiName,
Version: "1.0",
Service: NewPublicAPI(s),
Public: true,
@ -409,7 +410,7 @@ func (s *Service) syncMessages(ctx context.Context, mailServerID []byte, r types
}
}
func onNegotiatedFilters(filters []*protocolwhisper.Filter) {
func onNegotiatedFilters(filters []*transport.Filter) {
var signalFilters []*signal.Filter
for _, filter := range filters {
@ -430,8 +431,12 @@ func onNegotiatedFilters(filters []*protocolwhisper.Filter) {
}
}
func buildMessengerOptions(config params.ShhextConfig, db *sql.DB, envelopesMonitorConfig *protocolwhisper.EnvelopesMonitorConfig, logger *zap.Logger) []protocol.Option {
func buildMessengerOptions(
config params.ShhextConfig,
db *sql.DB,
envelopesMonitorConfig *transport.EnvelopesMonitorConfig,
logger *zap.Logger,
) []protocol.Option {
options := []protocol.Option{
protocol.WithCustomLogger(logger),
protocol.WithDatabase(db),

View File

@ -139,7 +139,7 @@ func (s *ShhExtSuite) SetupTest() {
db, err := leveldb.Open(storage.NewMemStorage(), nil)
s.Require().NoError(err)
nodeWrapper := &testNodeWrapper{w: s.whisperWrapper[i]}
s.services[i] = New(nodeWrapper, nil, nil, db, config)
s.services[i] = New(nodeWrapper, nil, "shhext", nil, db, config)
tmpdir, err := ioutil.TempDir("", "test-shhext-service")
s.Require().NoError(err)
@ -175,7 +175,7 @@ func (s *ShhExtSuite) TestInitProtocol() {
s.Require().NoError(err)
nodeWrapper := &testNodeWrapper{w: shh}
service := New(nodeWrapper, nil, nil, db, config)
service := New(nodeWrapper, nil, "shhext", nil, db, config)
tmpdir, err := ioutil.TempDir("", "test-shhext-service-init-protocol")
s.Require().NoError(err)
@ -215,7 +215,7 @@ func (s *ShhExtSuite) TestRequestMessagesErrors() {
PFSEnabled: true,
}
nodeWrapper := &testNodeWrapper{w: shh}
service := New(nodeWrapper, nil, mock, nil, config)
service := New(nodeWrapper, nil, "shhext", mock, nil, config)
api := NewPublicAPI(service)
const (
@ -321,7 +321,7 @@ func (s *ShhExtSuite) TestRequestMessagesSuccess() {
PFSEnabled: true,
}
nodeWrapper := &testNodeWrapper{w: shh}
service := New(nodeWrapper, nil, mock, nil, config)
service := New(nodeWrapper, nil, "shhext", mock, nil, config)
tmpdir, err := ioutil.TempDir("", "test-shhext-service-request-messages")
s.Require().NoError(err)
@ -397,6 +397,10 @@ func (w *testNodeWrapper) GetWhisper(_ interface{}) (types.Whisper, error) {
return w.w, nil
}
func (w *testNodeWrapper) GetWaku(_ interface{}) (types.Waku, error) {
return nil, errors.New("not implemented")
}
func (w *testNodeWrapper) AddPeer(url string) error {
panic("not implemented")
}
@ -457,7 +461,14 @@ func (s *WhisperNodeMockSuite) SetupTest() {
))
nodeWrapper := &testNodeWrapper{w: whisperWrapper}
s.localService = New(nodeWrapper, nil, nil, db, params.ShhextConfig{MailServerConfirmations: true, MaxMessageDeliveryAttempts: 3})
s.localService = New(
nodeWrapper,
nil,
"shhext",
nil,
db,
params.ShhextConfig{MailServerConfirmations: true, MaxMessageDeliveryAttempts: 3},
)
s.Require().NoError(s.localService.UpdateMailservers([]*enode.Node{node}))
s.localWhisperAPI = whisper.NewPublicWhisperAPI(w)
@ -584,7 +595,7 @@ func (s *RequestWithTrackingHistorySuite) SetupTest() {
s.localWhisperAPI = local.PublicWhisperAPI()
nodeWrapper := &testNodeWrapper{w: local}
s.localService = New(nodeWrapper, nil, nil, db, params.ShhextConfig{})
s.localService = New(nodeWrapper, nil, "shhext", nil, db, params.ShhextConfig{})
s.localContext = NewContextFromService(context.Background(), s.localService, s.localService.storage)
localPkey, err := crypto.GenerateKey()
s.Require().NoError(err)

File diff suppressed because one or more lines are too long

View File

@ -86,7 +86,7 @@ func configPublicChainAccountsJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "config/public-chain-accounts.json", size: 307, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "config/public-chain-accounts.json", size: 307, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x76, 0x5d, 0xc0, 0xfe, 0x57, 0x50, 0x18, 0xec, 0x2d, 0x61, 0x1b, 0xa9, 0x81, 0x11, 0x5f, 0x77, 0xf7, 0xb6, 0x67, 0x82, 0x1, 0x40, 0x68, 0x9d, 0xc5, 0x41, 0xaf, 0xce, 0x43, 0x81, 0x92, 0x96}}
return a, nil
}
@ -106,7 +106,7 @@ func configStatusChainAccountsJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "config/status-chain-accounts.json", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "config/status-chain-accounts.json", size: 543, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8e, 0xb3, 0x61, 0x51, 0x70, 0x3c, 0x12, 0x3e, 0xf1, 0x1c, 0x81, 0xfb, 0x9a, 0x7c, 0xe3, 0x63, 0xd0, 0x8f, 0x12, 0xc5, 0x2d, 0xf4, 0xea, 0x27, 0x33, 0xef, 0xca, 0xf9, 0x3f, 0x72, 0x44, 0xbf}}
return a, nil
}
@ -126,7 +126,7 @@ func configTestDataJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "config/test-data.json", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1573806410, 0)}
info := bindataFileInfo{name: "config/test-data.json", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xce, 0x9d, 0x80, 0xf5, 0x87, 0xfa, 0x57, 0x1d, 0xa1, 0xd5, 0x7a, 0x10, 0x3, 0xac, 0xd7, 0xf4, 0x64, 0x32, 0x96, 0x2b, 0xb7, 0x21, 0xb7, 0xa6, 0x80, 0x40, 0xe9, 0x65, 0xe3, 0xd6, 0xbd, 0x40}}
return a, nil
}

View File

@ -2,11 +2,25 @@ package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
"github.com/status-im/status-go/whisper/v6"
)
// NewGethEnvelopeErrorWrapper returns a types.EnvelopeError object that mimics Geth's EnvelopeError
func NewGethEnvelopeErrorWrapper(envelopeError *whisper.EnvelopeError) *types.EnvelopeError {
// NewWhisperEnvelopeErrorWrapper returns a types.EnvelopeError object that mimics Geth's EnvelopeError
func NewWhisperEnvelopeErrorWrapper(envelopeError *whisper.EnvelopeError) *types.EnvelopeError {
if envelopeError == nil {
panic("envelopeError should not be nil")
}
return &types.EnvelopeError{
Hash: types.Hash(envelopeError.Hash),
Code: mapGethErrorCode(envelopeError.Code),
Description: envelopeError.Description,
}
}
// NewWakuEnvelopeErrorWrapper returns a types.EnvelopeError object that mimics Geth's EnvelopeError
func NewWakuEnvelopeErrorWrapper(envelopeError *waku.EnvelopeError) *types.EnvelopeError {
if envelopeError == nil {
panic("envelopeError should not be nil")
}
@ -21,8 +35,10 @@ func NewGethEnvelopeErrorWrapper(envelopeError *whisper.EnvelopeError) *types.En
func mapGethErrorCode(code uint) uint {
switch code {
case whisper.EnvelopeTimeNotSynced:
case waku.EnvelopeTimeNotSynced:
return types.EnvelopeTimeNotSynced
case whisper.EnvelopeOtherError:
case waku.EnvelopeOtherError:
return types.EnvelopeOtherError
}
return types.EnvelopeOtherError

View File

@ -2,11 +2,12 @@ package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
"github.com/status-im/status-go/whisper/v6"
)
// NewGethEnvelopeEventWrapper returns a types.EnvelopeEvent object that mimics Geth's EnvelopeEvent
func NewGethEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.EnvelopeEvent {
// NewWhisperEnvelopeEventWrapper returns a types.EnvelopeEvent object that mimics Geth's EnvelopeEvent
func NewWhisperEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.EnvelopeEvent {
if envelopeEvent == nil {
panic("envelopeEvent should not be nil")
}
@ -16,10 +17,10 @@ func NewGethEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.En
case []whisper.EnvelopeError:
wrappedData := make([]types.EnvelopeError, len(data))
for index, envError := range data {
wrappedData[index] = *NewGethEnvelopeErrorWrapper(&envError)
wrappedData[index] = *NewWhisperEnvelopeErrorWrapper(&envError)
}
case *whisper.MailServerResponse:
wrappedData = NewGethMailServerResponseWrapper(data)
wrappedData = NewWhisperMailServerResponseWrapper(data)
case whisper.SyncEventResponse:
wrappedData = NewGethSyncEventResponseWrapper(data)
}
@ -31,3 +32,28 @@ func NewGethEnvelopeEventWrapper(envelopeEvent *whisper.EnvelopeEvent) *types.En
Data: wrappedData,
}
}
// NewWakuEnvelopeEventWrapper returns a types.EnvelopeEvent object that mimics Geth's EnvelopeEvent
func NewWakuEnvelopeEventWrapper(envelopeEvent *waku.EnvelopeEvent) *types.EnvelopeEvent {
if envelopeEvent == nil {
panic("envelopeEvent should not be nil")
}
wrappedData := envelopeEvent.Data
switch data := envelopeEvent.Data.(type) {
case []waku.EnvelopeError:
wrappedData := make([]types.EnvelopeError, len(data))
for index, envError := range data {
wrappedData[index] = *NewWakuEnvelopeErrorWrapper(&envError)
}
case *waku.MailServerResponse:
wrappedData = NewWakuMailServerResponseWrapper(data)
}
return &types.EnvelopeEvent{
Event: types.EventType(envelopeEvent.Event),
Hash: types.Hash(envelopeEvent.Hash),
Batch: types.Hash(envelopeEvent.Batch),
Peer: types.EnodeID(envelopeEvent.Peer),
Data: wrappedData,
}
}

View File

@ -1,33 +0,0 @@
package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/whisper/v6"
)
type gethFilterWrapper struct {
filter *whisper.Filter
id string
}
// NewGethFilterWrapper returns an object that wraps Geth's Filter in a types interface
func NewGethFilterWrapper(f *whisper.Filter, id string) types.Filter {
if f.Messages == nil {
panic("Messages should not be nil")
}
return &gethFilterWrapper{
filter: f,
id: id,
}
}
// GetGethFilterFrom retrieves the underlying whisper Filter struct from a wrapped Filter interface
func GetGethFilterFrom(f types.Filter) *whisper.Filter {
return f.(*gethFilterWrapper).filter
}
// ID returns the filter ID
func (w *gethFilterWrapper) ID() string {
return w.id
}

View File

@ -2,11 +2,25 @@ package gethbridge
import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
"github.com/status-im/status-go/whisper/v6"
)
// NewGethMailServerResponseWrapper returns a types.MailServerResponse object that mimics Geth's MailServerResponse
func NewGethMailServerResponseWrapper(mailServerResponse *whisper.MailServerResponse) *types.MailServerResponse {
// NewWhisperMailServerResponseWrapper returns a types.MailServerResponse object that mimics Geth's MailServerResponse
func NewWhisperMailServerResponseWrapper(mailServerResponse *whisper.MailServerResponse) *types.MailServerResponse {
if mailServerResponse == nil {
panic("mailServerResponse should not be nil")
}
return &types.MailServerResponse{
LastEnvelopeHash: types.Hash(mailServerResponse.LastEnvelopeHash),
Cursor: mailServerResponse.Cursor,
Error: mailServerResponse.Error,
}
}
// NewWakuMailServerResponseWrapper returns a types.MailServerResponse object that mimics Geth's MailServerResponse
func NewWakuMailServerResponseWrapper(mailServerResponse *waku.MailServerResponse) *types.MailServerResponse {
if mailServerResponse == nil {
panic("mailServerResponse should not be nil")
}

View File

@ -1,6 +1,9 @@
package gethbridge
import (
"errors"
"github.com/status-im/status-go/waku"
"go.uber.org/zap"
"github.com/ethereum/go-ethereum/node"
@ -41,12 +44,35 @@ func (w *gethNodeWrapper) GetWhisper(ctx interface{}) (types.Whisper, error) {
}
}
if nativeWhisper == nil {
panic("Whisper service is not available")
return nil, errors.New("whisper service is not available")
}
return NewGethWhisperWrapper(nativeWhisper), nil
}
func (w *gethNodeWrapper) GetWaku(ctx interface{}) (types.Waku, error) {
var nativeWaku *waku.Waku
if ctx == nil || ctx == w {
err := w.stack.Service(&nativeWaku)
if err != nil {
return nil, err
}
} else {
switch serviceProvider := ctx.(type) {
case *node.ServiceContext:
err := serviceProvider.Service(&nativeWaku)
if err != nil {
return nil, err
}
}
}
if nativeWaku == nil {
return nil, errors.New("waku service is not available")
}
return NewGethWakuWrapper(nativeWaku), nil
}
func (w *gethNodeWrapper) AddPeer(url string) error {
parsedNode, err := enode.ParseV4(url)
if err != nil {

View File

@ -0,0 +1,103 @@
package gethbridge
import (
"context"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
)
type gethPublicWakuAPIWrapper struct {
api *waku.PublicWakuAPI
}
// NewGethPublicWakuAPIWrapper returns an object that wraps Geth's PublicWakuAPI in a types interface
func NewGethPublicWakuAPIWrapper(api *waku.PublicWakuAPI) types.PublicWakuAPI {
if api == nil {
panic("PublicWakuAPI cannot be nil")
}
return &gethPublicWakuAPIWrapper{
api: api,
}
}
// AddPrivateKey imports the given private key.
func (w *gethPublicWakuAPIWrapper) AddPrivateKey(ctx context.Context, privateKey types.HexBytes) (string, error) {
return w.api.AddPrivateKey(ctx, hexutil.Bytes(privateKey))
}
// GenerateSymKeyFromPassword derives a key from the given password, stores it, and returns its ID.
func (w *gethPublicWakuAPIWrapper) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) {
return w.api.GenerateSymKeyFromPassword(ctx, passwd)
}
// DeleteKeyPair removes the key with the given key if it exists.
func (w *gethPublicWakuAPIWrapper) DeleteKeyPair(ctx context.Context, key string) (bool, error) {
return w.api.DeleteKeyPair(ctx, key)
}
// NewMessageFilter creates a new filter that can be used to poll for
// (new) messages that satisfy the given criteria.
func (w *gethPublicWakuAPIWrapper) NewMessageFilter(req types.Criteria) (string, error) {
topics := make([]waku.TopicType, len(req.Topics))
for index, tt := range req.Topics {
topics[index] = waku.TopicType(tt)
}
criteria := waku.Criteria{
SymKeyID: req.SymKeyID,
PrivateKeyID: req.PrivateKeyID,
Sig: req.Sig,
MinPow: req.MinPow,
Topics: topics,
AllowP2P: req.AllowP2P,
}
return w.api.NewMessageFilter(criteria)
}
// GetFilterMessages returns the messages that match the filter criteria and
// are received between the last poll and now.
func (w *gethPublicWakuAPIWrapper) GetFilterMessages(id string) ([]*types.Message, error) {
msgs, err := w.api.GetFilterMessages(id)
if err != nil {
return nil, err
}
wrappedMsgs := make([]*types.Message, len(msgs))
for index, msg := range msgs {
wrappedMsgs[index] = &types.Message{
Sig: msg.Sig,
TTL: msg.TTL,
Timestamp: msg.Timestamp,
Topic: types.TopicType(msg.Topic),
Payload: msg.Payload,
Padding: msg.Padding,
PoW: msg.PoW,
Hash: msg.Hash,
Dst: msg.Dst,
P2P: msg.P2P,
}
}
return wrappedMsgs, nil
}
// Post posts a message on the network.
// returns the hash of the message in case of success.
func (w *gethPublicWakuAPIWrapper) Post(ctx context.Context, req types.NewMessage) ([]byte, error) {
msg := waku.NewMessage{
SymKeyID: req.SymKeyID,
PublicKey: req.PublicKey,
Sig: req.SigID, // Sig is really a SigID
TTL: req.TTL,
Topic: waku.TopicType(req.Topic),
Payload: req.Payload,
Padding: req.Padding,
PowTime: req.PowTime,
PowTarget: req.PowTarget,
TargetPeer: req.TargetPeer,
}
return w.api.Post(ctx, msg)
}

View File

@ -0,0 +1,197 @@
package gethbridge
import (
"crypto/ecdsa"
"time"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku"
)
type gethWakuWrapper struct {
waku *waku.Waku
}
// NewGethWakuWrapper returns an object that wraps Geth's Waku in a types interface
func NewGethWakuWrapper(w *waku.Waku) types.Waku {
if w == nil {
panic("waku cannot be nil")
}
return &gethWakuWrapper{
waku: w,
}
}
// GetGethWhisperFrom retrieves the underlying whisper Whisper struct from a wrapped Whisper interface
func GetGethWakuFrom(m types.Waku) *waku.Waku {
return m.(*gethWakuWrapper).waku
}
func (w *gethWakuWrapper) PublicWakuAPI() types.PublicWakuAPI {
return NewGethPublicWakuAPIWrapper(waku.NewPublicWakuAPI(w.waku))
}
// MinPow returns the PoW value required by this node.
func (w *gethWakuWrapper) MinPow() float64 {
return w.waku.MinPow()
}
// BloomFilter returns the aggregated bloom filter for all the topics of interest.
// The nodes are required to send only messages that match the advertised bloom filter.
// If a message does not match the bloom, it will tantamount to spam, and the peer will
// be disconnected.
func (w *gethWakuWrapper) BloomFilter() []byte {
return w.waku.BloomFilter()
}
// GetCurrentTime returns current time.
func (w *gethWakuWrapper) GetCurrentTime() time.Time {
return w.waku.CurrentTime()
}
// SetTimeSource assigns a particular source of time to a whisper object.
func (w *gethWakuWrapper) SetTimeSource(timesource func() time.Time) {
w.waku.SetTimeSource(timesource)
}
func (w *gethWakuWrapper) SubscribeEnvelopeEvents(eventsProxy chan<- types.EnvelopeEvent) types.Subscription {
events := make(chan waku.EnvelopeEvent, 100) // must be buffered to prevent blocking whisper
go func() {
for e := range events {
eventsProxy <- *NewWakuEnvelopeEventWrapper(&e)
}
}()
return NewGethSubscriptionWrapper(w.waku.SubscribeEnvelopeEvents(events))
}
func (w *gethWakuWrapper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
return w.waku.GetPrivateKey(id)
}
// AddKeyPair imports a asymmetric private key and returns a deterministic identifier.
func (w *gethWakuWrapper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
return w.waku.AddKeyPair(key)
}
// DeleteKeyPair deletes the key with the specified ID if it exists.
func (w *gethWakuWrapper) DeleteKeyPair(keyID string) bool {
return w.waku.DeleteKeyPair(keyID)
}
func (w *gethWakuWrapper) AddSymKeyDirect(key []byte) (string, error) {
return w.waku.AddSymKeyDirect(key)
}
func (w *gethWakuWrapper) AddSymKeyFromPassword(password string) (string, error) {
return w.waku.AddSymKeyFromPassword(password)
}
func (w *gethWakuWrapper) DeleteSymKey(id string) bool {
return w.waku.DeleteSymKey(id)
}
func (w *gethWakuWrapper) GetSymKey(id string) ([]byte, error) {
return w.waku.GetSymKey(id)
}
func (w *gethWakuWrapper) Subscribe(opts *types.SubscriptionOptions) (string, error) {
var (
err error
keyAsym *ecdsa.PrivateKey
keySym []byte
)
if opts.SymKeyID != "" {
keySym, err = w.GetSymKey(opts.SymKeyID)
if err != nil {
return "", err
}
}
if opts.PrivateKeyID != "" {
keyAsym, err = w.GetPrivateKey(opts.PrivateKeyID)
if err != nil {
return "", err
}
}
f, err := w.createFilterWrapper("", keyAsym, keySym, opts.PoW, opts.Topics)
if err != nil {
return "", err
}
id, err := w.waku.Subscribe(GetWakuFilterFrom(f))
if err != nil {
return "", err
}
f.(*wakuFilterWrapper).id = id
return id, nil
}
func (w *gethWakuWrapper) GetFilter(id string) types.Filter {
return NewWakuFilterWrapper(w.waku.GetFilter(id), id)
}
func (w *gethWakuWrapper) Unsubscribe(id string) error {
return w.waku.Unsubscribe(id)
}
func (w *gethWakuWrapper) createFilterWrapper(id string, keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (types.Filter, error) {
return NewWakuFilterWrapper(&waku.Filter{
KeyAsym: keyAsym,
KeySym: keySym,
PoW: pow,
AllowP2P: true,
Topics: topics,
Messages: waku.NewMemoryMessageStore(),
}, id), nil
}
func (w *gethWakuWrapper) SendMessagesRequest(peerID []byte, r types.MessagesRequest) error {
return w.waku.SendMessagesRequest(peerID, waku.MessagesRequest{
ID: r.ID,
From: r.From,
To: r.To,
Limit: r.Limit,
Cursor: r.Cursor,
Bloom: r.Bloom,
})
}
// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer,
// which is known to implement MailServer interface, and is supposed to process this
// request and respond with a number of peer-to-peer messages (possibly expired),
// which are not supposed to be forwarded any further.
// The whisper protocol is agnostic of the format and contents of envelope.
func (w *gethWakuWrapper) RequestHistoricMessagesWithTimeout(peerID []byte, envelope types.Envelope, timeout time.Duration) error {
return w.waku.RequestHistoricMessagesWithTimeout(peerID, MustUnwrapWakuEnvelope(envelope), timeout)
}
type wakuFilterWrapper struct {
filter *waku.Filter
id string
}
// NewWakuFilterWrapper returns an object that wraps Geth's Filter in a types interface
func NewWakuFilterWrapper(f *waku.Filter, id string) types.Filter {
if f.Messages == nil {
panic("Messages should not be nil")
}
return &wakuFilterWrapper{
filter: f,
id: id,
}
}
// GetWakuFilterFrom retrieves the underlying whisper Filter struct from a wrapped Filter interface
func GetWakuFilterFrom(f types.Filter) *waku.Filter {
return f.(*wakuFilterWrapper).filter
}
// ID returns the filter ID
func (w *wakuFilterWrapper) ID() string {
return w.id
}

View File

@ -59,7 +59,7 @@ func (w *gethWhisperWrapper) SubscribeEnvelopeEvents(eventsProxy chan<- types.En
events := make(chan whisper.EnvelopeEvent, 100) // must be buffered to prevent blocking whisper
go func() {
for e := range events {
eventsProxy <- *NewGethEnvelopeEventWrapper(&e)
eventsProxy <- *NewWhisperEnvelopeEventWrapper(&e)
}
}()
@ -121,17 +121,17 @@ func (w *gethWhisperWrapper) Subscribe(opts *types.SubscriptionOptions) (string,
return "", err
}
id, err := w.whisper.Subscribe(GetGethFilterFrom(f))
id, err := w.whisper.Subscribe(GetWhisperFilterFrom(f))
if err != nil {
return "", err
}
f.(*gethFilterWrapper).id = id
f.(*whisperFilterWrapper).id = id
return id, nil
}
func (w *gethWhisperWrapper) GetFilter(id string) types.Filter {
return NewGethFilterWrapper(w.whisper.GetFilter(id), id)
return NewWhisperFilterWrapper(w.whisper.GetFilter(id), id)
}
func (w *gethWhisperWrapper) Unsubscribe(id string) error {
@ -139,7 +139,7 @@ func (w *gethWhisperWrapper) Unsubscribe(id string) error {
}
func (w *gethWhisperWrapper) createFilterWrapper(id string, keyAsym *ecdsa.PrivateKey, keySym []byte, pow float64, topics [][]byte) (types.Filter, error) {
return NewGethFilterWrapper(&whisper.Filter{
return NewWhisperFilterWrapper(&whisper.Filter{
KeyAsym: keyAsym,
KeySym: keySym,
PoW: pow,
@ -173,3 +173,30 @@ func (w *gethWhisperWrapper) RequestHistoricMessagesWithTimeout(peerID []byte, e
func (w *gethWhisperWrapper) SyncMessages(peerID []byte, req types.SyncMailRequest) error {
return w.whisper.SyncMessages(peerID, *GetGethSyncMailRequestFrom(&req))
}
type whisperFilterWrapper struct {
filter *whisper.Filter
id string
}
// NewWhisperFilterWrapper returns an object that wraps Geth's Filter in a types interface
func NewWhisperFilterWrapper(f *whisper.Filter, id string) types.Filter {
if f.Messages == nil {
panic("Messages should not be nil")
}
return &whisperFilterWrapper{
filter: f,
id: id,
}
}
// GetWhisperFilterFrom retrieves the underlying whisper Filter struct from a wrapped Filter interface
func GetWhisperFilterFrom(f types.Filter) *whisper.Filter {
return f.(*whisperFilterWrapper).filter
}
// ID returns the filter ID
func (w *whisperFilterWrapper) ID() string {
return w.id
}

View File

@ -0,0 +1,8 @@
package types
const (
// PubKeyLength represents the length (in bytes) of an uncompressed public key
PubKeyLength = 512 / 8
// AesKeyLength represents the length (in bytes) of an private key
AesKeyLength = 256 / 8
)

View File

@ -19,6 +19,7 @@ func (n EnodeID) String() string {
type Node interface {
NewENSVerifier(logger *zap.Logger) enstypes.ENSVerifier
GetWhisper(ctx interface{}) (Whisper, error)
GetWaku(ctx interface{}) (Waku, error)
AddPeer(url string) error
RemovePeer(url string) error
}

View File

@ -63,3 +63,25 @@ type PublicWhisperAPI interface {
// are received between the last poll and now.
GetFilterMessages(id string) ([]*Message, error)
}
// PublicWakuAPI provides the waku RPC service that can be
// use publicly without security implications.
type PublicWakuAPI interface {
// AddPrivateKey imports the given private key.
AddPrivateKey(ctx context.Context, privateKey HexBytes) (string, error)
// GenerateSymKeyFromPassword derives a key from the given password, stores it, and returns its ID.
GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error)
// DeleteKeyPair removes the key with the given key if it exists.
DeleteKeyPair(ctx context.Context, key string) (bool, error)
// Post posts a message on the Whisper network.
// returns the hash of the message in case of success.
Post(ctx context.Context, req NewMessage) ([]byte, error)
// NewMessageFilter creates a new filter that can be used to poll for
// (new) messages that satisfy the given criteria.
NewMessageFilter(req Criteria) (string, error)
// GetFilterMessages returns the messages that match the filter criteria and
// are received between the last poll and now.
GetFilterMessages(id string) ([]*Message, error)
}

View File

@ -0,0 +1,10 @@
package types
// SubscriptionOptions represents the parameters passed to Subscribe()
// to customize the subscription behavior.
type SubscriptionOptions struct {
PrivateKeyID string
SymKeyID string
PoW float64
Topics [][]byte
}

View File

@ -0,0 +1,53 @@
package types
import (
"crypto/ecdsa"
"time"
)
// Whisper represents a dark communication interface through the Ethereum
// network, using its very own P2P communication layer.
type Waku interface {
PublicWakuAPI() PublicWakuAPI
// MinPow returns the PoW value required by this node.
MinPow() float64
// BloomFilter returns the aggregated bloom filter for all the topics of interest.
// The nodes are required to send only messages that match the advertised bloom filter.
// If a message does not match the bloom, it will tantamount to spam, and the peer will
// be disconnected.
BloomFilter() []byte
// SetTimeSource assigns a particular source of time to a whisper object.
SetTimeSource(timesource func() time.Time)
// GetCurrentTime returns current time.
GetCurrentTime() time.Time
// GetPrivateKey retrieves the private key of the specified identity.
GetPrivateKey(id string) (*ecdsa.PrivateKey, error)
SubscribeEnvelopeEvents(events chan<- EnvelopeEvent) Subscription
// AddKeyPair imports a asymmetric private key and returns a deterministic identifier.
AddKeyPair(key *ecdsa.PrivateKey) (string, error)
// DeleteKeyPair deletes the key with the specified ID if it exists.
DeleteKeyPair(keyID string) bool
AddSymKeyDirect(key []byte) (string, error)
AddSymKeyFromPassword(password string) (string, error)
DeleteSymKey(id string) bool
GetSymKey(id string) ([]byte, error)
Subscribe(opts *SubscriptionOptions) (string, error)
GetFilter(id string) Filter
Unsubscribe(id string) error
// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer,
// which is known to implement MailServer interface, and is supposed to process this
// request and respond with a number of peer-to-peer messages (possibly expired),
// which are not supposed to be forwarded any further.
// The whisper protocol is agnostic of the format and contents of envelope.
// A timeout of 0 never expires.
RequestHistoricMessagesWithTimeout(peerID []byte, envelope Envelope, timeout time.Duration) error
// SendMessagesRequest sends a MessagesRequest. This is an equivalent to RequestHistoricMessages
// in terms of the functionality.
SendMessagesRequest(peerID []byte, request MessagesRequest) error
}

View File

@ -5,22 +5,6 @@ import (
"time"
)
const (
// PubKeyLength represents the length (in bytes) of an uncompressed public key
PubKeyLength = 512 / 8
// AesKeyLength represents the length (in bytes) of an private key
AesKeyLength = 256 / 8
)
// SubscriptionOptions represents the parameters passed to Whisper.Subscribe
// to customize the subscription behavior
type SubscriptionOptions struct {
PrivateKeyID string
SymKeyID string
PoW float64
Topics [][]byte
}
// Whisper represents a dark communication interface through the Ethereum
// network, using its very own P2P communication layer.
type Whisper interface {

View File

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

View File

@ -5,9 +5,8 @@ package encryption
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -697,6 +697,7 @@ 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-20190912160710-24e19bdeb0f2 h1:4dVFTC832rPn4pomLSz1vA+are2+dU19w1H8OngV7nc=
golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/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=

View File

@ -19,7 +19,7 @@ import (
"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"
"github.com/status-im/status-go/protocol/transport"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
@ -34,7 +34,7 @@ type messageProcessor struct {
identity *ecdsa.PrivateKey
datasync *datasync.DataSync
protocol *encryption.Protocol
transport *transport.WhisperServiceTransport
transport transport.Transport
logger *zap.Logger
featureFlags featureFlags
@ -44,7 +44,7 @@ func newMessageProcessor(
identity *ecdsa.PrivateKey,
database *sql.DB,
enc *encryption.Protocol,
transport *transport.WhisperServiceTransport,
transport transport.Transport,
logger *zap.Logger,
features featureFlags,
) (*messageProcessor, error) {

View File

@ -23,7 +23,9 @@ import (
"github.com/status-im/status-go/protocol/identity/identicon"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/sqlite"
transport "github.com/status-im/status-go/protocol/transport/whisper"
"github.com/status-im/status-go/protocol/transport"
wakutransp "github.com/status-im/status-go/protocol/transport/waku"
shhtransp "github.com/status-im/status-go/protocol/transport/whisper"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
@ -47,7 +49,7 @@ type Messenger struct {
node types.Node
identity *ecdsa.PrivateKey
persistence *sqlitePersistence
transport *transport.WhisperServiceTransport
transport transport.Transport
encryptor *encryption.Protocol
processor *messageProcessor
handler *MessageHandler
@ -195,11 +197,6 @@ func NewMessenger(
) (*Messenger, error) {
var messenger *Messenger
shh, err := node.GetWhisper(nil)
if err != nil {
return nil, err
}
c := config{}
for _, opt := range opts {
@ -279,22 +276,42 @@ func NewMessenger(
}
// Apply migrations for all components.
err = sqlite.Migrate(database)
err := sqlite.Migrate(database)
if err != nil {
return nil, errors.Wrap(err, "failed to apply migrations")
}
// Initialize transport layer.
t, err := transport.NewWhisperServiceTransport(
shh,
identity,
database,
nil,
c.envelopesMonitorConfig,
logger,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create a WhisperServiceTransport")
var transp transport.Transport
if shh, err := node.GetWhisper(nil); err == nil {
transp, err = shhtransp.NewWhisperServiceTransport(
shh,
identity,
database,
nil,
c.envelopesMonitorConfig,
logger,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create WhisperServiceTransport")
}
} else if err != nil {
logger.Info("failed to find Whisper service; trying Waku", zap.Error(err))
waku, err := node.GetWaku(nil)
if err != nil {
return nil, errors.Wrap(err, "failed to find Whisper and Waku services")
}
transp, err = wakutransp.NewWakuServiceTransport(
waku,
identity,
database,
nil,
c.envelopesMonitorConfig,
logger,
)
if err != nil {
return nil, errors.Wrap(err, "failed to create WakuServiceTransport")
}
}
// Initialize encryption layer.
@ -311,7 +328,7 @@ func NewMessenger(
identity,
database,
encryptionProtocol,
t,
transp,
logger,
c.featureFlags,
)
@ -325,7 +342,7 @@ func NewMessenger(
node: node,
identity: identity,
persistence: &sqlitePersistence{db: database},
transport: t,
transport: transp,
encryptor: encryptionProtocol,
processor: processor,
handler: handler,
@ -340,8 +357,8 @@ func NewMessenger(
verifyTransactionClient: c.verifyTransactionClient,
shutdownTasks: []func() error{
database.Close,
t.Reset,
t.Stop,
transp.ResetFilters,
transp.Stop,
func() error { processor.Stop(); return nil },
// Currently this often fails, seems like it's safe to ignore them
// https://github.com/uber-go/zap/issues/328

View File

@ -1,65 +0,0 @@
package protocol
import (
"strings"
"github.com/pkg/errors"
encryptmigrations "github.com/status-im/status-go/protocol/encryption/migrations"
appmigrations "github.com/status-im/status-go/protocol/migrations"
transpmigrations "github.com/status-im/status-go/protocol/transport/whisper/migrations"
)
type getter func(string) ([]byte, error)
type migrationsWithGetter struct {
Names []string
Getter getter
}
var defaultMigrations = []migrationsWithGetter{
{
Names: transpmigrations.AssetNames(),
Getter: transpmigrations.Asset,
},
{
Names: encryptmigrations.AssetNames(),
Getter: encryptmigrations.Asset,
},
{
Names: appmigrations.AssetNames(),
Getter: appmigrations.Asset,
},
}
func prepareMigrations(migrations []migrationsWithGetter) ([]string, getter, error) {
var allNames []string
nameToGetter := make(map[string]getter)
for _, m := range migrations {
for _, name := range m.Names {
if !validateName(name) {
continue
}
if _, ok := nameToGetter[name]; ok {
return nil, nil, errors.Errorf("migration with name %s already exists", name)
}
allNames = append(allNames, name)
nameToGetter[name] = m.Getter
}
}
return allNames, func(name string) ([]byte, error) {
getter, ok := nameToGetter[name]
if !ok {
return nil, errors.Errorf("no migration for name %s", name)
}
return getter(name)
}, nil
}
// validateName verifies that only *.sql files are taken into consideration.
func validateName(name string) bool {
return strings.HasSuffix(name, ".sql")
}

View File

@ -1,7 +1,7 @@
// Code generated by go-bindata. DO NOT EDIT.
// sources:
// 000001_init.down.db.sql (65B)
// 000001_init.up.db.sql (2.693kB)
// 000001_init.up.db.sql (2.719kB)
// doc.go (377B)
package migrations
@ -86,12 +86,12 @@ func _000001_initDownDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1577718673, 0)}
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1578756765, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5e, 0xbb, 0x3f, 0x1, 0x75, 0x19, 0x70, 0x86, 0xa7, 0x34, 0x40, 0x17, 0x34, 0x3e, 0x18, 0x51, 0x79, 0xd4, 0x22, 0xad, 0x8f, 0x80, 0xcc, 0xa6, 0xcc, 0x6, 0x2b, 0x62, 0x2, 0x47, 0xba, 0xf9}}
return a, nil
}
var __000001_initUpDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x56\x51\x6f\xe3\x36\x0c\x7e\xf7\xaf\x20\xb0\x87\xb6\x80\x3b\xdc\x80\xdb\x6d\x40\x9f\xd2\x9e\xbb\x05\xcb\x92\x43\xea\x0e\xbd\x27\x81\x91\xd8\x58\x88\x2d\x19\x12\x9d\x5c\x80\xfb\xf1\x83\x9c\x38\xb1\x12\xa7\xbd\x61\x7d\x28\x5a\x52\x24\xc5\x8f\xfc\x3e\xf9\x61\x9e\x8d\xf2\x0c\xf2\xd1\xfd\x24\x83\xf1\x23\x4c\x67\x39\x64\x2f\xe3\xa7\xfc\x09\x64\x81\xec\xe1\x3a\xd1\x0a\xfe\x19\xcd\x1f\xfe\x1c\xcd\xe1\xcb\x7c\xfc\xf7\x68\xfe\x15\xfe\xca\xbe\xc2\x6c\x0a\x0f\xb3\xe9\xe3\x64\xfc\x90\xc3\x3c\xfb\x32\x19\x3d\x64\x69\x62\xb0\xa2\xc3\xe9\x90\x6b\xfa\x3c\x99\xa4\x89\xb4\xa5\x75\x67\x76\xf8\x9c\x3d\x8e\x9e\x27\x39\x5c\xfd\x84\xbf\xfc\xfe\x9b\xfa\xf5\x2a\x4d\x78\x5b\x13\x8c\xa7\x79\x2f\x18\x25\xeb\x35\xc1\xfd\x6c\x36\xc9\x46\xd3\xf3\xe8\x7c\xfe\x9c\xa5\x09\xeb\x8a\x3c\x63\x55\x9f\x44\x2b\x2a\x89\x49\x09\x64\x21\x4b\x2b\x57\x62\x8d\x65\x13\x97\x38\x64\xfa\x90\x26\x75\xb3\x28\xb5\x14\x2b\xda\xc2\xfd\x64\x76\x9f\x26\x8d\x59\x6b\xda\x90\x12\x15\x79\x8f\x4b\x12\xd2\x36\x86\x2f\xc6\x97\xe8\x7f\xac\x50\x7b\x70\x9f\x73\x5f\xaa\xa2\x6a\x41\xce\xc7\xff\x15\xba\x16\x4d\xad\x90\x69\xe7\x48\x6e\xee\x92\x24\x9a\x9a\xb4\x86\x51\xb6\xa3\x02\xd0\x0a\xf2\xec\x25\x7f\x7f\x52\x00\xa8\x94\x23\xef\x77\xe7\x8f\x80\x01\xb4\x43\x3c\xb3\x92\xf1\x62\x4d\x4e\xbf\x6a\x52\x87\x61\x74\x0d\x3d\x8e\x26\x4f\xd9\xe9\x29\x81\x97\x71\x02\xc0\x52\xe3\x40\x71\xad\xc8\xb0\x96\xd6\x9c\xbb\xea\xc2\xb2\x3d\x37\xb7\x48\xee\x20\x52\x6f\xd4\xf3\x5b\xcf\x54\x09\xc6\x65\x87\x30\x80\xa2\xb5\x96\x24\xb4\x79\xb5\x07\x1b\x3b\xbd\x68\x98\x04\x5b\xc1\x58\xae\xe2\x7a\x2d\xfa\xb7\xb7\x30\xe6\x2b\x0f\xba\xaa\xad\x63\x34\x0c\x5c\x60\xf8\xa5\x3d\x30\x2e\x4a\x82\x02\x3d\x38\xbb\xd1\x0a\xd0\xc3\x86\xc0\x51\xb9\x05\x6b\x40\x73\x08\xde\x14\x64\x42\x70\x49\x55\xe8\xd5\x2c\x41\x9b\x57\x6d\x34\xd3\xad\x97\xce\x96\xe5\xcf\xc9\x1b\xb4\x6c\x3c\xb9\x6e\x71\x76\x33\x6f\xa7\xfe\xc3\x14\x0d\xe7\x37\x85\xf6\x35\x39\x11\x91\x26\xfb\x23\x9b\x47\xc0\x02\x78\xdb\x38\x39\xb0\x0b\x01\x39\xcf\xda\x20\x6b\x6b\x0e\xc8\x01\x30\x7d\xe3\x01\xfa\x07\x57\xd8\x52\x32\x2c\x06\x08\x1e\xdc\xa1\xab\xbe\x78\xec\xf3\x5d\x20\x75\x9b\xb0\x40\x16\xbd\xc6\x63\x6f\x69\x25\x96\xe2\xed\x33\x85\x56\x74\x79\x93\x01\x1c\xf9\xda\x1a\x1f\x56\x21\xbe\x56\x27\x05\x5d\x2f\xfb\x0b\x5d\x60\xfd\x1e\x4a\x22\x73\x59\xc3\x7a\x55\x6d\xc3\x4b\xab\xcd\x52\x78\x46\x6e\x7c\x5c\xb9\x46\xe7\x49\x89\x16\xe7\x23\xec\x0e\x37\xa2\xc6\x6d\x69\x51\xf5\xac\x9e\xb5\x5c\x91\x13\x35\xca\xd5\xf1\x96\x9d\xb5\x40\x5f\xc4\xb9\xa5\xad\x2a\x34\xaa\x87\x57\x6c\xdf\x75\x36\xe8\xea\xa4\x64\xd0\xf9\xea\x6c\x35\xec\x09\x3b\xe1\x50\xf2\xb0\x97\x1d\x1a\x1f\xc4\xdf\x9a\x37\x6e\xeb\xf5\xd2\x20\x37\x8e\x7a\x9d\x1f\x7c\x8c\xdc\xce\xa2\x2f\x9a\xe3\xe9\xe7\xec\x05\xb4\xfa\x26\xf6\xdb\x3d\x9b\xc6\x9c\xba\xde\xd9\x6f\xee\x06\x22\x08\x9d\x2c\xc4\x62\x7b\xd8\xac\xd9\x14\x4e\xa2\x77\x28\x37\x0b\xcf\xee\xfa\xea\xc3\xff\xfc\xb9\x82\xef\xdf\xfb\x8b\x95\xc2\xed\xa7\x8f\x29\x7c\xfa\x78\x13\x1c\x5a\xa5\x1d\x0d\xd2\x76\x9b\xcf\x1f\x87\x58\x3b\xc2\xa2\x44\xd2\xf1\xdf\x84\xe3\x7d\x52\xb5\x5a\xec\xe9\xe4\x81\x6c\xe5\x97\xda\x81\x9f\xbe\x9d\x7b\x17\x5f\xe6\xa1\xa3\x36\x14\x1b\xb6\x15\xb2\x96\x58\x96\xdb\xcb\xa7\x87\xa8\xe9\x48\xea\x5a\x93\xe1\xa3\xf0\xf7\xd9\xf2\x0e\x66\x21\x23\x99\x65\x50\xcb\xe3\x42\xfa\xf0\x3c\xac\xb1\xd4\xe1\xd5\x69\x91\xec\x0a\xc7\xec\x39\xe7\x54\xd4\xf9\xa5\x15\xef\x0f\x63\xd7\x01\xbb\xed\x11\xbd\x60\x7a\xd5\xae\x85\x9a\x4c\x67\x89\x99\x10\xd7\xe9\x5d\xf6\x14\xba\xdd\xe7\x13\xc0\xc9\x97\xcf\x20\x63\x06\xb1\x88\xa0\x08\x7c\x78\x1f\xb1\xeb\xde\xdf\x37\x77\xc9\xbf\x01\x00\x00\xff\xff\xc7\x20\x3e\x09\x85\x0a\x00\x00")
var __000001_initUpDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x56\xd1\x6f\xe2\xb8\x13\x7e\xe7\xaf\x18\xe9\xf7\x40\x2b\xd1\x9f\xf6\xa4\xbd\xbd\x93\xfa\x44\xd9\xf4\x0e\x1d\x07\x2b\x9a\x9e\xba\x4f\xd6\xe0\x0c\xc4\xc2\xb1\x23\x7b\x02\x8b\xb4\x7f\xfc\xc9\x81\x40\x0c\x81\xee\xea\xfa\x50\xb5\x33\xe3\x19\xcf\x37\xf3\x7d\xce\x68\x9e\x0c\xd3\x04\xd2\xe1\xd3\x24\x81\xf1\x33\x4c\x67\x29\x24\x6f\xe3\x97\xf4\x05\x64\x8e\xec\xe1\xae\x07\xa0\x32\xf8\x67\x38\x1f\xfd\x39\x9c\xc3\x97\xf9\xf8\xef\xe1\xfc\x2b\xfc\x95\x7c\x85\xd9\x14\x46\xb3\xe9\xf3\x64\x3c\x4a\x61\x9e\x7c\x99\x0c\x47\xc9\xa0\x07\x60\xb0\xa0\x63\x7c\xc8\x37\x7d\x9d\x4c\x82\x43\x5a\x6d\xdd\x85\x07\x3e\x27\xcf\xc3\xd7\x49\x0a\xfd\xff\xe1\x2f\xbf\xff\x96\xfd\xda\x0f\xb1\xbc\x2b\x09\xc6\xd3\x34\x4a\x80\x92\xd5\x86\xe0\x69\x36\x9b\x24\xc3\xe9\x65\x86\x74\xfe\x5a\xdf\x80\x55\x41\x9e\xb1\x28\x2f\x32\x64\xa4\x89\x29\x13\xc8\x42\x6a\x2b\xd7\x62\x83\xba\x8a\x0b\x1d\xb3\x7d\x08\x07\xca\x6a\xa1\x95\x14\x6b\xda\xc1\xd3\x64\xf6\x14\x4c\x95\xd9\x28\xda\x52\x26\x0a\xf2\x1e\x57\x24\xa4\xad\x0c\xdf\xc8\xa1\xd1\xff\x68\xb9\x3a\xf4\x90\xf7\x58\xb0\xa0\x62\x41\xce\x9f\xff\x9f\xab\x52\x54\x65\x86\x4c\x7b\x57\xef\xfe\xb1\xd7\x8b\xe6\x29\xad\x61\x94\xa7\x21\xa6\xc9\x5b\xfa\x23\x13\xc4\x2c\x73\xe4\xfd\x3e\xbe\x0d\x5f\x3d\xda\x0b\x2b\x19\x2f\x36\xe4\xd4\x52\x51\x76\x1c\x4e\xd3\xd6\xf3\x70\xf2\x92\x9c\x47\x09\xbc\x85\x17\x6a\x85\x1d\xc5\x55\x46\x86\x95\xb4\xe6\xd2\x55\xe6\x96\xed\xa5\xb9\x46\x73\x0f\x51\x76\xa3\x9e\xdf\x79\xa6\x42\x30\xae\x4e\x18\x67\xb4\x51\x92\x84\x32\x4b\x7b\xb4\xb1\x53\x8b\x8a\x49\xb0\x15\x8c\x7a\x1d\xd7\xab\xd1\x7f\x78\x80\x31\xf7\x3d\xa8\xa2\xb4\x8e\xd1\x30\x70\x8e\xe1\x97\xf2\xc0\xb8\xd0\x04\x39\x7a\x70\x76\xab\x32\x40\x0f\x5b\x02\x47\x7a\x07\xd6\x80\xe2\x70\x78\x9b\x93\x09\x87\x35\x15\xa1\x57\xb3\x02\x65\x96\xca\x28\xa6\x07\x2f\x9d\xd5\xfa\xff\xbd\x1b\x84\xad\x3c\xb9\x66\x79\xf6\x33\xff\x59\xea\x02\x6c\x73\xe5\x4b\x72\x22\xa2\x50\xf2\x47\x12\x33\x19\xc0\xdb\xca\xc9\x8e\x5d\x08\xc8\x79\x56\x06\x59\x59\x73\x44\x0e\x80\xe9\x1b\x77\x8a\x02\xd4\x5b\x4a\x86\x45\x27\xe5\xa1\xee\xaa\x2d\x29\x87\x7c\x57\x29\x0e\xb5\x70\x89\x56\xe3\xb1\x57\x5b\x89\x5a\xdc\x8e\xc9\x55\x46\xd7\x37\x19\xc0\x91\x2f\xad\xf1\x61\x15\xe2\x6b\x35\x92\xd0\xf4\x72\xb8\xd0\x15\xee\x1f\xa0\x24\x32\xd7\x35\xad\x55\xd5\x56\xbc\xb2\xca\xac\x84\x67\xe4\xca\xc7\x95\x4b\x74\x9e\x32\x51\xe3\x7c\x82\xdd\xe1\x56\x94\xb8\xd3\x16\xb3\x96\xd5\xb3\x92\x6b\x72\xa2\x44\xb9\x3e\xdd\xb2\xb1\xe6\xe8\xf3\x38\xb7\xb4\x45\x81\x26\x6b\xe1\x15\xdb\xf7\x9d\x75\xba\x1a\x29\xe9\x74\x2e\x9d\x2d\xba\x3d\x61\x27\x1c\x4a\xee\xf6\xb2\x43\xe3\xc3\x63\x60\xcd\x8d\xdb\x7a\xb5\x32\xc8\x95\xa3\x56\xe7\x47\x1f\x23\xd7\xb3\x68\x8b\xe6\x78\xfa\x39\x79\x03\x95\x7d\x13\x87\xed\x9e\x4d\x63\x4e\xdd\xed\xed\xf7\x8f\x1d\x27\x08\x9d\xcc\xc5\x62\x77\xdc\xac\xd9\x14\xce\x4e\xef\x51\xae\x16\x9e\xdd\x5d\xff\xc3\x7f\xfc\xe9\xc3\xf7\xef\xed\xc5\x1a\xc0\xc3\xa7\x8f\x03\xf8\xf4\xf1\x3e\x38\x54\x36\x68\x68\x30\xa8\xb7\xf9\xf2\x71\x88\xb5\x23\x2c\x4a\x24\x1d\x3f\x27\x1c\xef\x93\xaa\xd6\x62\x4f\x67\x0f\x65\x2d\xbf\x54\x0f\xfc\xfc\x0d\x3d\xb8\xf8\x3a\x0f\x1d\xd5\x47\xb1\x62\x5b\x20\x2b\x89\x5a\xef\xae\x47\x77\x51\xd3\x91\x54\xa5\x22\xc3\x27\xe1\x6f\xb3\xe5\x1d\xcc\x42\x46\x32\xab\xa0\x96\xa7\x85\xf4\xe1\x79\xd8\xa0\x56\xe1\xd5\xa9\x91\x6c\x0a\xc7\xec\xb9\xe4\x54\xd4\xf9\xb5\x15\x6f\x0f\x63\xdf\x01\xbb\xdd\x09\xbd\x60\x5a\x2a\x57\x43\x4d\xa6\xb1\xc4\x4c\x88\xeb\xb4\x2e\x7b\x0e\x5d\xf3\x39\x75\xf6\x0d\xd4\xc9\x98\x4e\x2c\x22\x28\x02\x1f\xde\x47\xec\xae\xf5\xf7\xfd\x63\xef\xdf\x00\x00\x00\xff\xff\xd7\x95\x8b\x6b\x9f\x0a\x00\x00")
func _000001_initUpDbSqlBytes() ([]byte, error) {
return bindataRead(
@ -106,8 +106,8 @@ func _000001_initUpDbSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2693, mode: os.FileMode(0644), modTime: time.Unix(1577718868, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0x9f, 0x6, 0x64, 0xcf, 0x97, 0xbe, 0xa8, 0xa2, 0x2f, 0xda, 0xc5, 0x9d, 0x26, 0x3, 0x65, 0x98, 0x8a, 0x7a, 0x6a, 0xc3, 0xd, 0x3f, 0x25, 0xfe, 0x4c, 0x5, 0xdb, 0x98, 0xa9, 0xf9, 0xf}}
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(0644), modTime: time.Unix(1578756765, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0xdc, 0xeb, 0xe, 0xc2, 0x4f, 0x75, 0xa, 0xf6, 0x3e, 0xc7, 0xc4, 0x4, 0xe2, 0xe1, 0xa4, 0x73, 0x2f, 0x4a, 0xad, 0x1a, 0x0, 0xc3, 0x93, 0x9d, 0x77, 0x3e, 0x31, 0x91, 0x77, 0x2e, 0xc8}}
return a, nil
}
@ -126,7 +126,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1574354941, 0)}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1578669164, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xef, 0xaf, 0xdf, 0xcf, 0x65, 0xae, 0x19, 0xfc, 0x9d, 0x29, 0xc1, 0x91, 0xaf, 0xb5, 0xd5, 0xb1, 0x56, 0xf3, 0xee, 0xa8, 0xba, 0x13, 0x65, 0xdb, 0xab, 0xcf, 0x4e, 0xac, 0x92, 0xe9, 0x60, 0xf1}}
return a, nil
}

View File

@ -5,9 +5,8 @@ package protobuf
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -5,9 +5,8 @@ package protobuf
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -5,9 +5,8 @@ package protobuf
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -7,7 +7,8 @@ import (
encryptmigrations "github.com/status-im/status-go/protocol/encryption/migrations"
appmigrations "github.com/status-im/status-go/protocol/migrations"
transpmigrations "github.com/status-im/status-go/protocol/transport/whisper/migrations"
wakumigrations "github.com/status-im/status-go/protocol/transport/waku/migrations"
whispermigrations "github.com/status-im/status-go/protocol/transport/whisper/migrations"
)
type getter func(string) ([]byte, error)
@ -19,8 +20,12 @@ type migrationsWithGetter struct {
var defaultMigrations = []migrationsWithGetter{
{
Names: transpmigrations.AssetNames(),
Getter: transpmigrations.Asset,
Names: whispermigrations.AssetNames(),
Getter: whispermigrations.Asset,
},
{
Names: wakumigrations.AssetNames(),
Getter: wakumigrations.Asset,
},
{
Names: encryptmigrations.AssetNames(),

View File

@ -0,0 +1,22 @@
package transport
import (
"github.com/status-im/status-go/eth-node/types"
"go.uber.org/zap"
)
type EnvelopesMonitorConfig struct {
EnvelopeEventsHandler EnvelopeEventsHandler
MaxAttempts int
MailserverConfirmationsEnabled bool
IsMailserver func(types.EnodeID) bool
Logger *zap.Logger
}
// EnvelopeEventsHandler used for two different event types.
type EnvelopeEventsHandler interface {
EnvelopeSent([][]byte)
EnvelopeExpired([][]byte, error)
MailServerRequestCompleted(types.Hash, types.Hash, []byte, error)
MailServerRequestExpired(types.Hash)
}

View File

@ -0,0 +1,30 @@
package transport
import "github.com/status-im/status-go/eth-node/types"
// TODO: revise fields encoding/decoding. Some are encoded using hexutil and some using encoding/hex.
type Filter struct {
// ChatID is the identifier of the chat
ChatID string `json:"chatId"`
// FilterID the whisper filter id generated
FilterID string `json:"filterId"`
// SymKeyID is the symmetric key id used for symmetric filters
SymKeyID string `json:"symKeyId"`
// OneToOne tells us if we need to use asymmetric encryption for this chat
OneToOne bool `json:"oneToOne"`
// Identity is the public key of the other recipient for non-public filters.
// It's encoded using encoding/hex.
Identity string `json:"identity"`
// Topic is the whisper topic
Topic types.TopicType `json:"topic"`
// Discovery is whether this is a discovery topic
Discovery bool `json:"discovery"`
// Negotiated tells us whether is a negotiated topic
Negotiated bool `json:"negotiated"`
// Listen is whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic
Listen bool `json:"listen"`
}
func (c *Filter) IsPublic() bool {
return !c.OneToOne
}

View File

@ -1,66 +1,47 @@
package whisper
package transport
import (
"crypto/ecdsa"
"database/sql"
"encoding/hex"
"math/big"
"strconv"
"sync"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
const (
discoveryTopic = "contact-discovery"
minPow = 0.0
)
var (
// The number of partitions.
nPartitions = big.NewInt(5000)
minPow = 0.0
)
type whisperFilter struct {
type RawFilter struct {
FilterID string
Topic types.TopicType
SymKeyID string
}
// TODO: revise fields encoding/decoding. Some are encoded using hexutil and some using encoding/hex.
type Filter struct {
// ChatID is the identifier of the chat
ChatID string `json:"chatId"`
// FilterID the whisper filter id generated
FilterID string `json:"filterId"`
// SymKeyID is the symmetric key id used for symmetric filters
SymKeyID string `json:"symKeyId"`
// OneToOne tells us if we need to use asymmetric encryption for this chat
OneToOne bool `json:"oneToOne"`
// Identity is the public key of the other recipient for non-public filters.
// It's encoded using encoding/hex.
Identity string `json:"identity"`
// Topic is the whisper topic
Topic types.TopicType `json:"topic"`
// Discovery is whether this is a discovery topic
Discovery bool `json:"discovery"`
// Negotiated tells us whether is a negotiated topic
Negotiated bool `json:"negotiated"`
// Listen is whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic
Listen bool `json:"listen"`
type KeysPersistence interface {
All() (map[string][]byte, error)
Add(chatID string, key []byte) error
}
func (c *Filter) IsPublic() bool {
return !c.OneToOne
type FiltersService interface {
AddKeyPair(key *ecdsa.PrivateKey) (string, error)
DeleteKeyPair(keyID string) bool
AddSymKeyDirect(key []byte) (string, error)
AddSymKeyFromPassword(password string) (string, error)
GetSymKey(id string) ([]byte, error)
DeleteSymKey(id string) bool
Subscribe(opts *types.SubscriptionOptions) (string, error)
Unsubscribe(id string) error
}
type filtersManager struct {
whisper types.Whisper
persistence *sqlitePersistence
type FiltersManager struct {
service FiltersService
persistence KeysPersistence
privateKey *ecdsa.PrivateKey
keys map[string][]byte // a cache of symmetric manager derived from passwords
logger *zap.Logger
@ -71,22 +52,20 @@ type filtersManager struct {
filters map[string]*Filter
}
// newFiltersManager returns a new filtersManager.
func newFiltersManager(db *sql.DB, w types.Whisper, privateKey *ecdsa.PrivateKey, logger *zap.Logger) (*filtersManager, error) {
// NewFiltersManager returns a new filtersManager.
func NewFiltersManager(persistence KeysPersistence, service FiltersService, privateKey *ecdsa.PrivateKey, logger *zap.Logger) (*FiltersManager, error) {
if logger == nil {
logger = zap.NewNop()
}
persistence := newSQLitePersistence(db)
keys, err := persistence.All()
if err != nil {
return nil, err
}
return &filtersManager{
return &FiltersManager{
privateKey: privateKey,
whisper: w,
service: service,
persistence: persistence,
keys: keys,
filters: make(map[string]*Filter),
@ -94,7 +73,7 @@ func newFiltersManager(db *sql.DB, w types.Whisper, privateKey *ecdsa.PrivateKey
}, nil
}
func (s *filtersManager) Init(
func (s *FiltersManager) Init(
chatIDs []string,
publicKeys []*ecdsa.PublicKey,
) ([]*Filter, error) {
@ -146,7 +125,7 @@ func (s *filtersManager) Init(
}
// DEPRECATED
func (s *filtersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
func (s *FiltersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
var (
chatIDs []string
publicKeys []*ecdsa.PublicKey
@ -154,7 +133,7 @@ func (s *filtersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
for _, filter := range filters {
if filter.Identity != "" && filter.OneToOne {
publicKey, err := strToPublicKey(filter.Identity)
publicKey, err := StrToPublicKey(filter.Identity)
if err != nil {
return nil, err
}
@ -167,7 +146,7 @@ func (s *filtersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
return s.Init(chatIDs, publicKeys)
}
func (s *filtersManager) Reset() error {
func (s *FiltersManager) Reset() error {
var filters []*Filter
s.mutex.Lock()
@ -179,7 +158,7 @@ func (s *filtersManager) Reset() error {
return s.Remove(filters...)
}
func (s *filtersManager) Filters() (result []*Filter) {
func (s *FiltersManager) Filters() (result []*Filter) {
s.mutex.Lock()
defer s.mutex.Unlock()
@ -190,14 +169,14 @@ func (s *filtersManager) Filters() (result []*Filter) {
return
}
func (s *filtersManager) Filter(chatID string) *Filter {
func (s *FiltersManager) Filter(chatID string) *Filter {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.filters[chatID]
}
// FilterByFilterID returns a Filter with a given Whisper filter ID.
func (s *filtersManager) FilterByFilterID(filterID string) *Filter {
func (s *FiltersManager) FilterByFilterID(filterID string) *Filter {
s.mutex.Lock()
defer s.mutex.Unlock()
for _, f := range s.filters {
@ -208,11 +187,11 @@ func (s *filtersManager) FilterByFilterID(filterID string) *Filter {
return nil
}
func (s *filtersManager) FiltersByPublicKey(publicKey *ecdsa.PublicKey) (result []*Filter) {
func (s *FiltersManager) FiltersByPublicKey(publicKey *ecdsa.PublicKey) (result []*Filter) {
s.mutex.Lock()
defer s.mutex.Unlock()
identityStr := publicKeyToStr(publicKey)
identityStr := PublicKeyToStr(publicKey)
for _, f := range s.filters {
if f.Identity == identityStr {
@ -224,16 +203,16 @@ func (s *filtersManager) FiltersByPublicKey(publicKey *ecdsa.PublicKey) (result
}
// Remove remove all the filters associated with a chat/identity
func (s *filtersManager) Remove(filters ...*Filter) error {
func (s *FiltersManager) Remove(filters ...*Filter) error {
s.mutex.Lock()
defer s.mutex.Unlock()
for _, f := range filters {
if err := s.whisper.Unsubscribe(f.FilterID); err != nil {
if err := s.service.Unsubscribe(f.FilterID); err != nil {
return err
}
if f.SymKeyID != "" {
s.whisper.DeleteSymKey(f.SymKeyID)
s.service.DeleteSymKey(f.SymKeyID)
}
delete(s.filters, f.ChatID)
}
@ -242,19 +221,19 @@ func (s *filtersManager) Remove(filters ...*Filter) error {
}
// LoadPartitioned creates a filter for a partitioned topic.
func (s *filtersManager) LoadPartitioned(publicKey *ecdsa.PublicKey) (*Filter, error) {
func (s *FiltersManager) LoadPartitioned(publicKey *ecdsa.PublicKey) (*Filter, error) {
return s.loadPartitioned(publicKey, false)
}
func (s *filtersManager) loadMyPartitioned() (*Filter, error) {
func (s *FiltersManager) loadMyPartitioned() (*Filter, error) {
return s.loadPartitioned(&s.privateKey.PublicKey, true)
}
func (s *filtersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool) (*Filter, error) {
func (s *FiltersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
chatID := partitionedTopic(publicKey)
chatID := PartitionedTopic(publicKey)
if _, ok := s.filters[chatID]; ok {
return s.filters[chatID], nil
}
@ -270,7 +249,7 @@ func (s *filtersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool
ChatID: chatID,
FilterID: filter.FilterID,
Topic: filter.Topic,
Identity: publicKeyToStr(publicKey),
Identity: PublicKeyToStr(publicKey),
Listen: listen,
OneToOne: true,
}
@ -281,11 +260,11 @@ func (s *filtersManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool
}
// LoadNegotiated loads a negotiated secret as a filter.
func (s *filtersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter, error) {
func (s *FiltersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
chatID := negotiatedTopic(secret.PublicKey)
chatID := NegotiatedTopic(secret.PublicKey)
if _, ok := s.filters[chatID]; ok {
return s.filters[chatID], nil
@ -302,7 +281,7 @@ func (s *filtersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter,
Topic: filter.Topic,
SymKeyID: filter.SymKeyID,
FilterID: filter.FilterID,
Identity: publicKeyToStr(secret.PublicKey),
Identity: PublicKeyToStr(secret.PublicKey),
Negotiated: true,
Listen: true,
OneToOne: true,
@ -315,11 +294,11 @@ func (s *filtersManager) LoadNegotiated(secret types.NegotiatedSecret) (*Filter,
// LoadDiscovery adds 1 discovery filter
// for the personal discovery topic.
func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
func (s *FiltersManager) LoadDiscovery() ([]*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
personalDiscoveryTopic := personalDiscoveryTopic(&s.privateKey.PublicKey)
personalDiscoveryTopic := PersonalDiscoveryTopic(&s.privateKey.PublicKey)
// Check if filters are already loaded.
var result []*Filter
@ -334,9 +313,7 @@ func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
return result, nil
}
var discoveryResponse *whisperFilter
var err error
identityStr := publicKeyToStr(&s.privateKey.PublicKey)
identityStr := PublicKeyToStr(&s.privateKey.PublicKey)
// Load personal discovery
personalDiscoveryChat := &Filter{
@ -347,7 +324,7 @@ func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
OneToOne: true,
}
discoveryResponse, err = s.addAsymmetric(personalDiscoveryChat.ChatID, true)
discoveryResponse, err := s.addAsymmetric(personalDiscoveryChat.ChatID, true)
if err != nil {
return nil, err
}
@ -361,7 +338,7 @@ func (s *filtersManager) LoadDiscovery() ([]*Filter, error) {
}
// LoadPublic adds a filter for a public chat.
func (s *filtersManager) LoadPublic(chatID string) (*Filter, error) {
func (s *FiltersManager) LoadPublic(chatID string) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
@ -389,11 +366,11 @@ func (s *filtersManager) LoadPublic(chatID string) (*Filter, error) {
}
// LoadContactCode creates a filter for the advertise topic for a given public key.
func (s *filtersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, error) {
func (s *FiltersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
chatID := contactCodeTopic(pubKey)
chatID := ContactCodeTopic(pubKey)
if _, ok := s.filters[chatID]; ok {
return s.filters[chatID], nil
@ -409,7 +386,7 @@ func (s *filtersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, erro
FilterID: contactCodeFilter.FilterID,
Topic: contactCodeFilter.Topic,
SymKeyID: contactCodeFilter.SymKeyID,
Identity: publicKeyToStr(pubKey),
Identity: PublicKeyToStr(pubKey),
Listen: true,
}
@ -418,25 +395,25 @@ func (s *filtersManager) LoadContactCode(pubKey *ecdsa.PublicKey) (*Filter, erro
}
// addSymmetric adds a symmetric key filter
func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
func (s *FiltersManager) addSymmetric(chatID string) (*RawFilter, error) {
var symKeyID string
var err error
topic := toTopic(chatID)
topic := ToTopic(chatID)
topics := [][]byte{topic}
symKey, ok := s.keys[chatID]
if ok {
symKeyID, err = s.whisper.AddSymKeyDirect(symKey)
symKeyID, err = s.service.AddSymKeyDirect(symKey)
if err != nil {
return nil, err
}
} else {
symKeyID, err = s.whisper.AddSymKeyFromPassword(chatID)
symKeyID, err = s.service.AddSymKeyFromPassword(chatID)
if err != nil {
return nil, err
}
if symKey, err = s.whisper.GetSymKey(symKeyID); err != nil {
if symKey, err = s.service.GetSymKey(symKeyID); err != nil {
return nil, err
}
s.keys[chatID] = symKey
@ -447,7 +424,7 @@ func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
}
}
id, err := s.whisper.Subscribe(&types.SubscriptionOptions{
id, err := s.service.Subscribe(&types.SubscriptionOptions{
SymKeyID: symKeyID,
PoW: minPow,
Topics: topics,
@ -456,7 +433,7 @@ func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
return nil, err
}
return &whisperFilter{
return &RawFilter{
FilterID: id,
SymKeyID: symKeyID,
Topic: types.BytesToTopic(topic),
@ -465,7 +442,7 @@ func (s *filtersManager) addSymmetric(chatID string) (*whisperFilter, error) {
// addAsymmetricFilter adds a filter with our private key
// and set minPow according to the listen parameter.
func (s *filtersManager) addAsymmetric(chatID string, listen bool) (*whisperFilter, error) {
func (s *FiltersManager) addAsymmetric(chatID string, listen bool) (*RawFilter, error) {
var (
err error
pow = 1.0 // use PoW high enough to discard all messages for the filter
@ -475,15 +452,15 @@ func (s *filtersManager) addAsymmetric(chatID string, listen bool) (*whisperFilt
pow = minPow
}
topic := toTopic(chatID)
topic := ToTopic(chatID)
topics := [][]byte{topic}
privateKeyID, err := s.whisper.AddKeyPair(s.privateKey)
privateKeyID, err := s.service.AddKeyPair(s.privateKey)
if err != nil {
return nil, err
}
id, err := s.whisper.Subscribe(&types.SubscriptionOptions{
id, err := s.service.Subscribe(&types.SubscriptionOptions{
PrivateKeyID: privateKeyID,
PoW: pow,
Topics: topics,
@ -491,58 +468,13 @@ func (s *filtersManager) addAsymmetric(chatID string, listen bool) (*whisperFilt
if err != nil {
return nil, err
}
return &whisperFilter{FilterID: id, Topic: types.BytesToTopic(topic)}, nil
return &RawFilter{FilterID: id, Topic: types.BytesToTopic(topic)}, nil
}
// GetNegotiated returns a negotiated chat given an identity
func (s *filtersManager) GetNegotiated(identity *ecdsa.PublicKey) *Filter {
func (s *FiltersManager) GetNegotiated(identity *ecdsa.PublicKey) *Filter {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.filters[negotiatedTopic(identity)]
}
func toTopic(s string) []byte {
return crypto.Keccak256([]byte(s))[:types.TopicLength]
}
// ToTopic converts a string to a whisper topic.
func ToTopic(s string) []byte {
return toTopic(s)
}
func strToPublicKey(str string) (*ecdsa.PublicKey, error) {
publicKeyBytes, err := hex.DecodeString(str)
if err != nil {
return nil, err
}
return crypto.UnmarshalPubkey(publicKeyBytes)
}
func publicKeyToStr(publicKey *ecdsa.PublicKey) string {
return hex.EncodeToString(crypto.FromECDSAPub(publicKey))
}
func personalDiscoveryTopic(publicKey *ecdsa.PublicKey) string {
return "contact-discovery-" + publicKeyToStr(publicKey)
}
// partitionedTopic returns the associated partitioned topic string
// with the given public key.
func partitionedTopic(publicKey *ecdsa.PublicKey) string {
partition := big.NewInt(0)
partition.Mod(publicKey.X, nPartitions)
return "contact-discovery-" + strconv.FormatInt(partition.Int64(), 10)
}
func ContactCodeTopic(publicKey *ecdsa.PublicKey) string {
return contactCodeTopic(publicKey)
}
func contactCodeTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + publicKeyToStr(publicKey) + "-contact-code"
}
func negotiatedTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + publicKeyToStr(publicKey) + "-negotiated"
return s.filters[NegotiatedTopic(identity)]
}

View File

@ -0,0 +1,13 @@
package transport
import "github.com/status-im/status-go/eth-node/types"
func DefaultMessage() types.NewMessage {
msg := types.NewMessage{}
msg.TTL = 10
msg.PowTarget = 0.002
msg.PowTime = 1
return msg
}

View File

@ -0,0 +1,59 @@
package transport
import (
"crypto/ecdsa"
"encoding/hex"
"math/big"
"strconv"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
)
const discoveryTopic = "contact-discovery"
var (
// The number of partitions.
nPartitions = big.NewInt(5000)
)
// ToTopic converts a string to a whisper topic.
func ToTopic(s string) []byte {
return crypto.Keccak256([]byte(s))[:types.TopicLength]
}
func StrToPublicKey(str string) (*ecdsa.PublicKey, error) {
publicKeyBytes, err := hex.DecodeString(str)
if err != nil {
return nil, err
}
return crypto.UnmarshalPubkey(publicKeyBytes)
}
func PublicKeyToStr(publicKey *ecdsa.PublicKey) string {
return hex.EncodeToString(crypto.FromECDSAPub(publicKey))
}
func PersonalDiscoveryTopic(publicKey *ecdsa.PublicKey) string {
return "contact-discovery-" + PublicKeyToStr(publicKey)
}
// PartitionedTopic returns the associated partitioned topic string
// with the given public key.
func PartitionedTopic(publicKey *ecdsa.PublicKey) string {
partition := big.NewInt(0)
partition.Mod(publicKey.X, nPartitions)
return "contact-discovery-" + strconv.FormatInt(partition.Int64(), 10)
}
func ContactCodeTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + PublicKeyToStr(publicKey) + "-contact-code"
}
func NegotiatedTopic(publicKey *ecdsa.PublicKey) string {
return "0x" + PublicKeyToStr(publicKey) + "-negotiated"
}
func DiscoveryTopic() string {
return discoveryTopic
}

View File

@ -0,0 +1,38 @@
package transport
import (
"context"
"crypto/ecdsa"
"github.com/status-im/status-go/eth-node/types"
)
type Transport interface {
Stop() error
JoinPrivate(publicKey *ecdsa.PublicKey) error
LeavePrivate(publicKey *ecdsa.PublicKey) error
JoinGroup(publicKeys []*ecdsa.PublicKey) error
LeaveGroup(publicKeys []*ecdsa.PublicKey) error
JoinPublic(chatID string) error
LeavePublic(chatID string) error
SendPublic(ctx context.Context, newMessage *types.NewMessage, chatName string) ([]byte, error)
SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error)
SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error)
SendMessagesRequest(
ctx context.Context,
peerID []byte,
from, to uint32,
previousCursor []byte,
) (cursor []byte, err error)
Track(identifiers [][]byte, hash []byte, newMessage *types.NewMessage)
InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*Filter, error)
LoadFilters(filters []*Filter) ([]*Filter, error)
RemoveFilters(filters []*Filter) error
ResetFilters() error
ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*Filter, error)
RetrieveRawAll() (map[Filter][]*types.Message, error)
}

View File

@ -0,0 +1,310 @@
package waku
import (
"context"
"errors"
"sync"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/transport"
)
// EnvelopeState in local tracker
type EnvelopeState int
const (
// NotRegistered returned if asked hash wasn't registered in the tracker.
NotRegistered EnvelopeState = -1
// EnvelopePosted is set when envelope was added to a local waku queue.
EnvelopePosted EnvelopeState = iota
// EnvelopeSent is set when envelope is sent to at least one peer.
EnvelopeSent
)
// EnvelopeEventsHandler used for two different event types.
type EnvelopeEventsHandler interface {
EnvelopeSent([][]byte)
EnvelopeExpired([][]byte, error)
MailServerRequestCompleted(types.Hash, types.Hash, []byte, error)
MailServerRequestExpired(types.Hash)
}
// NewEnvelopesMonitor returns a pointer to an instance of the EnvelopesMonitor.
func NewEnvelopesMonitor(w types.Waku, config transport.EnvelopesMonitorConfig) *EnvelopesMonitor {
logger := config.Logger
if logger == nil {
logger = zap.NewNop()
}
var api types.PublicWakuAPI
if w != nil {
api = w.PublicWakuAPI()
}
return &EnvelopesMonitor{
w: w,
api: api,
handler: config.EnvelopeEventsHandler,
mailServerConfirmation: config.MailserverConfirmationsEnabled,
maxAttempts: config.MaxAttempts,
isMailserver: config.IsMailserver,
logger: logger.With(zap.Namespace("EnvelopesMonitor")),
// key is envelope hash (event.Hash)
envelopes: map[types.Hash]EnvelopeState{},
messages: map[types.Hash]*types.NewMessage{},
attempts: map[types.Hash]int{},
identifiers: make(map[types.Hash][][]byte),
// key is hash of the batch (event.Batch)
batches: map[types.Hash]map[types.Hash]struct{}{},
}
}
// EnvelopesMonitor is responsible for monitoring waku envelopes state.
type EnvelopesMonitor struct {
w types.Waku
api types.PublicWakuAPI
handler EnvelopeEventsHandler
mailServerConfirmation bool
maxAttempts int
mu sync.Mutex
envelopes map[types.Hash]EnvelopeState
batches map[types.Hash]map[types.Hash]struct{}
messages map[types.Hash]*types.NewMessage
attempts map[types.Hash]int
identifiers map[types.Hash][][]byte
wg sync.WaitGroup
quit chan struct{}
isMailserver func(peer types.EnodeID) bool
logger *zap.Logger
}
// Start processing events.
func (m *EnvelopesMonitor) Start() {
m.quit = make(chan struct{})
m.wg.Add(1)
go func() {
m.handleEnvelopeEvents()
m.wg.Done()
}()
}
// Stop process events.
func (m *EnvelopesMonitor) Stop() {
close(m.quit)
m.wg.Wait()
}
// Add hash to a tracker.
func (m *EnvelopesMonitor) Add(identifiers [][]byte, envelopeHash types.Hash, message types.NewMessage) {
m.mu.Lock()
defer m.mu.Unlock()
m.envelopes[envelopeHash] = EnvelopePosted
m.identifiers[envelopeHash] = identifiers
m.messages[envelopeHash] = &message
m.attempts[envelopeHash] = 1
}
func (m *EnvelopesMonitor) GetState(hash types.Hash) EnvelopeState {
m.mu.Lock()
defer m.mu.Unlock()
state, exist := m.envelopes[hash]
if !exist {
return NotRegistered
}
return state
}
// handleEnvelopeEvents processes waku envelope events
func (m *EnvelopesMonitor) handleEnvelopeEvents() {
events := make(chan types.EnvelopeEvent, 100) // must be buffered to prevent blocking waku
sub := m.w.SubscribeEnvelopeEvents(events)
defer func() {
close(events)
sub.Unsubscribe()
}()
for {
select {
case <-m.quit:
return
case event := <-events:
m.handleEvent(event)
}
}
}
// handleEvent based on type of the event either triggers
// confirmation handler or removes hash from tracker
func (m *EnvelopesMonitor) handleEvent(event types.EnvelopeEvent) {
handlers := map[types.EventType]func(types.EnvelopeEvent){
types.EventEnvelopeSent: m.handleEventEnvelopeSent,
types.EventEnvelopeExpired: m.handleEventEnvelopeExpired,
types.EventBatchAcknowledged: m.handleAcknowledgedBatch,
types.EventEnvelopeReceived: m.handleEventEnvelopeReceived,
}
if handler, ok := handlers[event.Event]; ok {
handler(event)
}
}
func (m *EnvelopesMonitor) handleEventEnvelopeSent(event types.EnvelopeEvent) {
if m.mailServerConfirmation {
if !m.isMailserver(event.Peer) {
return
}
}
m.mu.Lock()
defer m.mu.Unlock()
state, ok := m.envelopes[event.Hash]
// if we didn't send a message using extension - skip it
// if message was already confirmed - skip it
if !ok || state == EnvelopeSent {
return
}
m.logger.Debug("envelope is sent", zap.String("hash", event.Hash.String()), zap.String("peer", event.Peer.String()))
if event.Batch != (types.Hash{}) {
if _, ok := m.batches[event.Batch]; !ok {
m.batches[event.Batch] = map[types.Hash]struct{}{}
}
m.batches[event.Batch][event.Hash] = struct{}{}
m.logger.Debug("waiting for a confirmation", zap.String("batch", event.Batch.String()))
} else {
m.envelopes[event.Hash] = EnvelopeSent
if m.handler != nil {
m.handler.EnvelopeSent(m.identifiers[event.Hash])
}
}
}
func (m *EnvelopesMonitor) handleAcknowledgedBatch(event types.EnvelopeEvent) {
if m.mailServerConfirmation {
if !m.isMailserver(event.Peer) {
return
}
}
m.mu.Lock()
defer m.mu.Unlock()
envelopes, ok := m.batches[event.Batch]
if !ok {
m.logger.Debug("batch is not found", zap.String("batch", event.Batch.String()))
}
m.logger.Debug("received a confirmation", zap.String("batch", event.Batch.String()), zap.String("peer", event.Peer.String()))
envelopeErrors, ok := event.Data.([]types.EnvelopeError)
if event.Data != nil && !ok {
m.logger.Error("received unexpected data in the the confirmation event", zap.String("batch", event.Batch.String()))
}
failedEnvelopes := map[types.Hash]struct{}{}
for i := range envelopeErrors {
envelopeError := envelopeErrors[i]
_, exist := m.envelopes[envelopeError.Hash]
if exist {
m.logger.Warn("envelope that was posted by us is discarded", zap.String("hash", envelopeError.Hash.String()), zap.String("peer", event.Peer.String()), zap.String("error", envelopeError.Description))
var err error
switch envelopeError.Code {
case types.EnvelopeTimeNotSynced:
err = errors.New("envelope wasn't delivered due to time sync issues")
}
m.handleEnvelopeFailure(envelopeError.Hash, err)
}
failedEnvelopes[envelopeError.Hash] = struct{}{}
}
for hash := range envelopes {
if _, exist := failedEnvelopes[hash]; exist {
continue
}
state, ok := m.envelopes[hash]
if !ok || state == EnvelopeSent {
continue
}
m.envelopes[hash] = EnvelopeSent
if m.handler != nil {
m.handler.EnvelopeSent(m.identifiers[hash])
}
}
delete(m.batches, event.Batch)
}
func (m *EnvelopesMonitor) handleEventEnvelopeExpired(event types.EnvelopeEvent) {
m.mu.Lock()
defer m.mu.Unlock()
m.handleEnvelopeFailure(event.Hash, errors.New("envelope expired due to connectivity issues"))
}
// handleEnvelopeFailure is a common code path for processing envelopes failures. not thread safe, lock
// must be used on a higher level.
func (m *EnvelopesMonitor) handleEnvelopeFailure(hash types.Hash, err error) {
if state, ok := m.envelopes[hash]; ok {
message, exist := m.messages[hash]
if !exist {
m.logger.Error("message was deleted erroneously", zap.String("envelope hash", hash.String()))
}
attempt := m.attempts[hash]
identifiers := m.identifiers[hash]
m.clearMessageState(hash)
if state == EnvelopeSent {
return
}
if attempt < m.maxAttempts {
m.logger.Debug("retrying to send a message", zap.String("hash", hash.String()), zap.Int("attempt", attempt+1))
hex, err := m.api.Post(context.TODO(), *message)
if err != nil {
m.logger.Error("failed to retry sending message", zap.String("hash", hash.String()), zap.Int("attempt", attempt+1), zap.Error(err))
if m.handler != nil {
m.handler.EnvelopeExpired(identifiers, err)
}
}
envelopeID := types.BytesToHash(hex)
m.envelopes[envelopeID] = EnvelopePosted
m.messages[envelopeID] = message
m.attempts[envelopeID] = attempt + 1
m.identifiers[envelopeID] = identifiers
} else {
m.logger.Debug("envelope expired", zap.String("hash", hash.String()))
if m.handler != nil {
m.handler.EnvelopeExpired(identifiers, err)
}
}
}
}
func (m *EnvelopesMonitor) handleEventEnvelopeReceived(event types.EnvelopeEvent) {
if m.mailServerConfirmation {
if !m.isMailserver(event.Peer) {
return
}
}
m.mu.Lock()
defer m.mu.Unlock()
state, ok := m.envelopes[event.Hash]
if !ok || state != EnvelopePosted {
return
}
m.logger.Debug("expected envelope received", zap.String("hash", event.Hash.String()), zap.String("peer", event.Peer.String()))
m.envelopes[event.Hash] = EnvelopeSent
if m.handler != nil {
m.handler.EnvelopeSent(m.identifiers[event.Hash])
}
}
// clearMessageState removes all message and envelope state.
// not thread-safe, should be protected on a higher level.
func (m *EnvelopesMonitor) clearMessageState(envelopeID types.Hash) {
delete(m.envelopes, envelopeID)
delete(m.messages, envelopeID)
delete(m.attempts, envelopeID)
delete(m.identifiers, envelopeID)
}

View File

@ -0,0 +1,38 @@
package waku
import (
"encoding/hex"
"math/big"
"github.com/google/uuid"
"github.com/status-im/status-go/eth-node/types"
)
func createMessagesRequest(from, to uint32, cursor []byte, topics []types.TopicType) types.MessagesRequest {
aUUID := uuid.New()
// uuid is 16 bytes, converted to hex it's 32 bytes as expected by types.MessagesRequest
id := []byte(hex.EncodeToString(aUUID[:]))
return types.MessagesRequest{
ID: id,
From: from,
To: to,
Limit: 100,
Cursor: cursor,
Bloom: topicsToBloom(topics...),
}
}
func topicsToBloom(topics ...types.TopicType) []byte {
i := new(big.Int)
for _, topic := range topics {
bloom := types.TopicToBloom(topic)
i.Or(i, new(big.Int).SetBytes(bloom[:]))
}
combined := make([]byte, types.BloomFilterSize)
data := i.Bytes()
copy(combined[types.BloomFilterSize-len(data):], data[:])
return combined
}

View File

@ -0,0 +1,319 @@
// Code generated by go-bindata. DO NOT EDIT.
// sources:
// 1561059284_add_waku_keys.down.sql (22B)
// 1561059284_add_waku_keys.up.sql (109B)
// doc.go (373B)
package sqlite
import (
"bytes"
"compress/gzip"
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
}
if clErr != nil {
return nil, err
}
return buf.Bytes(), nil
}
type asset struct {
bytes []byte
info os.FileInfo
digest [sha256.Size]byte
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
func (fi bindataFileInfo) Name() string {
return fi.name
}
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
func (fi bindataFileInfo) IsDir() bool {
return false
}
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
var __1561059284_add_waku_keysDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x28\x4f\xcc\x2e\x8d\xcf\x4e\xad\x2c\xb6\xe6\x02\x04\x00\x00\xff\xff\x4f\x00\xe6\x8e\x16\x00\x00\x00")
func _1561059284_add_waku_keysDownSqlBytes() ([]byte, error) {
return bindataRead(
__1561059284_add_waku_keysDownSql,
"1561059284_add_waku_keys.down.sql",
)
}
func _1561059284_add_waku_keysDownSql() (*asset, error) {
bytes, err := _1561059284_add_waku_keysDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1561059284_add_waku_keys.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1578604329, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0x2a, 0x7e, 0x9, 0xa3, 0xdd, 0xc6, 0x3, 0xfa, 0xaa, 0x98, 0xa0, 0x26, 0x5e, 0x67, 0x43, 0xe6, 0x20, 0xfd, 0x10, 0xfd, 0x60, 0x89, 0x17, 0x13, 0x87, 0x1b, 0x44, 0x36, 0x79, 0xb6, 0x60}}
return a, nil
}
var __1561059284_add_waku_keysUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x04\xc0\xb1\x0a\xc2\x40\x0c\x06\xe0\xfd\x9e\xe2\x1f\x15\x7c\x03\xa7\xbb\x33\x6a\x30\x26\x12\x52\x6a\xa7\x52\xb4\xa0\xdc\xa8\x22\x7d\xfb\x7e\xd5\x29\x07\x21\x72\x11\xc2\x7f\x6a\xbf\xb1\xcd\xcb\x07\x9b\x04\x3c\x5e\xd3\x77\x7c\x3f\x11\x74\x0f\xdc\x9c\xaf\xd9\x07\x5c\x68\x80\x29\xaa\xe9\x51\xb8\x06\xf8\xa4\xe6\xb4\x4b\x40\x9b\x17\x14\xb1\x02\xb5\x80\x76\x22\x69\x8b\x9e\xe3\x6c\x5d\xc0\xad\xe7\xc3\x3e\xad\x01\x00\x00\xff\xff\xbc\x45\x31\x54\x6d\x00\x00\x00")
func _1561059284_add_waku_keysUpSqlBytes() ([]byte, error) {
return bindataRead(
__1561059284_add_waku_keysUpSql,
"1561059284_add_waku_keys.up.sql",
)
}
func _1561059284_add_waku_keysUpSql() (*asset, error) {
bytes, err := _1561059284_add_waku_keysUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1561059284_add_waku_keys.up.sql", size: 109, mode: os.FileMode(0644), modTime: time.Unix(1578604337, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x5c, 0x8, 0x32, 0xef, 0x12, 0x88, 0x21, 0xd, 0x7a, 0x42, 0x4d, 0xe7, 0x2d, 0x6c, 0x99, 0xb6, 0x1, 0xf1, 0xba, 0x2c, 0x40, 0x8d, 0xa9, 0x4b, 0xe6, 0xc4, 0x21, 0xec, 0x47, 0x6b, 0xf7}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\x3d\x72\xeb\x30\x0c\x84\x7b\x9d\x62\xc7\x8d\x9b\x27\xb2\x79\x55\xba\x94\xe9\x73\x01\x98\x5a\x91\x18\x4b\xa4\x42\xc0\x7f\xb7\xcf\xc8\xe3\xc2\x5d\xda\x1d\x7c\x1f\x76\x63\xc4\x77\x51\xc3\xac\x0b\xa1\x86\xca\x44\x33\xe9\x0f\x9c\x98\xe4\x62\xc4\x21\xab\x97\xcb\x29\xa4\xb6\x46\x73\xf1\x8b\x8d\xba\xc6\x55\x73\x17\x67\xbc\xfe\x3f\x0c\x31\x22\x49\x3d\x3a\x8a\xd4\x69\xe1\xd3\x65\x30\x97\xee\x5a\x33\x6e\xea\x05\x82\xad\x73\xd6\x7b\xc0\xa7\x63\xa1\x98\xc3\x8b\xf8\xd1\xe0\x85\x48\x62\xdc\x35\x73\xeb\xc8\x6d\x3c\x69\x9d\xc4\x25\xec\xd1\xd7\xfc\x96\xec\x0d\x93\x2c\x0b\x27\xcc\xbd\xad\x4f\xd6\x64\x25\x26\xed\x4c\xde\xfa\xe3\x1f\xc4\x8c\x8e\x2a\x2b\x6d\xe7\x8b\x5c\x89\xda\x5e\xef\x21\x75\xfa\x7b\x11\x6e\xad\x9f\x0d\x62\xe0\x7d\x63\x72\x4e\x61\x18\x36\x49\x67\xc9\x84\xfd\x2c\xea\x1c\x86\x18\x73\xfb\xc8\xac\xdc\xa9\xf7\x8e\xe3\x76\xce\xaf\x2b\x8c\x0d\x21\xbc\xd4\xda\xaa\x85\xdc\x10\x86\xdf\x00\x00\x00\xff\xff\x21\xa5\x75\x05\x75\x01\x00\x00")
func docGoBytes() ([]byte, error) {
return bindataRead(
_docGo,
"doc.go",
)
}
func docGo() (*asset, error) {
bytes, err := docGoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 373, mode: os.FileMode(0644), modTime: time.Unix(1578604293, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x23, 0x6a, 0xc1, 0xce, 0x94, 0xf6, 0xef, 0xf1, 0x97, 0x95, 0xb, 0x35, 0xaf, 0x5f, 0xe7, 0x5f, 0xac, 0x6e, 0xb8, 0xab, 0xba, 0xb5, 0x35, 0x97, 0x22, 0x36, 0x11, 0xce, 0x44, 0xfc, 0xfa, 0xac}}
return a, nil
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}
return a.bytes, nil
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// AssetString returns the asset contents as a string (instead of a []byte).
func AssetString(name string) (string, error) {
data, err := Asset(name)
return string(data), err
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
a, err := Asset(name)
if err != nil {
panic("asset: Asset(" + name + "): " + err.Error())
}
return a
}
// MustAssetString is like AssetString but panics when Asset would return an
// error. It simplifies safe initialization of global variables.
func MustAssetString(name string) string {
return string(MustAsset(name))
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}
return a.info, nil
}
return nil, fmt.Errorf("AssetInfo %s not found", name)
}
// AssetDigest returns the digest of the file with the given name. It returns an
// error if the asset could not be found or the digest could not be loaded.
func AssetDigest(name string) ([sha256.Size]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
if err != nil {
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err)
}
return a.digest, nil
}
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name)
}
// Digests returns a map of all known files and their checksums.
func Digests() (map[string][sha256.Size]byte, error) {
mp := make(map[string][sha256.Size]byte, len(_bindata))
for name := range _bindata {
a, err := _bindata[name]()
if err != nil {
return nil, err
}
mp[name] = a.digest
}
return mp, nil
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"1561059284_add_waku_keys.down.sql": _1561059284_add_waku_keysDownSql,
"1561059284_add_waku_keys.up.sql": _1561059284_add_waku_keysUpSql,
"doc.go": docGo,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"},
// AssetDir("data/img") would return []string{"a.png", "b.png"},
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
canonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(canonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for childName := range node.Children {
rv = append(rv, childName)
}
return rv, nil
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"1561059284_add_waku_keys.down.sql": &bintree{_1561059284_add_waku_keysDownSql, map[string]*bintree{}},
"1561059284_add_waku_keys.up.sql": &bintree{_1561059284_add_waku_keysUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory.
func RestoreAsset(dir, name string) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}
return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
}
// RestoreAssets restores an asset under the given directory recursively.
func RestoreAssets(dir, name string) error {
children, err := AssetDir(name)
// File
if err != nil {
return RestoreAsset(dir, name)
}
// Dir
for _, child := range children {
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil {
return err
}
}
return nil
}
func _filePath(dir, name string) string {
canonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
}

View File

@ -0,0 +1,57 @@
package waku
import (
"database/sql"
)
type sqlitePersistence struct {
db *sql.DB
}
func newSQLitePersistence(db *sql.DB) *sqlitePersistence {
return &sqlitePersistence{db: db}
}
func (s *sqlitePersistence) Add(chatID string, key []byte) error {
statement := "INSERT INTO waku_keys(chat_id, key) VALUES(?, ?)"
stmt, err := s.db.Prepare(statement)
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(chatID, key)
return err
}
func (s *sqlitePersistence) All() (map[string][]byte, error) {
keys := make(map[string][]byte)
statement := "SELECT chat_id, key FROM waku_keys"
stmt, err := s.db.Prepare(statement)
if err != nil {
return nil, err
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil && err != sql.ErrNoRows {
return nil, err
}
for rows.Next() {
var (
chatID string
key []byte
)
err := rows.Scan(&chatID, &key)
if err != nil {
return nil, err
}
keys[chatID] = key
}
return keys, nil
}

View File

@ -0,0 +1,13 @@
package waku
import (
"github.com/status-im/status-go/eth-node/types"
)
type RequestOptions struct {
Topics []types.TopicType
Password string
Limit int
From int64 // in seconds
To int64 // in seconds
}

View File

@ -0,0 +1,426 @@
package waku
import (
"bytes"
"context"
"crypto/ecdsa"
"database/sql"
"sync"
"github.com/pkg/errors"
"go.uber.org/zap"
"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/transport"
)
var (
// ErrNoMailservers returned if there is no configured mailservers that can be used.
ErrNoMailservers = errors.New("no configured mailservers")
)
type wakuServiceKeysManager struct {
waku types.Waku
// Identity of the current user.
privateKey *ecdsa.PrivateKey
passToSymKeyMutex sync.RWMutex
passToSymKeyCache map[string]string
}
func (m *wakuServiceKeysManager) AddOrGetKeyPair(priv *ecdsa.PrivateKey) (string, error) {
// caching is handled in waku
return m.waku.AddKeyPair(priv)
}
func (m *wakuServiceKeysManager) AddOrGetSymKeyFromPassword(password string) (string, error) {
m.passToSymKeyMutex.Lock()
defer m.passToSymKeyMutex.Unlock()
if val, ok := m.passToSymKeyCache[password]; ok {
return val, nil
}
id, err := m.waku.AddSymKeyFromPassword(password)
if err != nil {
return id, err
}
m.passToSymKeyCache[password] = id
return id, nil
}
func (m *wakuServiceKeysManager) RawSymKey(id string) ([]byte, error) {
return m.waku.GetSymKey(id)
}
type Option func(*WakuServiceTransport) error
// WakuServiceTransport is a transport based on Whisper service.
type WakuServiceTransport struct {
waku types.Waku
api types.PublicWakuAPI // only PublicWakuAPI implements logic to send messages
keysManager *wakuServiceKeysManager
filters *transport.FiltersManager
logger *zap.Logger
mailservers []string
envelopesMonitor *EnvelopesMonitor
}
// NewWakuServiceTransport returns a new WakuServiceTransport.
// TODO: leaving a chat should verify that for a given public key
// there are no other chats. It may happen that we leave a private chat
// but still have a public chat for a given public key.
func NewWakuServiceTransport(
waku types.Waku,
privateKey *ecdsa.PrivateKey,
db *sql.DB,
mailservers []string,
envelopesMonitorConfig *transport.EnvelopesMonitorConfig,
logger *zap.Logger,
opts ...Option,
) (*WakuServiceTransport, error) {
filtersManager, err := transport.NewFiltersManager(newSQLitePersistence(db), waku, privateKey, logger)
if err != nil {
return nil, err
}
var envelopesMonitor *EnvelopesMonitor
if envelopesMonitorConfig != nil {
envelopesMonitor = NewEnvelopesMonitor(waku, *envelopesMonitorConfig)
envelopesMonitor.Start()
}
var api types.PublicWhisperAPI
if waku != nil {
api = waku.PublicWakuAPI()
}
t := &WakuServiceTransport{
waku: waku,
api: api,
envelopesMonitor: envelopesMonitor,
keysManager: &wakuServiceKeysManager{
waku: waku,
privateKey: privateKey,
passToSymKeyCache: make(map[string]string),
},
filters: filtersManager,
mailservers: mailservers,
logger: logger.With(zap.Namespace("WakuServiceTransport")),
}
for _, opt := range opts {
if err := opt(t); err != nil {
return nil, err
}
}
return t, nil
}
func (a *WakuServiceTransport) InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) {
return a.filters.Init(chatIDs, publicKeys)
}
func (a *WakuServiceTransport) Filters() []*transport.Filter {
return a.filters.Filters()
}
// DEPRECATED
func (a *WakuServiceTransport) LoadFilters(filters []*transport.Filter) ([]*transport.Filter, error) {
return a.filters.InitWithFilters(filters)
}
// DEPRECATED
func (a *WakuServiceTransport) RemoveFilters(filters []*transport.Filter) error {
return a.filters.Remove(filters...)
}
func (a *WakuServiceTransport) ResetFilters() error {
return a.filters.Reset()
}
func (a *WakuServiceTransport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*transport.Filter, error) {
filter, err := a.filters.LoadNegotiated(secret)
if err != nil {
return nil, err
}
return filter, nil
}
func (a *WakuServiceTransport) JoinPublic(chatID string) error {
_, err := a.filters.LoadPublic(chatID)
return err
}
func (a *WakuServiceTransport) LeavePublic(chatID string) error {
chat := a.filters.Filter(chatID)
if chat != nil {
return nil
}
return a.filters.Remove(chat)
}
func (a *WakuServiceTransport) JoinPrivate(publicKey *ecdsa.PublicKey) error {
_, err := a.filters.LoadDiscovery()
if err != nil {
return err
}
_, err = a.filters.LoadContactCode(publicKey)
return err
}
func (a *WakuServiceTransport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
filters := a.filters.FiltersByPublicKey(publicKey)
return a.filters.Remove(filters...)
}
func (a *WakuServiceTransport) JoinGroup(publicKeys []*ecdsa.PublicKey) error {
_, err := a.filters.LoadDiscovery()
if err != nil {
return err
}
for _, pk := range publicKeys {
_, err = a.filters.LoadContactCode(pk)
if err != nil {
return err
}
}
return nil
}
func (a *WakuServiceTransport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error {
for _, publicKey := range publicKeys {
filters := a.filters.FiltersByPublicKey(publicKey)
if err := a.filters.Remove(filters...); err != nil {
return err
}
}
return nil
}
type Message struct {
Message *types.Message
Public bool
}
func (a *WakuServiceTransport) RetrieveAllMessages() ([]Message, error) {
var messages []Message
for _, filter := range a.filters.Filters() {
filterMsgs, err := a.api.GetFilterMessages(filter.FilterID)
if err != nil {
return nil, err
}
for _, m := range filterMsgs {
messages = append(messages, Message{
Message: m,
Public: filter.IsPublic(),
})
}
}
return messages, nil
}
func (a *WakuServiceTransport) RetrievePublicMessages(chatID string) ([]*types.Message, error) {
filter, err := a.filters.LoadPublic(chatID)
if err != nil {
return nil, err
}
return a.api.GetFilterMessages(filter.FilterID)
}
func (a *WakuServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]*types.Message, error) {
chats := a.filters.FiltersByPublicKey(publicKey)
discoveryChats, err := a.filters.Init(nil, nil)
if err != nil {
return nil, err
}
var result []*types.Message
for _, chat := range append(chats, discoveryChats...) {
filterMsgs, err := a.api.GetFilterMessages(chat.FilterID)
if err != nil {
return nil, err
}
result = append(result, filterMsgs...)
}
return result, nil
}
func (a *WakuServiceTransport) RetrieveRawAll() (map[transport.Filter][]*types.Message, error) {
result := make(map[transport.Filter][]*types.Message)
allFilters := a.filters.Filters()
for _, filter := range allFilters {
msgs, err := a.api.GetFilterMessages(filter.FilterID)
if err != nil {
continue
}
result[*filter] = append(result[*filter], msgs...)
}
return result, nil
}
// SendPublic sends a new message using the Whisper service.
// For public filters, chat name is used as an ID as well as
// a topic.
func (a *WakuServiceTransport) SendPublic(ctx context.Context, newMessage *types.NewMessage, chatName string) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
filter, err := a.filters.LoadPublic(chatName)
if err != nil {
return nil, err
}
newMessage.SymKeyID = filter.SymKeyID
newMessage.Topic = filter.Topic
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
filter, err := a.filters.LoadNegotiated(types.NegotiatedSecret{
PublicKey: publicKey,
Key: secret,
})
if err != nil {
return nil, err
}
newMessage.SymKeyID = filter.SymKeyID
newMessage.Topic = filter.Topic
newMessage.PublicKey = nil
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
filter, err := a.filters.LoadPartitioned(publicKey)
if err != nil {
return nil, err
}
newMessage.Topic = filter.Topic
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) SendPrivateOnDiscovery(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
if err := a.addSig(newMessage); err != nil {
return nil, err
}
// There is no need to load any chat
// because listening on the discovery topic
// is done automatically.
// TODO: change this anyway, it should be explicit
// and idempotent.
newMessage.Topic = types.BytesToTopic(transport.ToTopic(transport.DiscoveryTopic()))
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
return a.api.Post(ctx, *newMessage)
}
func (a *WakuServiceTransport) addSig(newMessage *types.NewMessage) error {
sigID, err := a.keysManager.AddOrGetKeyPair(a.keysManager.privateKey)
if err != nil {
return err
}
newMessage.SigID = sigID
return nil
}
func (a *WakuServiceTransport) Track(identifiers [][]byte, hash []byte, newMessage *types.NewMessage) {
if a.envelopesMonitor != nil {
a.envelopesMonitor.Add(identifiers, types.BytesToHash(hash), *newMessage)
}
}
func (a *WakuServiceTransport) Stop() error {
if a.envelopesMonitor != nil {
a.envelopesMonitor.Stop()
}
return nil
}
// RequestHistoricMessages requests historic messages for all registered filters.
func (a *WakuServiceTransport) SendMessagesRequest(
ctx context.Context,
peerID []byte,
from, to uint32,
previousCursor []byte,
) (cursor []byte, err error) {
topics := make([]types.TopicType, len(a.Filters()))
for _, f := range a.Filters() {
topics = append(topics, f.Topic)
}
r := createMessagesRequest(from, to, previousCursor, topics)
r.SetDefaults(a.waku.GetCurrentTime())
events := make(chan types.EnvelopeEvent, 10)
sub := a.waku.SubscribeEnvelopeEvents(events)
defer sub.Unsubscribe()
err = a.waku.SendMessagesRequest(peerID, r)
if err != nil {
return
}
resp, err := a.waitForRequestCompleted(ctx, r.ID, events)
if err == nil && resp != nil && resp.Error != nil {
err = resp.Error
} else if err == nil && resp != nil {
cursor = resp.Cursor
}
return
}
func (a *WakuServiceTransport) waitForRequestCompleted(ctx context.Context, requestID []byte, events chan types.EnvelopeEvent) (*types.MailServerResponse, error) {
for {
select {
case ev := <-events:
a.logger.Debug(
"waiting for request completed and received an event",
zap.Binary("requestID", requestID),
zap.Any("event", ev),
)
if !bytes.Equal(ev.Hash.Bytes(), requestID) {
continue
}
if ev.Event != types.EventMailServerRequestCompleted {
continue
}
data, ok := ev.Data.(*types.MailServerResponse)
if ok {
return data, nil
}
case <-ctx.Done():
return nil, ctx.Err()
}
}
}

View File

@ -5,6 +5,8 @@ import (
"errors"
"sync"
"github.com/status-im/status-go/protocol/transport"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/types"
@ -18,18 +20,10 @@ const (
NotRegistered EnvelopeState = -1
// EnvelopePosted is set when envelope was added to a local whisper queue.
EnvelopePosted EnvelopeState = iota
// EnvelopeSent is set when envelope is sent to atleast one peer.
// EnvelopeSent is set when envelope is sent to at least one peer.
EnvelopeSent
)
type EnvelopesMonitorConfig struct {
EnvelopeEventsHandler EnvelopeEventsHandler
MaxAttempts int
MailserverConfirmationsEnabled bool
IsMailserver func(types.EnodeID) bool
Logger *zap.Logger
}
// EnvelopeEventsHandler used for two different event types.
type EnvelopeEventsHandler interface {
EnvelopeSent([][]byte)
@ -39,7 +33,7 @@ type EnvelopeEventsHandler interface {
}
// NewEnvelopesMonitor returns a pointer to an instance of the EnvelopesMonitor.
func NewEnvelopesMonitor(w types.Whisper, config EnvelopesMonitorConfig) *EnvelopesMonitor {
func NewEnvelopesMonitor(w types.Whisper, config transport.EnvelopesMonitorConfig) *EnvelopesMonitor {
logger := config.Logger
if logger == nil {

View File

@ -9,8 +9,6 @@ import (
"github.com/status-im/status-go/eth-node/types"
)
const defaultMessagesRequestLimit = 100
func createMessagesRequest(from, to uint32, cursor []byte, topics []types.TopicType) types.MessagesRequest {
aUUID := uuid.New()
// uuid is 16 bytes, converted to hex it's 32 bytes as expected by types.MessagesRequest
@ -19,7 +17,7 @@ func createMessagesRequest(from, to uint32, cursor []byte, topics []types.TopicT
ID: id,
From: from,
To: to,
Limit: defaultMessagesRequestLimit,
Limit: 100,
Cursor: cursor,
Bloom: topicsToBloom(topics...),
}

Some files were not shown because too many files have changed in this diff Show More