status-go/_assets/patches/geth/0014-whisperv6-notification...

280 lines
8.7 KiB
Diff
Raw Normal View History

diff --git a/whisper/whisperv6/api.go b/whisper/whisperv6/api.go
index 8ae2882e1..7c97f0680 100644
--- a/whisper/whisperv6/api.go
+++ b/whisper/whisperv6/api.go
@@ -319,6 +319,16 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
return true, api.w.Send(env)
}
+// UninstallFilter is alias for Unsubscribe
+func (api *PublicWhisperAPI) UninstallFilter(id string) {
+ api.w.Unsubscribe(id)
+}
+
+// Unsubscribe disables and removes an existing filter.
+func (api *PublicWhisperAPI) Unsubscribe(id string) {
+ api.w.Unsubscribe(id)
+}
+
//go:generate gencodec -type Criteria -field-override criteriaOverride -out gen_criteria_json.go
// Criteria holds various filter options for inbound messages.
diff --git a/whisper/whisperv6/doc.go b/whisper/whisperv6/doc.go
index d5d7fed60..5ad660616 100644
--- a/whisper/whisperv6/doc.go
+++ b/whisper/whisperv6/doc.go
@@ -35,6 +35,8 @@ package whisperv6
import (
"fmt"
"time"
+
+ "github.com/ethereum/go-ethereum/p2p"
)
// Whisper protocol parameters
@@ -95,3 +97,15 @@ type MailServer interface {
Archive(env *Envelope)
DeliverMail(whisperPeer *Peer, request *Envelope)
}
+
+// NotificationServer represents a notification server,
+// capable of screening incoming envelopes for special
+// topics, and once located, subscribe client nodes as
+// recipients to notifications (push notifications atm)
+type NotificationServer interface {
+ // Start initializes notification sending loop
+ Start(server *p2p.Server) error
+
+ // Stop stops notification sending loop, releasing related resources
+ Stop() error
+}
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index d75ad04ac..54d7d0f24 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -85,7 +85,8 @@ type Whisper struct {
statsMu sync.Mutex // guard stats
stats Statistics // Statistics of whisper node
- mailServer MailServer // MailServer interface
+ mailServer MailServer // MailServer interface
+ notificationServer NotificationServer
}
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
@@ -209,6 +210,11 @@ func (whisper *Whisper) RegisterServer(server MailServer) {
whisper.mailServer = server
}
+// RegisterNotificationServer registers notification server with Whisper
+func (whisper *Whisper) RegisterNotificationServer(server NotificationServer) {
+ whisper.notificationServer = server
+}
+
// Protocols returns the whisper sub-protocols ran by this particular client.
func (whisper *Whisper) Protocols() []p2p.Protocol {
return []p2p.Protocol{whisper.protocol}
@@ -380,9 +386,9 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
return "", fmt.Errorf("failed to generate valid key")
}
- id, err := GenerateRandomID()
+ id, err := toDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize)
if err != nil {
- return "", fmt.Errorf("failed to generate ID: %s", err)
+ return "", err
}
whisper.keyMu.Lock()
@@ -397,11 +403,16 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
// DeleteKeyPair deletes the specified key if it exists.
func (whisper *Whisper) DeleteKeyPair(key string) bool {
+ deterministicID, err := toDeterministicID(key, keyIDSize)
+ if err != nil {
+ return false
+ }
+
whisper.keyMu.Lock()
defer whisper.keyMu.Unlock()
- if whisper.privateKeys[key] != nil {
- delete(whisper.privateKeys, key)
+ if whisper.privateKeys[deterministicID] != nil {
+ delete(whisper.privateKeys, deterministicID)
return true
}
return false
@@ -409,31 +420,73 @@ func (whisper *Whisper) DeleteKeyPair(key string) bool {
// AddKeyPair imports a asymmetric private key and returns it identifier.
func (whisper *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
- id, err := GenerateRandomID()
+ id, err := makeDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize)
if err != nil {
- return "", fmt.Errorf("failed to generate ID: %s", err)
+ return "", err
+ }
+ if whisper.HasKeyPair(id) {
+ return id, nil // no need to re-inject
}
whisper.keyMu.Lock()
whisper.privateKeys[id] = key
whisper.keyMu.Unlock()
+ log.Info("Whisper identity added", "id", id, "pubkey", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
return id, nil
}
+// SelectKeyPair adds cryptographic identity, and makes sure
+// that it is the only private key known to the node.
+func (whisper *Whisper) SelectKeyPair(key *ecdsa.PrivateKey) error {
+ id, err := makeDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize)
+ if err != nil {
+ return err
+ }
+
+ whisper.keyMu.Lock()
+ defer whisper.keyMu.Unlock()
+
+ whisper.privateKeys = make(map[string]*ecdsa.PrivateKey) // reset key store
+ whisper.privateKeys[id] = key
+
+ log.Info("Whisper identity selected", "id", id, "key", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
+ return nil
+}
+
+// DeleteKeyPairs removes all cryptographic identities known to the node
+func (whisper *Whisper) DeleteKeyPairs() error {
+ whisper.keyMu.Lock()
+ defer whisper.keyMu.Unlock()
+
+ whisper.privateKeys = make(map[string]*ecdsa.PrivateKey)
+
+ return nil
+}
+
// HasKeyPair checks if the the whisper node is configured with the private key
// of the specified public pair.
func (whisper *Whisper) HasKeyPair(id string) bool {
+ deterministicID, err := toDeterministicID(id, keyIDSize)
+ if err != nil {
+ return false
+ }
+
whisper.keyMu.RLock()
defer whisper.keyMu.RUnlock()
- return whisper.privateKeys[id] != nil
+ return whisper.privateKeys[deterministicID] != nil
}
// GetPrivateKey retrieves the private key of the specified identity.
func (whisper *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
+ deterministicID, err := toDeterministicID(id, keyIDSize)
+ if err != nil {
+ return nil, err
+ }
+
whisper.keyMu.RLock()
defer whisper.keyMu.RUnlock()
- key := whisper.privateKeys[id]
+ key := whisper.privateKeys[deterministicID]
if key == nil {
return nil, fmt.Errorf("invalid id")
}
@@ -465,6 +518,23 @@ func (whisper *Whisper) GenerateSymKey() (string, error) {
return id, nil
}
+// AddSymKey stores the key with a given id.
+func (whisper *Whisper) AddSymKey(id string, key []byte) (string, error) {
+ deterministicID, err := toDeterministicID(id, keyIDSize)
+ if err != nil {
+ return "", err
+ }
+
+ whisper.keyMu.Lock()
+ defer whisper.keyMu.Unlock()
+
+ if whisper.symKeys[deterministicID] != nil {
+ return "", fmt.Errorf("key already exists: %v", id)
+ }
+ whisper.symKeys[deterministicID] = key
+ return deterministicID, nil
+}
+
// AddSymKeyDirect stores the key, and returns its id.
func (whisper *Whisper) AddSymKeyDirect(key []byte) (string, error) {
if len(key) != aesKeyLength {
@@ -599,7 +669,7 @@ func (whisper *Whisper) Send(envelope *Envelope) error {
// Start implements node.Service, starting the background data propagation thread
// of the Whisper protocol.
-func (whisper *Whisper) Start(*p2p.Server) error {
+func (whisper *Whisper) Start(stack *p2p.Server) error {
log.Info("started whisper v." + ProtocolVersionStr)
go whisper.update()
@@ -608,6 +678,12 @@ func (whisper *Whisper) Start(*p2p.Server) error {
go whisper.processQueue()
}
+ if whisper.notificationServer != nil {
+ if err := whisper.notificationServer.Start(stack); err != nil {
+ return err
+ }
+ }
+
return nil
}
@@ -615,6 +691,13 @@ func (whisper *Whisper) Start(*p2p.Server) error {
// of the Whisper protocol.
func (whisper *Whisper) Stop() error {
close(whisper.quit)
+
+ if whisper.notificationServer != nil {
+ if err := whisper.notificationServer.Stop(); err != nil {
+ return err
+ }
+ }
+
log.Info("whisper stopped")
return nil
}
@@ -1035,6 +1118,33 @@ func GenerateRandomID() (id string, err error) {
return id, err
}
+// makeDeterministicID generates a deterministic ID, based on a given input
+func makeDeterministicID(input string, keyLen int) (id string, err error) {
+ buf := pbkdf2.Key([]byte(input), nil, 4096, keyLen, sha256.New)
+ if !validateDataIntegrity(buf, keyIDSize) {
+ return "", fmt.Errorf("error in GenerateDeterministicID: failed to generate key")
+ }
+ id = common.Bytes2Hex(buf)
+ return id, err
+}
+
+// toDeterministicID reviews incoming id, and transforms it to format
+// expected internally be private key store. Originally, public keys
+// were used as keys, now random keys are being used. And in order to
+// make it easier to consume, we now allow both random IDs and public
+// keys to be passed.
+func toDeterministicID(id string, expectedLen int) (string, error) {
+ if len(id) != (expectedLen * 2) { // we received hex key, so number of chars in id is doubled
+ var err error
+ id, err = makeDeterministicID(id, expectedLen)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ return id, nil
+}
+
func isFullNode(bloom []byte) bool {
if bloom == nil {
return true