Skip to content

Commit 228cdab

Browse files
authored
Merge pull request #234 from status-im/fix-doc
2 parents 383dd04 + 7a641ec commit 228cdab

File tree

11 files changed

+305
-87
lines changed

11 files changed

+305
-87
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Examples (web-chat): New `/fleet` command to switch connection between Status prod and test fleets.
12+
- Export `generatePrivateKey` and `getPublicKey` directly from the root.
13+
- Usage of the encryption and signature APIs to the readme.
14+
15+
### Changed
16+
- **Breaking**: Renamed `WakuRelay.(add|delete)PrivateDecryptionKey` to `WakuRelay.(add|delete)DecryptionKey` to make it clearer that it accepts both symmetric keys and asymmetric private keys.
17+
18+
### Fix
19+
- Align `WakuMessage` readme example with actual code behaviour.
20+
1021
## [0.8.0] - 2021-07-15
1122

1223
### Added

README.md

Lines changed: 188 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,17 @@ Install `js-waku` package:
1010
npm install js-waku
1111
```
1212

13-
Start a waku node:
13+
### Start a waku node
1414

15-
```javascript
15+
```ts
1616
import { Waku } from 'js-waku';
1717

1818
const waku = await Waku.create();
1919
```
2020

21-
Connect to a new peer:
22-
23-
```javascript
24-
import { multiaddr } from 'multiaddr';
25-
import PeerId from 'peer-id';
21+
### Connect to a new peer
2622

23+
```ts
2724
// Directly dial a new peer
2825
await waku.dial('/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ');
2926

@@ -36,63 +33,226 @@ waku.addPeerToAddressBook(
3633

3734
You can also use `getStatusFleetNodes` to connect to nodes run by Status:
3835

39-
```javascript
36+
```ts
4037
import { getStatusFleetNodes } from 'js-waku';
4138

42-
const nodes = await getStatusFleetNodes();
43-
await Promise.all(
44-
nodes.map((addr) => {
45-
return waku.dial(addr);
46-
})
47-
);
39+
getStatusFleetNodes().then((nodes) => {
40+
nodes.forEach((addr) => {
41+
waku.dial(addr);
42+
});
43+
});
4844
```
4945

46+
### Listen for messages
47+
5048
The `contentTopic` is a metadata `string` that allows categorization of messages on the waku network.
5149
Depending on your use case, you can either create one (or several) new `contentTopic`(s) or look at the [RFCs](https://rfc.vac.dev/) and use an existing `contentTopic`.
5250
See the [Waku v2 Topic Usage Recommendations](https://rfc.vac.dev/spec/23/) for more details.
5351

5452
For example, if you were to use a new `contentTopic` such as `/my-cool-app/1/my-use-case/proto`,
5553
here is how to listen to new messages received via [Waku v2 Relay](https://rfc.vac.dev/spec/11/):
5654

57-
```javascript
55+
```ts
5856
waku.relay.addObserver((msg) => {
5957
console.log("Message received:", msg.payloadAsUtf8)
6058
}, ["/my-cool-app/1/my-use-case/proto"]);
6159
```
6260

6361
The examples chat apps currently use content topic `"/toy-chat/2/huilong/proto"`.
6462

65-
Send a message on the waku relay network:
63+
### Send messages
6664

67-
```javascript
65+
There are two ways to send messages:
66+
67+
#### Waku Relay
68+
69+
[Waku Relay](https://rfc.vac.dev/spec/11/) is the most decentralized option,
70+
peer receiving your messages are unlikely to know whether you are the originator or simply forwarding them.
71+
However, it does not give you any delivery information.
72+
73+
```ts
6874
import { WakuMessage } from 'js-waku';
6975

70-
const msg = WakuMessage.fromUtf8String("Here is a message!", "/my-cool-app/1/my-use-case/proto")
76+
const msg = await WakuMessage.fromUtf8String("Here is a message!", { contentTopic: "/my-cool-app/1/my-use-case/proto" })
7177
await waku.relay.send(msg);
7278
```
7379

74-
The [Waku v2 Store protocol](https://rfc.vac.dev/spec/13/) enables full nodes to store messages received via relay
75-
and clients to retrieve them (e.g. after resuming connectivity).
80+
#### Waku Light Push
81+
82+
[Waku Light Push](https://rfc.vac.dev/spec/19/) gives you confirmation that the light push server node has
83+
received your message.
84+
However, it means that said node knows you are the originator of the message.
85+
It cannot guarantee that the node will forward the message.
86+
87+
```ts
88+
const ack = await waku.lightPush.push(message);
89+
if (!ack?.isSuccess) {
90+
// Message was not sent
91+
}
92+
```
93+
94+
### Retrieve archived messages
95+
96+
The [Waku v2 Store protocol](https://rfc.vac.dev/spec/13/) enables more permanent nodes to store messages received via relay
97+
and ephemeral clients to retrieve them (e.g. mobile phone resuming connectivity).
7698
The protocol implements pagination meaning that it may take several queries to retrieve all messages.
7799

78100
Query a waku store peer to check historical messages:
79101

80-
```javascript
81-
// Process messages once they are all retrieved:
82-
const messages = await waku.store.queryHistory(storePeerId, ["my-cool-app"]);
102+
```ts
103+
// Process messages once they are all retrieved
104+
const messages = await waku.store.queryHistory({ contentTopics: ["/my-cool-app/1/my-use-case/proto"] });
83105
messages.forEach((msg) => {
84106
console.log("Message retrieved:", msg.payloadAsUtf8)
85107
})
86108

87109
// Or, pass a callback function to be executed as pages are received:
88-
waku.store.queryHistory(storePeerId, ["my-cool-app"],
89-
(messages) => {
90-
messages.forEach((msg) => {
91-
console.log("Message retrieved:", msg.payloadAsUtf8)
92-
})
110+
waku.store.queryHistory({
111+
contentTopics: ["/my-cool-app/1/my-use-case/proto"],
112+
callback: (messages) => {
113+
messages.forEach((msg) => {
114+
console.log("Message retrieved:", msg.payloadAsUtf8);
115+
});
116+
}
117+
});
118+
```
119+
120+
## Encryption & Signature
121+
122+
With js-waku, you can:
123+
124+
- Encrypt messages over the wire using public/private key pair (asymmetric encryption),
125+
- Encrypt messages over the wire using a unique key to both encrypt and decrypt (symmetric encryption),
126+
- Sign and verify your waku messages (must use encryption, compatible with both symmetric and asymmetric).
127+
128+
### Cryptographic Libraries
129+
130+
A quick note on the cryptographic libraries used as it is a not a straightforward affair:
131+
- Asymmetric encryption:
132+
Uses [ecies-geth](https://github.com/cyrildever/ecies-geth/)
133+
which in turns uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) Web API (browser),
134+
[secp256k1](https://www.npmjs.com/package/secp256k1) (native binding for node)
135+
or [elliptic](https://www.npmjs.com/package/elliptic) (pure JS if none of the other libraries are available).
136+
- Symmetric encryption:
137+
Uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) Web API (browser)
138+
or [NodeJS' crypto](https://nodejs.org/api/crypto.html) module.
139+
140+
### Create new keys
141+
142+
Asymmetric private keys and symmetric keys are expected to be 32 bytes arrays.
143+
144+
```ts
145+
import { generatePrivateKey, getPublicKey } from 'js-waku';
146+
147+
// Asymmetric
148+
const privateKey = generatePrivateKey();
149+
const publicKey = getPublicKey(privateKey);
150+
151+
// Symmetric
152+
const symKey = generatePrivateKey();
153+
```
154+
155+
### Encrypt Waku Messages
156+
157+
To encrypt your waku messages, simply pass the encryption key when creating it:
158+
159+
```ts
160+
import { WakuMessage } from 'js-waku';
161+
162+
// Asymmetric
163+
const message = await WakuMessage.fromBytes(payload, {
164+
contentTopic: myAppContentTopic,
165+
encPublicKey: publicKey,
166+
});
167+
168+
// Symmetric
169+
const message = await WakuMessage.fromBytes(payload, {
170+
contentTopic: myAppContentTopic,
171+
symKey: symKey,
93172
});
94173
```
95174

175+
### Decrypt Waku Messages
176+
177+
#### Waku Relay
178+
179+
If you expect to receive encrypted messages then simply add private decryption key(s) to `WakuRelay`.
180+
Waku Relay will attempt to decrypt incoming messages with each keys, both for symmetric and asymmetric encryption.
181+
Messages that are successfully decrypted (or received in clear) will be passed to the observers, other messages will be omitted.
182+
183+
```ts
184+
// Asymmetric
185+
waku.relay.addDecryptionKey(privateKey);
186+
187+
// Symmetric
188+
waku.relay.addDecryptionKey(symKey);
189+
190+
// Then add the observer
191+
waku.relay.addObserver(callback, [contentTopic]);
192+
```
193+
194+
Keys can be removed using `WakuMessage.deleteDecryptionKey`.
195+
196+
#### Waku Store
197+
198+
```ts
199+
const messages = await waku.store.queryHistory({
200+
contentTopics: [],
201+
decryptionKeys: [privateKey, symKey],
202+
});
203+
```
204+
205+
Similarly to relay, only decrypted or clear messages will be returned.
206+
207+
### Sign Waku Messages
208+
209+
As per version 1`s [specs](https://rfc.vac.dev/spec/26/), signatures are only included in encrypted messages.
210+
In the case where your app does not need encryption then you could use symmetric encryption with a trivial key, I intend to dig [more on the subject](https://github.com/status-im/js-waku/issues/74#issuecomment-880440186) and come back with recommendation and examples.
211+
212+
Signature keys can be generated the same way asymmetric keys for encryption are:
213+
214+
```ts
215+
import { generatePrivateKey, getPublicKey, WakuMessage } from 'js-waku';
216+
217+
const signPrivateKey = generatePrivateKey();
218+
219+
// Asymmetric Encryption
220+
const message = await WakuMessage.fromBytes(payload, {
221+
contentTopic: myAppContentTopic,
222+
encPublicKey: recipientPublicKey,
223+
sigPrivKey: signPrivateKey
224+
});
225+
226+
// Symmetric Encryption
227+
const message = await WakuMessage.fromBytes(payload, {
228+
contentTopic: myAppContentTopic,
229+
encPublicKey: symKey,
230+
sigPrivKey: signPrivateKey
231+
});
232+
```
233+
234+
### Verify Waku Message signatures
235+
236+
Two fields are available on `WakuMessage` regarding signatures:
237+
238+
- `signaturePublicKey`: If the message is signed, it holds the public key of the signature,
239+
- `signature`: If the message is signed, it holds the actual signature.
240+
241+
Thus, if you expect messages to be signed by Alice,
242+
you can simply compare `WakuMessage.signaturePublicKey` with Alice's public key.
243+
As comparing hex string can lead to issues (is the `0x` prefix present?),
244+
simply use helper function `equalByteArrays`.
245+
246+
```ts
247+
import { equalByteArrays } from 'js-waku/lib/utils';
248+
249+
const sigPubKey = wakuMessage.signaturePublicKey;
250+
251+
const isSignedByAlice = sigPubKey && equalByteArrays(sigPubKey, alicePublicKey);
252+
```
253+
254+
## More documentation
255+
96256
Find more [examples](#examples) below
97257
or checkout the latest `main` branch documentation at [https://status-im.github.io/js-waku/docs/](https://status-im.github.io/js-waku/docs/).
98258

examples/eth-dm/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,13 @@ function App() {
128128
if (!waku) return;
129129
if (!ethDmKeyPair) return;
130130

131-
waku.relay.addDecryptionPrivateKey(ethDmKeyPair.privateKey);
131+
waku.relay.addDecryptionKey(ethDmKeyPair.privateKey);
132132

133133
return function cleanUp() {
134134
if (!waku) return;
135135
if (!ethDmKeyPair) return;
136136

137-
waku.relay.deleteDecryptionPrivateKey(ethDmKeyPair.privateKey);
137+
waku.relay.deleteDecryptionKey(ethDmKeyPair.privateKey);
138138
};
139139
}, [waku, ethDmKeyPair]);
140140

examples/eth-dm/src/crypto.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ import { ethers } from 'ethers';
44
import { Signer } from '@ethersproject/abstract-signer';
55
import { PublicKeyMessage } from './messaging/wire';
66
import { hexToBuf, equalByteArrays, bufToHex } from 'js-waku/lib/utils';
7-
import {
8-
generatePrivateKey,
9-
getPublicKey,
10-
} from 'js-waku/lib/waku_message/version_1';
7+
import { generatePrivateKey, getPublicKey } from 'js-waku';
118

129
export interface KeyPair {
1310
privateKey: Uint8Array;

0 commit comments

Comments
 (0)