mirror of
https://github.com/status-im/status-go.git
synced 2025-01-30 08:26:54 +00:00
Updated Whisper Push Notifications (markdown)
parent
347c3bb4a6
commit
0aafec2317
@ -457,16 +457,315 @@ var removeClientSession = function () {
|
||||
|
||||
# Complete Sample
|
||||
|
||||
Full sample page used for testing can be found here: https://gist.github.com/farazdagi/5ac082ddf006d00de422385f07d41ad3
|
||||
We rely on Mocha.js test, to make sure that all aspects of notification sending is covered in reproducible and easy-to-follow manner.
|
||||
|
||||
In order to use that page you need to start the following:
|
||||
In order to use the test you need:
|
||||
- to clone `status-go` repo and `npm install` there (so that Mocha.js and other node modules are installed)
|
||||
- to run `make` (to build the `statusd` daemon)
|
||||
- to start the following:
|
||||
```bash
|
||||
statusd --datadir app1 --http --httpport 8645 wnode # as Device A
|
||||
statusd --datadir app2 --http --httpport 8745 wnode # as Device B
|
||||
statusd --datadir wnode1 wnode --notify --identity ./wnodekey --injectaccounts=false --firebaseauth ./firebaseauthkey
|
||||
|
||||
```
|
||||
|
||||
If you run that page in gist, you should see sth like this:
|
||||
At this point, if you run `npm test`, you should see something like this:
|
||||
![image](https://cloud.githubusercontent.com/assets/188194/25640962/6a09b66e-2f9a-11e7-9a33-e86f2b9a11d1.png)
|
||||
|
||||
Here is full source-code of the test (the most up to date version of test is available as [status-go/static/tests/whisper.js](https://github.com/status-im/status-go/blob/develop/static/tests/whisper.js))
|
||||
|
||||
```js
|
||||
context('push notifications', function () {
|
||||
this.timeout(5000);
|
||||
var discoveryPubKey = '0x040edb0d71a3dbe928e154fcb696ffbda359b153a90efc2b46f0043ce9f5dbe55b77b9328fd841a1db5273758624afadd5b39638d4c35b36b3a96e1a586c1b4c2a';
|
||||
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
|
||||
var checkClientSessionTopic = '0x8745d931'; // CHECK_CLIENT_SESSION
|
||||
var confirmClientSessionTopic = '0xd3202c5f'; // CONFIRM_CLIENT_SESSION
|
||||
var dropClientSessionTopic = '0x3a6656bb'; // DROP_CLIENT_SESSION
|
||||
|
||||
// ensures that message had payload (which is HEX-encoded JSON)
|
||||
var extractPayload = function (message) {
|
||||
expect(message).to.have.property('payload');
|
||||
return JSON.parse(web3.toAscii(message.payload));
|
||||
};
|
||||
|
||||
var identity1 = ''; // pub key of device 1
|
||||
var identity2 = ''; // pub key of device 2
|
||||
var chatKeySharingTopic = makeTopic(); // topic used by device1 to send chat key to device 2
|
||||
|
||||
context('prepare devices', function () {
|
||||
it('create key pair to be used as main identity on device1', function () {
|
||||
var keyId = node1.shh.newKeyPair();
|
||||
assert.lengthOf(keyId, 64);
|
||||
|
||||
identity1 = node1.shh.getPublicKey(keyId);
|
||||
assert.lengthOf(identity1, 132);
|
||||
|
||||
expect(node1.shh.hasKeyPair(identity1)).to.equal(true);
|
||||
expect(node1.shh.hasKeyPair(identity2)).to.equal(false);
|
||||
});
|
||||
|
||||
it('create key pair to be used as main identity on device2', function () {
|
||||
var keyId = node2.shh.newKeyPair();
|
||||
assert.lengthOf(keyId, 64);
|
||||
|
||||
identity2 = node2.shh.getPublicKey(keyId);
|
||||
assert.lengthOf(identity1, 132);
|
||||
|
||||
expect(node2.shh.hasKeyPair(identity1)).to.equal(false);
|
||||
expect(node2.shh.hasKeyPair(identity2)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
context('run device1', function () {
|
||||
var serverId = ''; // accepted/selected server id
|
||||
var subscriptionKeyId = ''; // symkey provided by server, and used to configure client-server subscription
|
||||
var chatKeyId = ''; // symkey provided by server, and shared among clients so that they can trigger notifications
|
||||
var appChatId = ''; // chat id that identifies device1-device2 interaction session on RN app level
|
||||
|
||||
|
||||
it('start discovery by sending discovery request', function () {
|
||||
var message = {
|
||||
type: "asym",
|
||||
sig: identity1,
|
||||
key: discoveryPubKey,
|
||||
topic: discoverServerTopic,
|
||||
ttl: 20
|
||||
};
|
||||
expect(node1.shh.post(message)).to.equal(null);
|
||||
});
|
||||
|
||||
it('watch for server proposals', function (done) {
|
||||
watchFilter(node1.shh.filter({
|
||||
type: "asym",
|
||||
sig: discoveryPubKey,
|
||||
key: identity1,
|
||||
topics: [proposeServerTopic]
|
||||
}), function (err, message) {
|
||||
if (err) return done(err);
|
||||
|
||||
// process payload
|
||||
var payload = extractPayload(message);
|
||||
expect(payload).to.have.property('server');
|
||||
serverId = payload.server;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('client accepts server', function () {
|
||||
var message = {
|
||||
type: "asym",
|
||||
sig: identity1,
|
||||
key: discoveryPubKey,
|
||||
topic: acceptServerTopic,
|
||||
payload: '{"server": "' + serverId + '"}',
|
||||
ttl: 20
|
||||
};
|
||||
expect(node1.shh.post(message)).to.equal(null);
|
||||
});
|
||||
|
||||
it('watch for server ACK response and save provided subscription key', function (done) {
|
||||
watchFilter(node1.shh.filter({
|
||||
type: "asym",
|
||||
key: identity1,
|
||||
topics: [ackClientSubscriptionTopic]
|
||||
}), function (err, message) {
|
||||
if (err) return done(err);
|
||||
|
||||
// process payload
|
||||
var payload = extractPayload(message);
|
||||
expect(payload).to.have.property('server');
|
||||
expect(payload).to.have.property('key');
|
||||
|
||||
// save subscription key
|
||||
subscriptionKeyId = node1.shh.addSymmetricKeyDirect(payload.key);
|
||||
assert.lengthOf(subscriptionKeyId, 64);
|
||||
expect(node1.shh.hasSymmetricKey(subscriptionKeyId)).to.equal(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('create chat session', function () {
|
||||
appChatId = makeTopic(); // globally unique chat id
|
||||
var message = {
|
||||
type: "sym",
|
||||
sig: identity1,
|
||||
key: subscriptionKeyId,
|
||||
topic: newChatSessionTopic,
|
||||
payload: '{"chat": "' + appChatId + '"}',
|
||||
ttl: 20
|
||||
};
|
||||
expect(node1.shh.post(message)).to.equal(null);
|
||||
});
|
||||
|
||||
it('watch for server to respond with chat key', function (done) {
|
||||
watchFilter(node1.shh.filter({
|
||||
type: "asym",
|
||||
key: identity1,
|
||||
topics: [ackNewChatSessionTopic]
|
||||
}), function (err, message) {
|
||||
if (err) return done(err);
|
||||
|
||||
// process payload
|
||||
var payload = extractPayload(message);
|
||||
expect(payload).to.have.property('server');
|
||||
expect(payload).to.have.property('key');
|
||||
|
||||
// save subscription key
|
||||
chatKeyId = node1.shh.addSymmetricKeyDirect(payload.key);
|
||||
assert.lengthOf(chatKeyId, 64);
|
||||
expect(node1.shh.hasSymmetricKey(chatKeyId)).to.equal(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('register device with a given chat', function (done) {
|
||||
// this obtained from https://status-sandbox-c1b34.firebaseapp.com/
|
||||
var deviceId = 'ca5pRJc6L8s:APA91bHpYFtpxvXx6uOayGmnNVnktA4PEEZdquCCt3fWR5ldLzSy1A37Tsbzk5Gavlmk1d_fvHRVnK7xPAhFFl-erF7O87DnIEstW6DEyhyiKZYA4dXFh6uy323f9A3uw5hEtT_kQVhT';
|
||||
var message = {
|
||||
type: "sym",
|
||||
sig: identity1,
|
||||
key: chatKeyId,
|
||||
topic: newDeviceRegistrationTopic,
|
||||
payload: '{"device": "' + deviceId + '"}',
|
||||
ttl: 20
|
||||
};
|
||||
expect(node1.shh.post(message)).to.equal(null);
|
||||
|
||||
// watch for server server ACK
|
||||
watchFilter(node1.shh.filter({
|
||||
type: "asym",
|
||||
key: identity1,
|
||||
topics: [ackDeviceRegistrationTopic]
|
||||
}), function (err, message) {
|
||||
if (err) return done(err);
|
||||
|
||||
// process payload
|
||||
var payload = extractPayload(message);
|
||||
expect(payload).to.have.property('server');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('share chat key, so that another device can send us notifications', function () {
|
||||
var chatKey = node1.shh.getSymmetricKey(chatKeyId);
|
||||
assert.lengthOf(chatKey, 66);
|
||||
var message = {
|
||||
type: "asym",
|
||||
sig: identity1,
|
||||
key: identity2,
|
||||
topic: chatKeySharingTopic,
|
||||
payload: '{"chat": "' + appChatId + '", "key": "' + chatKey + '"}',
|
||||
ttl: 20
|
||||
};
|
||||
expect(node1.shh.post(message)).to.equal(null);
|
||||
});
|
||||
});
|
||||
|
||||
context('run device2', function () {
|
||||
var chatKeyId = '';
|
||||
|
||||
it('watch for device1 to send us chat key', function (done) {
|
||||
watchFilter(node2.shh.filter({
|
||||
type: "asym",
|
||||
key: identity2,
|
||||
topics: [chatKeySharingTopic]
|
||||
}), function (err, message) {
|
||||
if (err) return done(err);
|
||||
|
||||
// process payload
|
||||
var payload = extractPayload(message);
|
||||
expect(payload).to.have.property('chat');
|
||||
expect(payload).to.have.property('key');
|
||||
|
||||
// persist chat key
|
||||
chatKeyId = node2.shh.addSymmetricKeyDirect(payload.key);
|
||||
assert.lengthOf(chatKeyId, 64);
|
||||
expect(node2.shh.hasSymmetricKey(chatKeyId)).to.equal(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('trigger notification (from device2, on device1)', function () {
|
||||
var message = {
|
||||
type: "sym",
|
||||
sig: identity2,
|
||||
key: chatKeyId,
|
||||
topic: sendNotificationTopic,
|
||||
payload: '{' // see https://firebase.google.com/docs/cloud-messaging/http-server-ref
|
||||
+ '"notification": {'
|
||||
+ '"title": "status.im notification",'
|
||||
+ '"body": "Hello this is test notification!",'
|
||||
+ '"icon": "https://status.im/img/logo.png",'
|
||||
+ '"click_action": "https://status.im"'
|
||||
+ '},'
|
||||
+ '"to": "{{ ID }}"' // this get replaced by device id your've registered
|
||||
+ '}',
|
||||
ttl: 20
|
||||
};
|
||||
expect(node2.shh.post(message)).to.equal(null);
|
||||
});
|
||||
});
|
||||
|
||||
context('misc methods and cleanup', function () {
|
||||
|
||||
it('check client session', function (done) {
|
||||
// request status
|
||||
var message = {
|
||||
type: "asym",
|
||||
sig: identity1,
|
||||
key: discoveryPubKey,
|
||||
topic: checkClientSessionTopic,
|
||||
ttl: 20
|
||||
};
|
||||
expect(node1.shh.post(message)).to.equal(null);
|
||||
|
||||
// process server's response
|
||||
watchFilter(node1.shh.filter({
|
||||
type: "asym",
|
||||
key: identity1,
|
||||
topics: [confirmClientSessionTopic]
|
||||
}), function (err, message) {
|
||||
if (err) return done(err);
|
||||
|
||||
// process payload
|
||||
var payload = extractPayload(message);
|
||||
expect(payload).to.have.property('server');
|
||||
expect(payload).to.have.property('key');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('remove client session', function () {
|
||||
var message = {
|
||||
type: "asym",
|
||||
sig: identity1,
|
||||
key: discoveryPubKey,
|
||||
topic: dropClientSessionTopic,
|
||||
ttl: 20
|
||||
};
|
||||
expect(node1.shh.post(message)).to.equal(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Provided you've updated deviceId (to point to your device), once you run the test, you should get sth like this:
|
||||
|
||||
![image](https://cloud.githubusercontent.com/assets/188194/24966636/34a226ea-1fb0-11e7-9b18-b3595ed108e6.png)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user