Updated Whisper Push Notifications (markdown)
parent
91635d30d5
commit
a11542c039
|
@ -14,42 +14,34 @@ It is crucial to understand what is **Whisper Notification Service** is designed
|
|||
The crux here is how to allow `DeviceB` to trigger notifications on `DeviceA`, all this w/o knowing much of which wnode is used, or details of `DeviceA`. And `Chat SymKey` solves this issue elegantly (the beauty is that it works for both one-on-one and group chats, all you need to ensure is share a secret, namely `Chat SymKey`, so that newcomers can add their devices to subscribers list).
|
||||
|
||||
**Important Notes:**
|
||||
- `Device A` can start the protocol by broadcasting using Discovery Protocol SymKey. However, `statusd wnode` command (that is used to start notification-enabled wnodes) also supports using asymmetric keys to kick off the process. For further details, see examples below.
|
||||
- `Device A` starts the protocol by sending encrypted message using Discovery Protocol PubKey (Status test cluster will have a single PubKey installed on all the nodes, allowing any of them to respond on discovery requests).
|
||||
- While discovery happens using asymmetric cryptography, once you obtain `Subscription SymKey` and `Chat SymKey` you rely on symmetric encryption.
|
||||
- It is important to understand that notification request messages go *along* the normal communication i.e.
|
||||
- on `DeviceA` you send encrypted message to `DeviceB` (so, only `DeviceB` can open envelope)
|
||||
- once done, you need to send a broadcast message encrypting it with `Chat SymKey`
|
||||
- some node over there, will be able to decrypt your broadcast (the only one that has `Chat SymKey`)
|
||||
- once decrypted, wnode will go over list of device IDs previously registered for this Chat, and send notifications requests to FCM using those IDs (only 1 request for one-on-one chats, `n-1` requests for group of `n` chats - that's we do not notify ourselves)
|
||||
- So, messages are never exposed, and they are routed in parallel. Notifications are also encrypted (by Chat SymKey), so are not exposed to eavesdropper. This means we are not compromising on darkness. The following info gets exposed though:
|
||||
- So, messages are never exposed, and they are routed in parallel. Notifications are also encrypted (by Chat SymKey), so are not exposed to eavesdropper either. This means we are not compromising on darkness. The following info gets exposed though:
|
||||
- by registering device ID with a given chat session we expose it to `wnode`
|
||||
- we expose our PubKeys (wnodes need message to be signed, so that you PubKey can be filtered out, and notification by you towards yourself is avoided)
|
||||
- we may expose some critical information in body of notification message (highly not advised!).
|
||||
|
||||
# Communication Protocol
|
||||
|
||||
## Accessing Notification Service enabled nodes using symmetric/topic keys
|
||||
Suppose, you started service node(s) using `statusd --datadir wnode1 wnode --notify --identity ./wnodekey --firebaseauth ./firebaseuathkey`, where `wnodekey` and `firebaseauthkey` files contain node's private key and FCM authorization key respectively. Now, your server is ready to receive requests encrypted with its PubKey, which for our cluster is `0x040edb0d71a3dbe928e154fcb696ffbda359b153a90efc2b46f0043ce9f5dbe55b77b9328fd841a1db5273758624afadd5b39638d4c35b36b3a96e1a586c1b4c2a`.
|
||||
|
||||
Suppose, you started service node(s) using `statusd --datadir wnode1 wnode --notify --password ./wnodepassword --firebaseauth ./firebaseuathkey`. Such a server will expect certain pre-defined topic symmetrically encrypted with password (that in this example lives in file `wnodepassword`).
|
||||
|
||||
On client side, we need to add that password as symmetric key, to be used later on for discovery requests:
|
||||
On client side, we need to use protocol PubKey and pre-defined topic:
|
||||
|
||||
```javascript
|
||||
var keyname = 'NOTIFICATION_PROTOCOL_KEY';
|
||||
var keypass = 'asdfasdf';
|
||||
// make sure that notification protocol key exists in whisper
|
||||
if (!web3.shh.hasSymKey(keyname)) {
|
||||
console.log("protocol key not found, adding..");
|
||||
web3.shh.addSymKey(keyname, web3.fromAscii(keypass));
|
||||
}
|
||||
|
||||
var sendDiscoveryRequestUsingKeySym = function (identity) {
|
||||
// notification server discovery request is a signed (sent from us) broadcast,
|
||||
// encrypted with Notification Protocol Symmetric Key (which is publicly known)
|
||||
var protocolKey = '0x040edb0d71a3dbe928e154fcb696ffbda359b153a90efc2b46f0043ce9f5dbe55b77b9328fd841a1db5273758624afadd5b39638d4c35b36b3a96e1a586c1b4c2a';
|
||||
var sendDiscoveryRequest = function (identity) {
|
||||
// notification server discovery request is a signed (sent from us),
|
||||
// encrypted with Notification Protocol Asymmetric (Public) Key
|
||||
var err = web3.shh.post({
|
||||
from: identity,
|
||||
to: protocolKey,
|
||||
topics: [discoverServerTopic],
|
||||
ttl: 20,
|
||||
keyname: keyname
|
||||
ttl: 20
|
||||
});
|
||||
if (err !== null) {
|
||||
console.log("message NOT sent")
|
||||
|
@ -58,25 +50,26 @@ var sendDiscoveryRequestUsingKeySym = function (identity) {
|
|||
}
|
||||
};
|
||||
```
|
||||
It is important to understand that this key is publicly known (we will use different password on our cluster, you may use your own password, see `statusd wnode --password` option). So, encryption here doesn't provide privacy - instead, it allows Notification Service capable nodes to filter requests to them (as they will be able to decrypt those messages).
|
||||
|
||||
## Accessing Notification Service enabled nodes using asymmetric key
|
||||
|
||||
Now, `statusd` can be started with loaded identity (which is basically a private key) for asymmetric encryption, e.g. `statusd --datadir wnode1 wnode --notify --identity ./wnodekey --firebaseauth ./firebaseuathkey`. To start a discovery request:
|
||||
|
||||
```js
|
||||
|
||||
Here is the list of topics (see the full sample file, where they are all used):
|
||||
```
|
||||
var discoverServerTopic = '0x268302f3'; // DISCOVER_NOTIFICATION_SERVER
|
||||
var proposeServerTopic = '0x08e3d8c0'; // PROPOSE_NOTIFICATION_SERVER
|
||||
var acceptServerTopic = '0x04f7dea6'; // ACCEPT_NOTIFICATION_SERVER
|
||||
var ackClientSubscriptionTopic = '0x93dafe28'; // ACK_NOTIFICATION_SERVER_SUBSCRIPTION
|
||||
var sendNotificationTopic = '0x69915296'; // SEND_NOTIFICATION
|
||||
var newChatSessionTopic = '0x509579a2'; // NEW_CHAT_SESSION
|
||||
var ackNewChatSessionTopic = '0xd012aae8'; // ACK_NEW_CHAT_SESSION
|
||||
var newDeviceRegistrationTopic = '0x14621a51'; // NEW_DEVICE_REGISTRATION
|
||||
var ackDeviceRegistrationTopic = '0x424358d6'; // ACK_DEVICE_REGISTRATION
|
||||
```
|
||||
|
||||
|
||||
Assume that we have two nodes (`Device A` and `Device B`) which have different underlying nodes:
|
||||
Finally, in order to test everything out, you'd better use two different clients not one. So, assume that we have two nodes (`Device A` and `Device B`) which have different underlying Status daemons:
|
||||
```javascript
|
||||
var web3 = new Web3();
|
||||
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8645')); // Device A
|
||||
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8745')); // Device B
|
||||
```
|
||||
Both nodes have Notification Protocol SymKey added, so can participate in discovery and subscription to Notification Services.
|
||||
|
||||
To support those two different apps, two Status nodes are started:
|
||||
```bash
|
||||
statusd --datadir app1 --http --httpport 8645 --shh
|
||||
|
|
Loading…
Reference in New Issue