Extract waku initialisation in separate component

This commit is contained in:
Franck Royer 2021-06-29 12:30:57 +10:00
parent 5de030d3ca
commit 6921242877
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
5 changed files with 158 additions and 128 deletions

View File

@ -1,22 +1,18 @@
import '@ethersproject/shims'; import '@ethersproject/shims';
import React, { Dispatch, SetStateAction, useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import './App.css'; import './App.css';
import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku'; import { Waku, WakuMessage } from 'js-waku';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { Web3Provider } from '@ethersproject/providers'; import { Web3Provider } from '@ethersproject/providers';
import { import { createPublicKeyMessage, KeyPair } from './crypto';
createPublicKeyMessage, import { encode, PublicKeyMessage } from './messages';
decryptMessage, import Messages, { Message } from './Messages';
KeyPair,
validatePublicKeyMessage,
} from './crypto';
import { decode, DirectMessage, encode, PublicKeyMessage } from './messages';
import { Message, Messages } from './Messages';
import 'fontsource-roboto'; import 'fontsource-roboto';
import { Button } from '@material-ui/core'; import { Button } from '@material-ui/core';
import { SendMessage } from './SendMessage'; import SendMessage from './SendMessage';
import { KeyPairHandling } from './key_pair_handling/KeyPairHandling'; import KeyPairHandling from './key_pair_handling/KeyPairHandling';
import InitWaku from './InitWaku';
export const PublicKeyContentTopic = '/eth-dm/1/public-key/json'; export const PublicKeyContentTopic = '/eth-dm/1/public-key/json';
export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json'; export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json';
@ -42,54 +38,6 @@ function App() {
} }
}, [provider]); }, [provider]);
useEffect(() => {
if (waku) return;
initWaku()
.then((wakuNode) => {
console.log('waku: ready');
setWaku(wakuNode);
})
.catch((e) => {
console.error('Failed to initiate Waku', e);
});
}, [waku]);
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
{},
ethDmKeyPair?.publicKey,
setPublicKeys
);
const observerDirectMessage = ethDmKeyPair
? handleDirectMessage.bind({}, setMessages, ethDmKeyPair.privateKey)
: undefined;
useEffect(() => {
if (!waku) return;
waku.relay.addObserver(observerPublicKeyMessage, [PublicKeyContentTopic]);
return function cleanUp() {
if (!waku) return;
waku.relay.deleteObserver(observerPublicKeyMessage, [
PublicKeyContentTopic,
]);
};
});
useEffect(() => {
if (!waku) return;
if (!observerDirectMessage) return;
waku.relay.addObserver(observerDirectMessage, [DirectMessageContentTopic]);
return function cleanUp() {
if (!waku) return;
if (!observerDirectMessage) return;
waku.relay.deleteObserver(observerDirectMessage, [
DirectMessageContentTopic,
]);
};
});
const broadcastPublicKey = () => { const broadcastPublicKey = () => {
if (!ethDmKeyPair) return; if (!ethDmKeyPair) return;
if (!provider) return; if (!provider) return;
@ -115,12 +63,16 @@ function App() {
} }
}; };
const wakuReady = !!waku ? 'Waku is ready' : 'Waku is loading';
return ( return (
<div className="App"> <div className="App">
<header className="App-header"> <header className="App-header">
{wakuReady} <InitWaku
ethDmKeyPair={ethDmKeyPair}
setMessages={setMessages}
setPublicKeys={setPublicKeys}
setWaku={setWaku}
waku={waku}
/>
<KeyPairHandling <KeyPairHandling
ethDmKeyPair={ethDmKeyPair} ethDmKeyPair={ethDmKeyPair}
setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)} setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)}
@ -144,69 +96,7 @@ function App() {
export default App; export default App;
async function initWaku(): Promise<Waku> {
const waku = await Waku.create({});
const nodes = await getNodes();
await Promise.all(
nodes.map((addr) => {
return waku.dial(addr);
})
);
return waku;
}
function getNodes() {
// Works with react-scripts
if (process?.env?.NODE_ENV === 'development') {
return getStatusFleetNodes(Environment.Test);
} else {
return getStatusFleetNodes(Environment.Prod);
}
}
function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage { function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage {
const payload = encode(ethDmMsg); const payload = encode(ethDmMsg);
return WakuMessage.fromBytes(payload, PublicKeyContentTopic); return WakuMessage.fromBytes(payload, PublicKeyContentTopic);
} }
function handlePublicKeyMessage(
myPublicKey: string | undefined,
setter: Dispatch<SetStateAction<Map<string, string>>>,
msg: WakuMessage
) {
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);
setter((prevPks: Map<string, string>) => {
prevPks.set(publicKeyMsg.ethAddress, publicKeyMsg.ethDmPublicKey);
return new Map(prevPks);
});
}
async function handleDirectMessage(
setter: Dispatch<SetStateAction<Message[]>>,
privateKey: string,
wakuMsg: WakuMessage
) {
console.log('Waku Message received:', wakuMsg);
if (!wakuMsg.payload) return;
const directMessage: DirectMessage = decode(wakuMsg.payload);
const text = await decryptMessage(privateKey, directMessage);
const timestamp = wakuMsg.timestamp ? wakuMsg.timestamp : new Date();
console.log('Message decrypted:', text);
setter((prevMsgs: Message[]) => {
const copy = prevMsgs.slice();
copy.push({
text: text,
timestamp: timestamp,
});
return copy;
});
}

View File

@ -0,0 +1,137 @@
import { Dispatch, SetStateAction, useEffect } from 'react';
import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
import { decode, DirectMessage, PublicKeyMessage } from './messages';
import { decryptMessage, KeyPair, validatePublicKeyMessage } from './crypto';
import { Message } from './Messages';
import { DirectMessageContentTopic, PublicKeyContentTopic } from './App';
interface Props {
waku: Waku | undefined;
setWaku: (waku: Waku) => void;
ethDmKeyPair: KeyPair | undefined;
setPublicKeys: Dispatch<SetStateAction<Map<string, string>>>;
setMessages: Dispatch<SetStateAction<Message[]>>;
}
/**
* Does all the waku initialisation
*/
export default function InitWaku({
waku,
setWaku,
ethDmKeyPair,
setPublicKeys,
setMessages,
}: Props) {
useEffect(() => {
if (waku) return;
initWaku()
.then((wakuNode) => {
console.log('waku: ready');
setWaku(wakuNode);
})
.catch((e) => {
console.error('Failed to initiate Waku', e);
});
}, [waku, setWaku]);
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
{},
ethDmKeyPair?.publicKey,
setPublicKeys
);
const observerDirectMessage = ethDmKeyPair
? handleDirectMessage.bind({}, setMessages, ethDmKeyPair.privateKey)
: undefined;
useEffect(() => {
if (!waku) return;
waku.relay.addObserver(observerPublicKeyMessage, [PublicKeyContentTopic]);
return function cleanUp() {
if (!waku) return;
waku.relay.deleteObserver(observerPublicKeyMessage, [
PublicKeyContentTopic,
]);
};
});
useEffect(() => {
if (!waku) return;
if (!observerDirectMessage) return;
waku.relay.addObserver(observerDirectMessage, [DirectMessageContentTopic]);
return function cleanUp() {
if (!waku) return;
if (!observerDirectMessage) return;
waku.relay.deleteObserver(observerDirectMessage, [
DirectMessageContentTopic,
]);
};
});
return <p>{!!waku ? 'Waku is ready' : 'Waku is loading'}</p>;
}
async function initWaku(): Promise<Waku> {
const waku = await Waku.create({});
const nodes = await getNodes();
await Promise.all(
nodes.map((addr) => {
return waku.dial(addr);
})
);
return waku;
}
function getNodes() {
// Works with react-scripts
if (process?.env?.NODE_ENV === 'development') {
return getStatusFleetNodes(Environment.Test);
} else {
return getStatusFleetNodes(Environment.Prod);
}
}
function handlePublicKeyMessage(
myPublicKey: string | undefined,
setter: Dispatch<SetStateAction<Map<string, string>>>,
msg: WakuMessage
) {
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);
setter((prevPks: Map<string, string>) => {
prevPks.set(publicKeyMsg.ethAddress, publicKeyMsg.ethDmPublicKey);
return new Map(prevPks);
});
}
async function handleDirectMessage(
setter: Dispatch<SetStateAction<Message[]>>,
privateKey: string,
wakuMsg: WakuMessage
) {
console.log('Waku Message received:', wakuMsg);
if (!wakuMsg.payload) return;
const directMessage: DirectMessage = decode(wakuMsg.payload);
const text = await decryptMessage(privateKey, directMessage);
const timestamp = wakuMsg.timestamp ? wakuMsg.timestamp : new Date();
console.log('Message decrypted:', text);
setter((prevMsgs: Message[]) => {
const copy = prevMsgs.slice();
copy.push({
text: text,
timestamp: timestamp,
});
return copy;
});
}

View File

@ -7,7 +7,7 @@ export interface Props {
messages: Message[]; messages: Message[];
} }
export function Messages(props: Props) { export default function Messages(props: Props) {
const messages = props.messages.map((msg) => { const messages = props.messages.map((msg) => {
return ( return (
<li> <li>

View File

@ -28,7 +28,7 @@ export interface Props {
recipients: Map<string, string>; recipients: Map<string, string>;
} }
export function SendMessage({ waku, recipients }: Props) { export default function SendMessage({ waku, recipients }: Props) {
const classes = useStyles(); const classes = useStyles();
const [recipient, setRecipient] = useState<string>(''); const [recipient, setRecipient] = useState<string>('');
const [message, setMessage] = useState<string>(); const [message, setMessage] = useState<string>();

View File

@ -9,7 +9,10 @@ export interface Props {
setEthDmKeyPair: (keyPair: KeyPair) => void; setEthDmKeyPair: (keyPair: KeyPair) => void;
} }
export function KeyPairHandling({ ethDmKeyPair, setEthDmKeyPair }: Props) { export default function KeyPairHandling({
ethDmKeyPair,
setEthDmKeyPair,
}: Props) {
const generateKeyPair = () => { const generateKeyPair = () => {
if (ethDmKeyPair) return; if (ethDmKeyPair) return;