From dc2c09bd41bf6f47a995da5299c72689686e3e6b Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 1 Jul 2021 11:52:07 +1000 Subject: [PATCH 1/9] Change public key message encoding to protobuf --- examples/eth-dm/package-lock.json | 174 +++++++++++++++++++++ examples/eth-dm/package.json | 1 + examples/eth-dm/src/BroadcastPublicKey.tsx | 8 +- examples/eth-dm/src/InitWaku.tsx | 17 +- examples/eth-dm/src/crypto.ts | 25 ++- examples/eth-dm/src/messaging/wire.ts | 54 ++++++- 6 files changed, 261 insertions(+), 18 deletions(-) diff --git a/examples/eth-dm/package-lock.json b/examples/eth-dm/package-lock.json index 18ca7dca48..7e42b0bdf3 100644 --- a/examples/eth-dm/package-lock.json +++ b/examples/eth-dm/package-lock.json @@ -19,6 +19,7 @@ "ethers": "^5.2.0", "fontsource-roboto": "^4.0.0", "js-waku": "../../build/main", + "protobufjs": "^6.11.2", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", @@ -3705,6 +3706,60 @@ "node": ">= 8" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "node_modules/@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -4204,6 +4259,11 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "node_modules/@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -14838,6 +14898,11 @@ "url": "https://tidelift.com/funding/github/npm/loglevel" } }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -17973,6 +18038,31 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -26672,6 +26762,60 @@ } } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -27034,6 +27178,11 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -35215,6 +35364,11 @@ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -37707,6 +37861,26 @@ } } }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", diff --git a/examples/eth-dm/package.json b/examples/eth-dm/package.json index 1c7cb88c86..e28a570b3f 100644 --- a/examples/eth-dm/package.json +++ b/examples/eth-dm/package.json @@ -16,6 +16,7 @@ "ethers": "^5.2.0", "fontsource-roboto": "^4.0.0", "js-waku": "../../build/main", + "protobufjs": "^6.11.2", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", diff --git a/examples/eth-dm/src/BroadcastPublicKey.tsx b/examples/eth-dm/src/BroadcastPublicKey.tsx index f73e4cf9a4..8c4484276b 100644 --- a/examples/eth-dm/src/BroadcastPublicKey.tsx +++ b/examples/eth-dm/src/BroadcastPublicKey.tsx @@ -1,7 +1,7 @@ import { Button } from '@material-ui/core'; import React, { useState } from 'react'; import { createPublicKeyMessage, KeyPair } from './crypto'; -import { encode, PublicKeyMessage } from './messaging/wire'; +import { PublicKeyMessage } from './messaging/wire'; import { WakuMessage, Waku } from 'js-waku'; import { Signer } from '@ethersproject/abstract-signer'; import { PublicKeyContentTopic } from './InitWaku'; @@ -56,7 +56,9 @@ export default function BroadcastPublicKey({ ); } -function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage { - const payload = encode(ethDmMsg); +function encodePublicKeyWakuMessage( + publicKeyMessage: PublicKeyMessage +): WakuMessage { + const payload = publicKeyMessage.encode(); return WakuMessage.fromBytes(payload, PublicKeyContentTopic); } diff --git a/examples/eth-dm/src/InitWaku.tsx b/examples/eth-dm/src/InitWaku.tsx index ad1a56b649..a1c5b07708 100644 --- a/examples/eth-dm/src/InitWaku.tsx +++ b/examples/eth-dm/src/InitWaku.tsx @@ -1,10 +1,15 @@ import { Dispatch, SetStateAction, useEffect } from 'react'; import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku'; -import { decode, DirectMessage, PublicKeyMessage } from './messaging/wire'; +import { + bytesToHexStr, + decode, + DirectMessage, + PublicKeyMessage, +} from './messaging/wire'; import { decryptMessage, KeyPair, validatePublicKeyMessage } from './crypto'; import { Message } from './messaging/Messages'; -export const PublicKeyContentTopic = '/eth-dm/1/public-key/json'; +export const PublicKeyContentTopic = '/eth-dm/1/public-key/proto'; export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json'; interface Props { @@ -115,13 +120,15 @@ function handlePublicKeyMessage( msg: WakuMessage ) { if (!msg.payload) return; - const publicKeyMsg: PublicKeyMessage = decode(msg.payload); - if (publicKeyMsg.ethDmPublicKey === myPublicKey) return; + const publicKeyMsg = PublicKeyMessage.decode(msg.payload); + const ethDmPublicKey = bytesToHexStr(publicKeyMsg.ethDmPublicKey); + if (ethDmPublicKey === myPublicKey) return; + const res = validatePublicKeyMessage(publicKeyMsg); console.log(`Public Key Message Received, valid: ${res}`, publicKeyMsg); setter((prevPks: Map) => { - prevPks.set(publicKeyMsg.ethAddress, publicKeyMsg.ethDmPublicKey); + prevPks.set(bytesToHexStr(publicKeyMsg.ethAddress), ethDmPublicKey); return new Map(prevPks); }); } diff --git a/examples/eth-dm/src/crypto.ts b/examples/eth-dm/src/crypto.ts index b357efcfef..ac9480c908 100644 --- a/examples/eth-dm/src/crypto.ts +++ b/examples/eth-dm/src/crypto.ts @@ -3,7 +3,11 @@ import '@ethersproject/shims'; import * as EthCrypto from 'eth-crypto'; import { ethers } from 'ethers'; import { Signer } from '@ethersproject/abstract-signer'; -import { DirectMessage, PublicKeyMessage } from './messaging/wire'; +import { + bytesToHexStr, + DirectMessage, + PublicKeyMessage, +} from './messaging/wire'; export interface KeyPair { privateKey: string; @@ -29,10 +33,19 @@ export async function createPublicKeyMessage( ethDmPublicKey: string ): Promise { const ethAddress = await web3Signer.getAddress(); - const sig = await web3Signer.signMessage( + const signature = await web3Signer.signMessage( formatPublicKeyForSignature(ethDmPublicKey) ); - return { ethDmPublicKey, ethAddress, sig }; + + const bytesEthDmPublicKey = Buffer.from(ethDmPublicKey, 'hex'); + const bytesEthAddress = Buffer.from(ethAddress.replace(/0x/, ''), 'hex'); + const bytesSignature = Buffer.from(signature.replace(/0x/, ''), 'hex'); + + return new PublicKeyMessage({ + ethDmPublicKey: bytesEthDmPublicKey, + ethAddress: bytesEthAddress, + signature: bytesSignature, + }); } /** @@ -41,10 +54,10 @@ export async function createPublicKeyMessage( export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { try { const sigAddress = ethers.utils.verifyMessage( - formatPublicKeyForSignature(msg.ethDmPublicKey), - msg.sig + formatPublicKeyForSignature(bytesToHexStr(msg.ethDmPublicKey)), + msg.signature ); - return sigAddress === msg.ethAddress; + return sigAddress === bytesToHexStr(msg.ethAddress); } catch (e) { return false; } diff --git a/examples/eth-dm/src/messaging/wire.ts b/examples/eth-dm/src/messaging/wire.ts index e76cbc8a89..803bc04b1c 100644 --- a/examples/eth-dm/src/messaging/wire.ts +++ b/examples/eth-dm/src/messaging/wire.ts @@ -1,12 +1,58 @@ import * as EthCrypto from 'eth-crypto'; +import * as protobuf from 'protobufjs/light'; + +export interface PublicKeyMessagePayload { + ethDmPublicKey: Uint8Array; + ethAddress: Uint8Array; + signature: Uint8Array; +} + +const Root = protobuf.Root, + Type = protobuf.Type, + Field = protobuf.Field; /** * Message used to communicate the Eth-Dm public key linked to a given Ethereum account */ -export interface PublicKeyMessage { - ethDmPublicKey: string; - ethAddress: string; - sig: string; +export class PublicKeyMessage { + private static Type = new Type('PublicKeyMessage') + .add(new Field('PublicKeyMessage', 1, 'bytes')) + .add(new Field('ethAddress', 2, 'bytes')) + .add(new Field('signature', 3, 'bytes')); + private static Root = new Root() + .define('messages') + .add(PublicKeyMessage.Type); + + constructor(public payload: PublicKeyMessagePayload) {} + + public encode(): Uint8Array { + const message = PublicKeyMessage.Type.create(this.payload); + return PublicKeyMessage.Type.encode(message).finish(); + } + + public static decode(bytes: Uint8Array | Buffer): PublicKeyMessage { + const payload = PublicKeyMessage.Type.decode( + bytes + ) as unknown as PublicKeyMessagePayload; + return new PublicKeyMessage(payload); + } + + get ethDmPublicKey(): Uint8Array { + return this.payload.ethDmPublicKey; + } + + get ethAddress(): Uint8Array { + return this.payload.ethAddress; + } + + get signature(): Uint8Array { + return this.payload.signature; + } +} + +export function bytesToHexStr(bytes: Uint8Array): string { + const buf = new Buffer(bytes); + return buf.toString('hex'); } /** From 75297b9987f64fc124825aceba0daab201610523 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 1 Jul 2021 16:48:56 +1000 Subject: [PATCH 2/9] Display # of connections --- examples/eth-dm/src/App.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/eth-dm/src/App.tsx b/examples/eth-dm/src/App.tsx index b375f0cfbc..12590f370e 100644 --- a/examples/eth-dm/src/App.tsx +++ b/examples/eth-dm/src/App.tsx @@ -83,6 +83,11 @@ function App() { .then((address) => setAddress(address)); }); + let peers; + if (waku) { + peers = waku.libp2p.connectionManager.connections.size; + } + return (
@@ -99,6 +104,7 @@ function App() { style={waku ? { color: green[500] } : {}} /> + {peers} From 370a347ff22c030a20301f648e417c3c312ff2b0 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Fri, 2 Jul 2021 10:51:58 +1000 Subject: [PATCH 3/9] Actually disable keep alive if set to 0 --- CHANGELOG.md | 3 +++ src/lib/waku.ts | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60700660f5..e844c4308c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Breaking**: Auto select peer if none provided for store and light push protocols. - Upgrade to `libp2p@0.31.7` and `libp2p-gossipsub@0.10.0` to avoid `TextEncoder` errors in ReactJS tests. +### Fixed +- Disable `keepAlive` if set to `0`. + ## [0.7.0] - 2021-06-15 ### Changed diff --git a/src/lib/waku.ts b/src/lib/waku.ts index 0d3b663e3e..093192217f 100644 --- a/src/lib/waku.ts +++ b/src/lib/waku.ts @@ -76,15 +76,20 @@ export class Waku { this.lightPush = lightPush; this.keepAliveTimers = {}; - const keepAlive = options.keepAlive ? options.keepAlive : 10; + const keepAlive = options.keepAlive !== undefined ? options.keepAlive : 10; - libp2p.connectionManager.on('peer:connect', (connection: Connection) => { - this.startKeepAlive(connection.remotePeer, keepAlive); - }); + if (keepAlive !== 0) { + libp2p.connectionManager.on('peer:connect', (connection: Connection) => { + this.startKeepAlive(connection.remotePeer, keepAlive); + }); - libp2p.connectionManager.on('peer:disconnect', (connection: Connection) => { - this.stopKeepAlive(connection.remotePeer); - }); + libp2p.connectionManager.on( + 'peer:disconnect', + (connection: Connection) => { + this.stopKeepAlive(connection.remotePeer); + } + ); + } } /** From f9174cd3d2161deb80aec39f9a6058ce630539ce Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Fri, 2 Jul 2021 10:52:35 +1000 Subject: [PATCH 4/9] Do not process Public Key Message if field is missing --- examples/eth-dm/src/InitWaku.tsx | 1 + examples/eth-dm/src/messaging/wire.ts | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/eth-dm/src/InitWaku.tsx b/examples/eth-dm/src/InitWaku.tsx index a1c5b07708..3ef45e0c76 100644 --- a/examples/eth-dm/src/InitWaku.tsx +++ b/examples/eth-dm/src/InitWaku.tsx @@ -121,6 +121,7 @@ function handlePublicKeyMessage( ) { if (!msg.payload) return; const publicKeyMsg = PublicKeyMessage.decode(msg.payload); + if (!publicKeyMsg) return; const ethDmPublicKey = bytesToHexStr(publicKeyMsg.ethDmPublicKey); if (ethDmPublicKey === myPublicKey) return; diff --git a/examples/eth-dm/src/messaging/wire.ts b/examples/eth-dm/src/messaging/wire.ts index 803bc04b1c..da5dbe52a2 100644 --- a/examples/eth-dm/src/messaging/wire.ts +++ b/examples/eth-dm/src/messaging/wire.ts @@ -30,10 +30,16 @@ export class PublicKeyMessage { return PublicKeyMessage.Type.encode(message).finish(); } - public static decode(bytes: Uint8Array | Buffer): PublicKeyMessage { + public static decode( + bytes: Uint8Array | Buffer + ): PublicKeyMessage | undefined { const payload = PublicKeyMessage.Type.decode( bytes ) as unknown as PublicKeyMessagePayload; + if (!payload.signature || !payload.ethDmPublicKey || !payload.ethAddress) { + console.log('Field missing on decoded Public Key Message', payload); + return; + } return new PublicKeyMessage(payload); } From 3c618f435ea51415110864fd22f11cc04fbd12dd Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Fri, 2 Jul 2021 10:52:46 +1000 Subject: [PATCH 5/9] Fix typo --- examples/eth-dm/src/messaging/wire.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/eth-dm/src/messaging/wire.ts b/examples/eth-dm/src/messaging/wire.ts index da5dbe52a2..d595ea978c 100644 --- a/examples/eth-dm/src/messaging/wire.ts +++ b/examples/eth-dm/src/messaging/wire.ts @@ -16,7 +16,7 @@ const Root = protobuf.Root, */ export class PublicKeyMessage { private static Type = new Type('PublicKeyMessage') - .add(new Field('PublicKeyMessage', 1, 'bytes')) + .add(new Field('ethDmPublicKey', 1, 'bytes')) .add(new Field('ethAddress', 2, 'bytes')) .add(new Field('signature', 3, 'bytes')); private static Root = new Root() From f020aa7a8ca6ad1c1d72ef109c5b5cdb53353fef Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Fri, 2 Jul 2021 10:54:56 +1000 Subject: [PATCH 6/9] Improve logging upon receiving messages --- examples/eth-dm/src/InitWaku.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/eth-dm/src/InitWaku.tsx b/examples/eth-dm/src/InitWaku.tsx index 3ef45e0c76..e01f12e85d 100644 --- a/examples/eth-dm/src/InitWaku.tsx +++ b/examples/eth-dm/src/InitWaku.tsx @@ -119,6 +119,7 @@ function handlePublicKeyMessage( setter: Dispatch>>, msg: WakuMessage ) { + console.log('Public Key Message received:', msg); if (!msg.payload) return; const publicKeyMsg = PublicKeyMessage.decode(msg.payload); if (!publicKeyMsg) return; @@ -140,7 +141,7 @@ async function handleDirectMessage( address: string, wakuMsg: WakuMessage ) { - console.log('Waku Message received:', wakuMsg); + console.log('Direct Message received:', wakuMsg); if (!wakuMsg.payload) return; const directMessage: DirectMessage = decode(wakuMsg.payload); if (directMessage.toAddress !== address) return; From 2f2f89cf6591d2b7e9abcbe47e420df0a9d3c026 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Fri, 2 Jul 2021 10:56:23 +1000 Subject: [PATCH 7/9] Fix filtering of own messages --- examples/eth-dm/src/InitWaku.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/eth-dm/src/InitWaku.tsx b/examples/eth-dm/src/InitWaku.tsx index e01f12e85d..e19991bb68 100644 --- a/examples/eth-dm/src/InitWaku.tsx +++ b/examples/eth-dm/src/InitWaku.tsx @@ -144,7 +144,8 @@ async function handleDirectMessage( console.log('Direct Message received:', wakuMsg); if (!wakuMsg.payload) return; const directMessage: DirectMessage = decode(wakuMsg.payload); - if (directMessage.toAddress !== address) return; + // Do not return our own messages + if (directMessage.toAddress === address) return; const text = await decryptMessage(privateKey, directMessage); From e9a1d8851276ac2c649098c6f96bc5ee8916d7e4 Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Fri, 2 Jul 2021 11:29:04 +1000 Subject: [PATCH 8/9] Fix Public Key Message validation and use it --- examples/eth-dm/src/InitWaku.tsx | 12 +++++++----- examples/eth-dm/src/crypto.ts | 30 ++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/examples/eth-dm/src/InitWaku.tsx b/examples/eth-dm/src/InitWaku.tsx index e19991bb68..da105ff848 100644 --- a/examples/eth-dm/src/InitWaku.tsx +++ b/examples/eth-dm/src/InitWaku.tsx @@ -127,12 +127,14 @@ function handlePublicKeyMessage( if (ethDmPublicKey === myPublicKey) return; const res = validatePublicKeyMessage(publicKeyMsg); - console.log(`Public Key Message Received, valid: ${res}`, publicKeyMsg); + console.log('Is Public Key Message valid?', res); - setter((prevPks: Map) => { - prevPks.set(bytesToHexStr(publicKeyMsg.ethAddress), ethDmPublicKey); - return new Map(prevPks); - }); + if (res) { + setter((prevPks: Map) => { + prevPks.set(bytesToHexStr(publicKeyMsg.ethAddress), ethDmPublicKey); + return new Map(prevPks); + }); + } } async function handleDirectMessage( diff --git a/examples/eth-dm/src/crypto.ts b/examples/eth-dm/src/crypto.ts index ac9480c908..da76e4cdc8 100644 --- a/examples/eth-dm/src/crypto.ts +++ b/examples/eth-dm/src/crypto.ts @@ -33,11 +33,14 @@ export async function createPublicKeyMessage( ethDmPublicKey: string ): Promise { const ethAddress = await web3Signer.getAddress(); + const bytesEthDmPublicKey = Buffer.from( + ethDmPublicKey.replace(/0x/, ''), + 'hex' + ); const signature = await web3Signer.signMessage( - formatPublicKeyForSignature(ethDmPublicKey) + formatPublicKeyForSignature(bytesEthDmPublicKey) ); - const bytesEthDmPublicKey = Buffer.from(ethDmPublicKey, 'hex'); const bytesEthAddress = Buffer.from(ethAddress.replace(/0x/, ''), 'hex'); const bytesSignature = Buffer.from(signature.replace(/0x/, ''), 'hex'); @@ -52,13 +55,24 @@ export async function createPublicKeyMessage( * Validate that the EthDm Public Key was signed by the holder of the given Ethereum address. */ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { + const formatedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey); try { - const sigAddress = ethers.utils.verifyMessage( - formatPublicKeyForSignature(bytesToHexStr(msg.ethDmPublicKey)), - msg.signature + const sigAddress = ethers.utils.verifyMessage(formatedMsg, msg.signature); + const sigAddressBytes = Buffer.from(sigAddress.replace(/0x/, ''), 'hex'); + // Compare the actual byte arrays instead of strings that may differ in casing or prefixing. + const cmp = sigAddressBytes.compare(new Buffer(msg.ethAddress)); + console.log( + `Buffer comparison result: ${cmp} for (signature address, message address)`, + sigAddressBytes, + msg.ethAddress ); - return sigAddress === bytesToHexStr(msg.ethAddress); + return cmp === 0; } catch (e) { + console.log( + 'Failed to verify signature for Public Key Message', + formatedMsg, + msg + ); return false; } } @@ -70,9 +84,9 @@ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { * The usage of the object helps ensure the signature is only used in an Eth-DM * context. */ -function formatPublicKeyForSignature(ethDmPublicKey: string): string { +function formatPublicKeyForSignature(ethDmPublicKey: Uint8Array): string { return JSON.stringify({ - ethDmPublicKey, + ethDmPublicKey: bytesToHexStr(ethDmPublicKey), }); } From e59e9f41622e1f6069ccc57e5aca0555e2a3e60f Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Fri, 2 Jul 2021 11:44:04 +1000 Subject: [PATCH 9/9] Fix typo --- examples/eth-dm/src/crypto.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/eth-dm/src/crypto.ts b/examples/eth-dm/src/crypto.ts index da76e4cdc8..0b72b88f69 100644 --- a/examples/eth-dm/src/crypto.ts +++ b/examples/eth-dm/src/crypto.ts @@ -55,9 +55,9 @@ export async function createPublicKeyMessage( * Validate that the EthDm Public Key was signed by the holder of the given Ethereum address. */ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { - const formatedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey); + const formattedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey); try { - const sigAddress = ethers.utils.verifyMessage(formatedMsg, msg.signature); + const sigAddress = ethers.utils.verifyMessage(formattedMsg, msg.signature); const sigAddressBytes = Buffer.from(sigAddress.replace(/0x/, ''), 'hex'); // Compare the actual byte arrays instead of strings that may differ in casing or prefixing. const cmp = sigAddressBytes.compare(new Buffer(msg.ethAddress)); @@ -70,7 +70,7 @@ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { } catch (e) { console.log( 'Failed to verify signature for Public Key Message', - formatedMsg, + formattedMsg, msg ); return false;