diff --git a/CHANGELOG.md b/CHANGELOG.md index ed2f4974ac..9f352b81d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. - 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 `Waku` instance to avoid having to pass them to both `WakuRelay` and `WakuStore`. ### 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. diff --git a/src/lib/waku.spec.ts b/src/lib/waku.spec.ts index 797700bf3d..528d7649df 100644 --- a/src/lib/waku.spec.ts +++ b/src/lib/waku.spec.ts @@ -12,6 +12,10 @@ import { } from '../test_utils/'; 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 () { 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 = 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()); + }); +}); diff --git a/src/lib/waku.ts b/src/lib/waku.ts index 9d7d3e9cd5..729ef77066 100644 --- a/src/lib/waku.ts +++ b/src/lib/waku.ts @@ -93,6 +93,7 @@ export interface CreateOptions { * {@link CreateOptions.libp2p}. */ bootstrap?: boolean | string[] | (() => string[] | Promise); + decryptionKeys?: Array; } export class Waku { @@ -133,6 +134,8 @@ export class Waku { libp2p.connectionManager.on('peer:disconnect', (connection: Connection) => { this.stopKeepAlive(connection.remotePeer); }); + + options?.decryptionKeys?.forEach(this.addDecryptionKey); } /** @@ -270,6 +273,29 @@ export class Waku { 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. * @throws if libp2p is not listening on localhost