forked from status-im/status-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path0014-whisperv6-notifications.patch
279 lines (258 loc) · 8.75 KB
/
0014-whisperv6-notifications.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
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