Merge pull request #218 from status-im/remove-json

This commit is contained in:
Franck Royer 2021-07-02 13:12:42 +10:00 committed by GitHub
commit 6bc79ad587
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 318 additions and 36 deletions

View File

@ -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

View File

@ -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",

View File

@ -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",

View File

@ -83,6 +83,11 @@ function App() {
.then((address) => setAddress(address));
});
let peers;
if (waku) {
peers = waku.libp2p.connectionManager.connections.size;
}
return (
<ThemeProvider theme={theme}>
<div className={classes.root}>
@ -99,6 +104,7 @@ function App() {
style={waku ? { color: green[500] } : {}}
/>
</IconButton>
<Typography>{peers}</Typography>
</Toolbar>
</AppBar>

View File

@ -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);
}

View File

@ -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 {
@ -114,16 +119,22 @@ function handlePublicKeyMessage(
setter: Dispatch<SetStateAction<Map<string, string>>>,
msg: WakuMessage
) {
console.log('Public Key Message received:', msg);
if (!msg.payload) return;
const publicKeyMsg: PublicKeyMessage = decode(msg.payload);
if (publicKeyMsg.ethDmPublicKey === myPublicKey) return;
const res = validatePublicKeyMessage(publicKeyMsg);
console.log(`Public Key Message Received, valid: ${res}`, publicKeyMsg);
const publicKeyMsg = PublicKeyMessage.decode(msg.payload);
if (!publicKeyMsg) return;
const ethDmPublicKey = bytesToHexStr(publicKeyMsg.ethDmPublicKey);
if (ethDmPublicKey === myPublicKey) return;
setter((prevPks: Map<string, string>) => {
prevPks.set(publicKeyMsg.ethAddress, publicKeyMsg.ethDmPublicKey);
return new Map(prevPks);
});
const res = validatePublicKeyMessage(publicKeyMsg);
console.log('Is Public Key Message valid?', res);
if (res) {
setter((prevPks: Map<string, string>) => {
prevPks.set(bytesToHexStr(publicKeyMsg.ethAddress), ethDmPublicKey);
return new Map(prevPks);
});
}
}
async function handleDirectMessage(
@ -132,10 +143,11 @@ 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;
// Do not return our own messages
if (directMessage.toAddress === address) return;
const text = await decryptMessage(privateKey, directMessage);

View File

@ -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,23 +33,46 @@ export async function createPublicKeyMessage(
ethDmPublicKey: string
): Promise<PublicKeyMessage> {
const ethAddress = await web3Signer.getAddress();
const sig = await web3Signer.signMessage(
formatPublicKeyForSignature(ethDmPublicKey)
const bytesEthDmPublicKey = Buffer.from(
ethDmPublicKey.replace(/0x/, ''),
'hex'
);
return { ethDmPublicKey, ethAddress, sig };
const signature = await web3Signer.signMessage(
formatPublicKeyForSignature(bytesEthDmPublicKey)
);
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,
});
}
/**
* Validate that the EthDm Public Key was signed by the holder of the given Ethereum address.
*/
export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
const formattedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey);
try {
const sigAddress = ethers.utils.verifyMessage(
formatPublicKeyForSignature(msg.ethDmPublicKey),
msg.sig
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));
console.log(
`Buffer comparison result: ${cmp} for (signature address, message address)`,
sigAddressBytes,
msg.ethAddress
);
return sigAddress === msg.ethAddress;
return cmp === 0;
} catch (e) {
console.log(
'Failed to verify signature for Public Key Message',
formattedMsg,
msg
);
return false;
}
}
@ -57,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),
});
}

View File

@ -1,12 +1,64 @@
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('ethDmPublicKey', 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 | 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);
}
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');
}
/**

View File

@ -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);
}
);
}
}
/**