mirror of https://github.com/waku-org/js-waku.git
Merge pull request #220 from status-im/eth-dm-clean-up
This commit is contained in:
commit
db6bb95a9b
|
@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Changed
|
### Changed
|
||||||
- **Breaking**: Auto select peer if none provided for store and light push protocols.
|
- **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.
|
- Upgrade to `libp2p@0.31.7` and `libp2p-gossipsub@0.10.0` to avoid `TextEncoder` errors in ReactJS tests.
|
||||||
|
- Disable keep alive by default as latest nim-waku release does not support ping protocol.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Disable `keepAlive` if set to `0`.
|
- Disable `keepAlive` if set to `0`.
|
||||||
|
|
|
@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import { Waku } from 'js-waku';
|
import { Waku } from 'js-waku';
|
||||||
import { ethers } from 'ethers';
|
import { ethers } from 'ethers';
|
||||||
import { Web3Provider } from '@ethersproject/providers';
|
import { Signer } from '@ethersproject/abstract-signer';
|
||||||
import { KeyPair } from './crypto';
|
import { KeyPair } from './crypto';
|
||||||
import { Message } from './messaging/Messages';
|
import { Message } from './messaging/Messages';
|
||||||
import 'fontsource-roboto';
|
import 'fontsource-roboto';
|
||||||
|
@ -52,12 +52,18 @@ const useStyles = makeStyles({
|
||||||
flex: 1,
|
flex: 1,
|
||||||
margin: '10px',
|
margin: '10px',
|
||||||
},
|
},
|
||||||
wakuStatus: {},
|
wakuStatus: {
|
||||||
|
marginRight: theme.spacing(2),
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
|
peers: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [waku, setWaku] = useState<Waku>();
|
const [waku, setWaku] = useState<Waku>();
|
||||||
const [provider, setProvider] = useState<Web3Provider>();
|
const [signer, setSigner] = useState<Signer>();
|
||||||
const [ethDmKeyPair, setEthDmKeyPair] = useState<KeyPair | undefined>();
|
const [ethDmKeyPair, setEthDmKeyPair] = useState<KeyPair | undefined>();
|
||||||
const [publicKeys, setPublicKeys] = useState<Map<string, string>>(new Map());
|
const [publicKeys, setPublicKeys] = useState<Map<string, string>>(new Map());
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
|
@ -66,36 +72,37 @@ function App() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (provider) return;
|
|
||||||
try {
|
try {
|
||||||
window.ethereum.request({ method: 'eth_requestAccounts' });
|
window.ethereum
|
||||||
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
.request({ method: 'eth_requestAccounts' })
|
||||||
setProvider(_provider);
|
.then((accounts: string[]) => {
|
||||||
|
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||||
|
setAddress(accounts[0]);
|
||||||
|
setSigner(_provider.getSigner());
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('No web3 provider available');
|
console.error('No web3 provider available');
|
||||||
}
|
}
|
||||||
}, [provider]);
|
}, [address, signer]);
|
||||||
|
|
||||||
useEffect(() => {
|
let peers = 0;
|
||||||
provider
|
|
||||||
?.getSigner()
|
|
||||||
.getAddress()
|
|
||||||
.then((address) => setAddress(address));
|
|
||||||
});
|
|
||||||
|
|
||||||
let peers;
|
|
||||||
if (waku) {
|
if (waku) {
|
||||||
peers = waku.libp2p.connectionManager.connections.size;
|
peers = waku.libp2p.connectionManager.connections.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let addressDisplay = '';
|
||||||
|
if (address) {
|
||||||
|
addressDisplay =
|
||||||
|
address.substr(0, 6) + '...' + address.substr(address.length - 4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<AppBar className={classes.appBar} position="static">
|
<AppBar className={classes.appBar} position="static">
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Typography>Ethereum Direct Message</Typography>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
edge="end"
|
edge="start"
|
||||||
className={classes.wakuStatus}
|
className={classes.wakuStatus}
|
||||||
aria-label="waku-status"
|
aria-label="waku-status"
|
||||||
>
|
>
|
||||||
|
@ -104,7 +111,13 @@ function App() {
|
||||||
style={waku ? { color: green[500] } : {}}
|
style={waku ? { color: green[500] } : {}}
|
||||||
/>
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography>{peers}</Typography>
|
<Typography className={classes.peers} aria-label="connected-peers">
|
||||||
|
{peers} peer{peers && peers > 1 ? 's' : ''}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h6" className={classes.title}>
|
||||||
|
Ethereum Direct Message
|
||||||
|
</Typography>
|
||||||
|
<Typography>{addressDisplay}</Typography>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
|
|
||||||
|
@ -125,7 +138,7 @@ function App() {
|
||||||
setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)}
|
setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)}
|
||||||
/>
|
/>
|
||||||
<BroadcastPublicKey
|
<BroadcastPublicKey
|
||||||
signer={provider?.getSigner()}
|
signer={signer}
|
||||||
ethDmKeyPair={ethDmKeyPair}
|
ethDmKeyPair={ethDmKeyPair}
|
||||||
waku={waku}
|
waku={waku}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
import { Dispatch, SetStateAction, useEffect } from 'react';
|
import { Dispatch, SetStateAction, useEffect } from 'react';
|
||||||
import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
||||||
import {
|
import { decode, DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||||
bytesToHexStr,
|
|
||||||
decode,
|
|
||||||
DirectMessage,
|
|
||||||
PublicKeyMessage,
|
|
||||||
} from './messaging/wire';
|
|
||||||
import { decryptMessage, KeyPair, validatePublicKeyMessage } from './crypto';
|
import { decryptMessage, KeyPair, validatePublicKeyMessage } from './crypto';
|
||||||
import { Message } from './messaging/Messages';
|
import { Message } from './messaging/Messages';
|
||||||
|
import { byteArrayToHex } from './utils';
|
||||||
|
|
||||||
export const PublicKeyContentTopic = '/eth-dm/1/public-key/proto';
|
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/json';
|
||||||
|
@ -106,12 +102,7 @@ async function initWaku(): Promise<Waku> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodes() {
|
function getNodes() {
|
||||||
// Works with react-scripts
|
return getStatusFleetNodes(Environment.Prod);
|
||||||
if (process?.env?.NODE_ENV === 'development') {
|
|
||||||
return getStatusFleetNodes(Environment.Test);
|
|
||||||
} else {
|
|
||||||
return getStatusFleetNodes(Environment.Prod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePublicKeyMessage(
|
function handlePublicKeyMessage(
|
||||||
|
@ -123,7 +114,7 @@ function handlePublicKeyMessage(
|
||||||
if (!msg.payload) return;
|
if (!msg.payload) return;
|
||||||
const publicKeyMsg = PublicKeyMessage.decode(msg.payload);
|
const publicKeyMsg = PublicKeyMessage.decode(msg.payload);
|
||||||
if (!publicKeyMsg) return;
|
if (!publicKeyMsg) return;
|
||||||
const ethDmPublicKey = bytesToHexStr(publicKeyMsg.ethDmPublicKey);
|
const ethDmPublicKey = byteArrayToHex(publicKeyMsg.ethDmPublicKey);
|
||||||
if (ethDmPublicKey === myPublicKey) return;
|
if (ethDmPublicKey === myPublicKey) return;
|
||||||
|
|
||||||
const res = validatePublicKeyMessage(publicKeyMsg);
|
const res = validatePublicKeyMessage(publicKeyMsg);
|
||||||
|
@ -131,7 +122,7 @@ function handlePublicKeyMessage(
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
setter((prevPks: Map<string, string>) => {
|
setter((prevPks: Map<string, string>) => {
|
||||||
prevPks.set(bytesToHexStr(publicKeyMsg.ethAddress), ethDmPublicKey);
|
prevPks.set(byteArrayToHex(publicKeyMsg.ethAddress), ethDmPublicKey);
|
||||||
return new Map(prevPks);
|
return new Map(prevPks);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,8 @@ import '@ethersproject/shims';
|
||||||
import * as EthCrypto from 'eth-crypto';
|
import * as EthCrypto from 'eth-crypto';
|
||||||
import { ethers } from 'ethers';
|
import { ethers } from 'ethers';
|
||||||
import { Signer } from '@ethersproject/abstract-signer';
|
import { Signer } from '@ethersproject/abstract-signer';
|
||||||
import {
|
import { DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||||
bytesToHexStr,
|
import { byteArrayToHex, hexToBuf } from './utils';
|
||||||
DirectMessage,
|
|
||||||
PublicKeyMessage,
|
|
||||||
} from './messaging/wire';
|
|
||||||
|
|
||||||
export interface KeyPair {
|
export interface KeyPair {
|
||||||
privateKey: string;
|
privateKey: string;
|
||||||
|
@ -33,21 +30,15 @@ export async function createPublicKeyMessage(
|
||||||
ethDmPublicKey: string
|
ethDmPublicKey: string
|
||||||
): Promise<PublicKeyMessage> {
|
): Promise<PublicKeyMessage> {
|
||||||
const ethAddress = await web3Signer.getAddress();
|
const ethAddress = await web3Signer.getAddress();
|
||||||
const bytesEthDmPublicKey = Buffer.from(
|
const bytesEthDmPublicKey = hexToBuf(ethDmPublicKey);
|
||||||
ethDmPublicKey.replace(/0x/, ''),
|
|
||||||
'hex'
|
|
||||||
);
|
|
||||||
const signature = await web3Signer.signMessage(
|
const signature = await web3Signer.signMessage(
|
||||||
formatPublicKeyForSignature(bytesEthDmPublicKey)
|
formatPublicKeyForSignature(bytesEthDmPublicKey)
|
||||||
);
|
);
|
||||||
|
|
||||||
const bytesEthAddress = Buffer.from(ethAddress.replace(/0x/, ''), 'hex');
|
|
||||||
const bytesSignature = Buffer.from(signature.replace(/0x/, ''), 'hex');
|
|
||||||
|
|
||||||
return new PublicKeyMessage({
|
return new PublicKeyMessage({
|
||||||
ethDmPublicKey: bytesEthDmPublicKey,
|
ethDmPublicKey: bytesEthDmPublicKey,
|
||||||
ethAddress: bytesEthAddress,
|
ethAddress: hexToBuf(ethAddress),
|
||||||
signature: bytesSignature,
|
signature: hexToBuf(signature),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +49,7 @@ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
||||||
const formattedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey);
|
const formattedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey);
|
||||||
try {
|
try {
|
||||||
const sigAddress = ethers.utils.verifyMessage(formattedMsg, msg.signature);
|
const sigAddress = ethers.utils.verifyMessage(formattedMsg, msg.signature);
|
||||||
const sigAddressBytes = Buffer.from(sigAddress.replace(/0x/, ''), 'hex');
|
const sigAddressBytes = hexToBuf(sigAddress);
|
||||||
// Compare the actual byte arrays instead of strings that may differ in casing or prefixing.
|
// Compare the actual byte arrays instead of strings that may differ in casing or prefixing.
|
||||||
const cmp = sigAddressBytes.compare(new Buffer(msg.ethAddress));
|
const cmp = sigAddressBytes.compare(new Buffer(msg.ethAddress));
|
||||||
console.log(
|
console.log(
|
||||||
|
@ -86,7 +77,7 @@ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
||||||
*/
|
*/
|
||||||
function formatPublicKeyForSignature(ethDmPublicKey: Uint8Array): string {
|
function formatPublicKeyForSignature(ethDmPublicKey: Uint8Array): string {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
ethDmPublicKey: bytesToHexStr(ethDmPublicKey),
|
ethDmPublicKey: byteArrayToHex(ethDmPublicKey),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,11 +56,6 @@ export class PublicKeyMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bytesToHexStr(bytes: Uint8Array): string {
|
|
||||||
const buf = new Buffer(bytes);
|
|
||||||
return buf.toString('hex');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Direct Encrypted Message used for private communication over the Waku network.
|
* Direct Encrypted Message used for private communication over the Waku network.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
export function byteArrayToHex(bytes: Uint8Array): string {
|
||||||
|
const buf = new Buffer(bytes);
|
||||||
|
return buf.toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hexToBuf(str: string): Buffer {
|
||||||
|
return Buffer.from(str.replace(/0x/, ''), 'hex');
|
||||||
|
}
|
|
@ -76,7 +76,7 @@ export class Waku {
|
||||||
this.lightPush = lightPush;
|
this.lightPush = lightPush;
|
||||||
this.keepAliveTimers = {};
|
this.keepAliveTimers = {};
|
||||||
|
|
||||||
const keepAlive = options.keepAlive !== undefined ? options.keepAlive : 10;
|
const keepAlive = options.keepAlive !== undefined ? options.keepAlive : 0;
|
||||||
|
|
||||||
if (keepAlive !== 0) {
|
if (keepAlive !== 0) {
|
||||||
libp2p.connectionManager.on('peer:connect', (connection: Connection) => {
|
libp2p.connectionManager.on('peer:connect', (connection: Connection) => {
|
||||||
|
|
|
@ -114,7 +114,7 @@ export class WakuRelay extends Gossipsub {
|
||||||
*/
|
*/
|
||||||
public async send(message: WakuMessage): Promise<void> {
|
public async send(message: WakuMessage): Promise<void> {
|
||||||
const msg = message.encode();
|
const msg = message.encode();
|
||||||
await super.publish(this.pubsubTopic, Buffer.from(msg));
|
await super.publish(this.pubsubTopic, new Buffer(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue