Updated Whisper Push Notifications (markdown)

Victor Farazdagi 2017-04-14 10:09:21 +03:00
parent 91635d30d5
commit a11542c039
1 changed files with 23 additions and 30 deletions

@ -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