diff --git a/CHANGELOG.md b/CHANGELOG.md index 85e023f63c..5d30c16828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Breaking**: `WakuMessage` constructor is now private, `from*` and `decode*` function should be used. - `WakuMessage` version 1 is partially supported, enabling asymmetrical encryption and signature of messages; this can be done by passing keys to `WakuMessage.from*` and `WakuMessage.decode*` methods. -- Examples (eth-dm): Use Waku Message version 1 encryption scheme instead of `eth-crypto`. +- Examples (eth-dm): Use Waku Message version 1 encryption scheme instead of `eth-crypto`. +- Examples (eth-dm): Use Protobuf for direct messages instead of JSON ([#214](https://github.com/status-im/js-waku/issues/214)). ### Fixed - Disable `keepAlive` if set to `0`. diff --git a/examples/eth-dm/src/messaging/SendMessage.tsx b/examples/eth-dm/src/messaging/SendMessage.tsx index 037a96d147..e09931f815 100644 --- a/examples/eth-dm/src/messaging/SendMessage.tsx +++ b/examples/eth-dm/src/messaging/SendMessage.tsx @@ -8,7 +8,8 @@ import { } from '@material-ui/core'; import React, { ChangeEvent, useState, KeyboardEvent } from 'react'; import { Waku, WakuMessage } from 'js-waku'; -import { DirectMessage, encode } from './wire'; +import { hexToBuf } from 'js-waku/lib/utils'; +import { DirectMessage } from './wire'; import { DirectMessageContentTopic } from '../waku'; const useStyles = makeStyles((theme) => ({ @@ -108,12 +109,12 @@ async function encodeEncryptedWakuMessage( publicKey: string, address: string ): Promise { - const directMsg: DirectMessage = { - toAddress: address, + const directMsg = new DirectMessage({ + toAddress: hexToBuf(address), message: message, - }; + }); - const payload = encode(directMsg); + const payload = directMsg.encode(); return WakuMessage.fromBytes(payload, { contentTopic: DirectMessageContentTopic, encPublicKey: publicKey, diff --git a/examples/eth-dm/src/messaging/wire.ts b/examples/eth-dm/src/messaging/wire.ts index df980eb24b..f9795288fb 100644 --- a/examples/eth-dm/src/messaging/wire.ts +++ b/examples/eth-dm/src/messaging/wire.ts @@ -55,21 +55,43 @@ export class PublicKeyMessage { } } -/** - * Direct Encrypted Message used for private communication over the Waku network. - */ -export interface DirectMessage { - toAddress: string; +export interface DirectMessagePayload { + toAddress: Uint8Array; message: string; } -export function encode(msg: T): Buffer { - const jsonStr = JSON.stringify(msg); - return Buffer.from(jsonStr, 'utf-8'); -} +/** + * Direct Encrypted Message used for private communication over the Waku network. + */ +export class DirectMessage { + private static Type = new Type('DirectMessage') + .add(new Field('toAddress', 1, 'bytes')) + .add(new Field('message', 2, 'string')); + private static Root = new Root().define('messages').add(DirectMessage.Type); -export function decode(bytes: Uint8Array): T { - const buf = Buffer.from(bytes); - const str = buf.toString('utf-8'); - return JSON.parse(str); + constructor(public payload: DirectMessagePayload) {} + + public encode(): Uint8Array { + const message = DirectMessage.Type.create(this.payload); + return DirectMessage.Type.encode(message).finish(); + } + + public static decode(bytes: Uint8Array | Buffer): DirectMessage | undefined { + const payload = DirectMessage.Type.decode( + bytes + ) as unknown as DirectMessagePayload; + if (!payload.toAddress || !payload.message) { + console.log('Field missing on decoded Direct Message', payload); + return; + } + return new DirectMessage(payload); + } + + get toAddress(): Uint8Array { + return this.payload.toAddress; + } + + get message(): string { + return this.payload.message; + } } diff --git a/examples/eth-dm/src/waku.ts b/examples/eth-dm/src/waku.ts index 5dcbd19140..99a2877fe0 100644 --- a/examples/eth-dm/src/waku.ts +++ b/examples/eth-dm/src/waku.ts @@ -1,12 +1,12 @@ import { Dispatch, SetStateAction } from 'react'; import { getStatusFleetNodes, Waku, WakuMessage } from 'js-waku'; -import { decode, DirectMessage, PublicKeyMessage } from './messaging/wire'; +import { DirectMessage, PublicKeyMessage } from './messaging/wire'; import { validatePublicKeyMessage } from './crypto'; import { Message } from './messaging/Messages'; import { bufToHex, equalByteArrays } from 'js-waku/lib/utils'; export const PublicKeyContentTopic = '/eth-dm/1/public-key/proto'; -export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json'; +export const DirectMessageContentTopic = '/eth-dm/1/direct-message/proto'; export async function initWaku(): Promise { const waku = await Waku.create({}); @@ -64,8 +64,11 @@ export async function handleDirectMessage( ) { console.log('Direct Message received:', wakuMsg); if (!wakuMsg.payload) return; - const directMessage: DirectMessage = decode(wakuMsg.payload); - + const directMessage = DirectMessage.decode(wakuMsg.payload); + if (!directMessage) { + console.log('Failed to decode Direct Message'); + return; + } if (!equalByteArrays(directMessage.toAddress, address)) return; const timestamp = wakuMsg.timestamp ? wakuMsg.timestamp : new Date(); diff --git a/src/lib/waku_message/version_1.ts b/src/lib/waku_message/version_1.ts index 18b685eea8..82ddc249b6 100644 --- a/src/lib/waku_message/version_1.ts +++ b/src/lib/waku_message/version_1.ts @@ -28,7 +28,7 @@ export function clearEncode( ): { payload: Uint8Array; sig?: Signature } { let envelope = Buffer.from([0]); // No flags envelope = addPayloadSizeField(envelope, messagePayload); - envelope = Buffer.concat([envelope, messagePayload]); + envelope = Buffer.concat([envelope, Buffer.from(messagePayload)]); // Calculate padding: let rawSize =