Allow passing decryption keys to `Waku` instance

Keys can be set at creation or at run time.
They are passed to `WakuStore` and `WakuRelay` instances.
This commit is contained in:
Franck Royer 2021-09-01 15:02:28 +10:00
parent 911ce5bab7
commit cfb97b6bde
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
3 changed files with 104 additions and 0 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Guides: Encrypt messages using Waku Message Version 1. - Guides: Encrypt messages using Waku Message Version 1.
- Allow passing decryption keys in hex string format. - Allow passing decryption keys in hex string format.
- Allow passing decryption keys to `WakuStore` instance to avoid having to pass them at every `queryHistory` call. - Allow passing decryption keys to `WakuStore` instance to avoid having to pass them at every `queryHistory` call.
- Allow passing decryption keys to `Waku` instance to avoid having to pass them to both `WakuRelay` and `WakuStore`.
### Changed ### Changed
- **Breaking**: Moved `startTime` and `endTime` for history queries to a `timeFilter` property as both or neither must be passed; passing only one parameter is not supported. - **Breaking**: Moved `startTime` and `endTime` for history queries to a `timeFilter` property as both or neither must be passed; passing only one parameter is not supported.

View File

@ -12,6 +12,10 @@ import {
} from '../test_utils/'; } from '../test_utils/';
import { Waku } from './waku'; import { Waku } from './waku';
import { WakuMessage } from './waku_message';
import { generateSymmetricKey } from './waku_message/version_1';
const TestContentTopic = '/test/1/waku/utf8';
describe('Waku Dial', function () { describe('Waku Dial', function () {
let waku: Waku; let waku: Waku;
@ -130,3 +134,76 @@ describe('Waku Dial', function () {
}); });
}); });
}); });
describe('Decryption Keys', () => {
afterEach(function () {
if (this.currentTest?.state === 'failed') {
console.log(`Test failed, log file name is ${makeLogFileName(this)}`);
}
});
let waku1: Waku;
let waku2: Waku;
beforeEach(async function () {
[waku1, waku2] = await Promise.all([
Waku.create({ staticNoiseKey: NOISE_KEY_1 }),
Waku.create({
staticNoiseKey: NOISE_KEY_2,
libp2p: { addresses: { listen: ['/ip4/0.0.0.0/tcp/0/ws'] } },
}),
]);
waku1.addPeerToAddressBook(waku2.libp2p.peerId, waku2.libp2p.multiaddrs);
await Promise.all([
new Promise((resolve) =>
waku1.libp2p.pubsub.once('pubsub:subscription-change', () =>
resolve(null)
)
),
new Promise((resolve) =>
waku2.libp2p.pubsub.once('pubsub:subscription-change', () =>
resolve(null)
)
),
]);
});
afterEach(async function () {
this.timeout(5000);
await waku1.stop();
await waku2.stop();
});
it('Used by Waku Relay', async function () {
this.timeout(10000);
const symKey = generateSymmetricKey();
waku2.addDecryptionKey(symKey);
const messageText = 'Message is encrypted';
const messageTimestamp = new Date('1995-12-17T03:24:00');
const message = await WakuMessage.fromUtf8String(
messageText,
TestContentTopic,
{
timestamp: messageTimestamp,
symKey,
}
);
const receivedMsgPromise: Promise<WakuMessage> = new Promise((resolve) => {
waku2.relay.addObserver(resolve);
});
await waku1.relay.send(message);
const receivedMsg = await receivedMsgPromise;
expect(receivedMsg.contentTopic).to.eq(message.contentTopic);
expect(receivedMsg.version).to.eq(message.version);
expect(receivedMsg.payloadAsUtf8).to.eq(messageText);
expect(receivedMsg.timestamp?.valueOf()).to.eq(messageTimestamp.valueOf());
});
});

View File

@ -93,6 +93,7 @@ export interface CreateOptions {
* {@link CreateOptions.libp2p}. * {@link CreateOptions.libp2p}.
*/ */
bootstrap?: boolean | string[] | (() => string[] | Promise<string[]>); bootstrap?: boolean | string[] | (() => string[] | Promise<string[]>);
decryptionKeys?: Array<Uint8Array | string>;
} }
export class Waku { export class Waku {
@ -133,6 +134,8 @@ export class Waku {
libp2p.connectionManager.on('peer:disconnect', (connection: Connection) => { libp2p.connectionManager.on('peer:disconnect', (connection: Connection) => {
this.stopKeepAlive(connection.remotePeer); this.stopKeepAlive(connection.remotePeer);
}); });
options?.decryptionKeys?.forEach(this.addDecryptionKey);
} }
/** /**
@ -270,6 +273,29 @@ export class Waku {
return this.libp2p.stop(); return this.libp2p.stop();
} }
/**
* Register a decryption key to attempt decryption of messages received via
* [[WakuRelay]] and [[WakuStore]]. This can either be a private key for
* asymmetric encryption or a symmetric key.
*
* Strings must be in hex format.
*/
addDecryptionKey(key: Uint8Array | string): void {
this.relay.addDecryptionKey(key);
this.store.addDecryptionKey(key);
}
/**
* Delete a decryption key that was used to attempt decryption of messages
* received via [[WakuRelay]] or [[WakuStore]].
*
* Strings must be in hex format.
*/
deleteDecryptionKey(key: Uint8Array | string): void {
this.relay.deleteDecryptionKey(key);
this.store.deleteDecryptionKey(key);
}
/** /**
* Return the local multiaddr with peer id on which libp2p is listening. * Return the local multiaddr with peer id on which libp2p is listening.
* @throws if libp2p is not listening on localhost * @throws if libp2p is not listening on localhost