2022-06-17 00:48:15 +00:00
|
|
|
import "@ethersproject/shims";
|
|
|
|
|
|
|
|
import React, { useEffect, useState } from "react";
|
|
|
|
import "./App.css";
|
2022-11-04 05:38:22 +00:00
|
|
|
import type { WakuPrivacy } from "@waku/interfaces";
|
|
|
|
import { AsymDecoder, SymDecoder } from "@waku/message-encryption";
|
2022-06-17 00:48:15 +00:00
|
|
|
import { KeyPair, PublicKeyMessageEncryptionKey } from "./crypto";
|
|
|
|
import { Message } from "./messaging/Messages";
|
|
|
|
import "fontsource-roboto";
|
|
|
|
import { AppBar, IconButton, Toolbar, Typography } from "@material-ui/core";
|
|
|
|
import KeyPairHandling from "./key_pair_handling/KeyPairHandling";
|
|
|
|
import {
|
|
|
|
createMuiTheme,
|
|
|
|
ThemeProvider,
|
|
|
|
makeStyles,
|
|
|
|
} from "@material-ui/core/styles";
|
|
|
|
import { teal, purple, green } from "@material-ui/core/colors";
|
|
|
|
import WifiIcon from "@material-ui/icons/Wifi";
|
|
|
|
import BroadcastPublicKey from "./BroadcastPublicKey";
|
|
|
|
import Messaging from "./messaging/Messaging";
|
|
|
|
import {
|
|
|
|
PrivateMessageContentTopic,
|
|
|
|
handlePrivateMessage,
|
|
|
|
handlePublicKeyMessage,
|
|
|
|
initWaku,
|
|
|
|
PublicKeyContentTopic,
|
|
|
|
} from "./waku";
|
|
|
|
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
|
|
|
|
import ConnectWallet from "./ConnectWallet";
|
|
|
|
|
|
|
|
const theme = createMuiTheme({
|
|
|
|
palette: {
|
|
|
|
primary: {
|
|
|
|
main: purple[500],
|
|
|
|
},
|
|
|
|
secondary: {
|
|
|
|
main: teal[600],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const useStyles = makeStyles({
|
|
|
|
root: {
|
|
|
|
textAlign: "center",
|
|
|
|
display: "flex",
|
|
|
|
flexDirection: "column",
|
|
|
|
minHeight: "100vh",
|
|
|
|
},
|
|
|
|
appBar: {
|
|
|
|
// height: '200p',
|
|
|
|
},
|
|
|
|
container: {
|
|
|
|
display: "flex",
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
main: {
|
|
|
|
flex: 1,
|
|
|
|
margin: "10px",
|
|
|
|
},
|
|
|
|
wakuStatus: {
|
|
|
|
marginRight: theme.spacing(2),
|
|
|
|
},
|
|
|
|
title: {
|
|
|
|
flexGrow: 1,
|
|
|
|
},
|
|
|
|
peers: {},
|
|
|
|
});
|
|
|
|
|
|
|
|
function App() {
|
2022-11-07 10:46:59 +00:00
|
|
|
const [waku, setWaku] = useState<WakuPrivacy>();
|
2022-06-17 00:48:15 +00:00
|
|
|
const [provider, setProvider] = useState<Web3Provider>();
|
|
|
|
const [encryptionKeyPair, setEncryptionKeyPair] = useState<
|
|
|
|
KeyPair | undefined
|
|
|
|
>();
|
2022-09-20 04:21:52 +00:00
|
|
|
const [privateMessageDecoder, setPrivateMessageDecoder] =
|
|
|
|
useState<AsymDecoder>();
|
2022-06-17 00:48:15 +00:00
|
|
|
const [publicKeys, setPublicKeys] = useState<Map<string, Uint8Array>>(
|
|
|
|
new Map()
|
|
|
|
);
|
|
|
|
const [messages, setMessages] = useState<Message[]>([]);
|
|
|
|
const [address, setAddress] = useState<string>();
|
|
|
|
const [peerStats, setPeerStats] = useState<{
|
2022-11-07 10:46:59 +00:00
|
|
|
relayPeers: number;
|
2022-06-17 00:48:15 +00:00
|
|
|
}>({
|
2022-11-07 10:46:59 +00:00
|
|
|
relayPeers: 0,
|
2022-06-17 00:48:15 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
const classes = useStyles();
|
|
|
|
|
|
|
|
// Waku initialization
|
|
|
|
useEffect(() => {
|
2022-08-20 08:31:52 +00:00
|
|
|
(async () => {
|
|
|
|
if (waku) return;
|
|
|
|
|
|
|
|
const _waku = await initWaku();
|
|
|
|
console.log("waku: ready");
|
|
|
|
setWaku(_waku);
|
|
|
|
})().catch((e) => {
|
|
|
|
console.error("Failed to initiate Waku", e);
|
|
|
|
});
|
2022-06-17 00:48:15 +00:00
|
|
|
}, [waku]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!waku) return;
|
|
|
|
|
|
|
|
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
|
|
|
|
{},
|
|
|
|
address,
|
|
|
|
setPublicKeys
|
|
|
|
);
|
|
|
|
|
2022-09-20 04:21:52 +00:00
|
|
|
const publicKeyMessageDecoder = new SymDecoder(
|
|
|
|
PublicKeyContentTopic,
|
|
|
|
PublicKeyMessageEncryptionKey
|
|
|
|
);
|
|
|
|
|
2022-08-20 08:49:48 +00:00
|
|
|
let unsubscribe: undefined | (() => Promise<void>);
|
|
|
|
|
2022-11-07 10:46:59 +00:00
|
|
|
waku.relay.addObserver(publicKeyMessageDecoder, observerPublicKeyMessage);
|
2022-06-17 00:48:15 +00:00
|
|
|
|
|
|
|
return function cleanUp() {
|
2022-08-20 08:49:48 +00:00
|
|
|
if (typeof unsubscribe === "undefined") return;
|
2022-09-20 04:21:52 +00:00
|
|
|
|
2022-08-20 08:49:48 +00:00
|
|
|
unsubscribe().then(
|
|
|
|
() => {
|
|
|
|
console.log("unsubscribed to ", PublicKeyContentTopic);
|
|
|
|
},
|
|
|
|
(e) => console.error("Failed to unsubscribe", e)
|
2022-08-20 08:31:52 +00:00
|
|
|
);
|
2022-06-17 00:48:15 +00:00
|
|
|
};
|
2022-08-20 08:49:48 +00:00
|
|
|
}, [waku, address]);
|
2022-06-17 00:48:15 +00:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!encryptionKeyPair) return;
|
|
|
|
|
2022-09-20 04:21:52 +00:00
|
|
|
setPrivateMessageDecoder(
|
|
|
|
new AsymDecoder(PrivateMessageContentTopic, encryptionKeyPair.privateKey)
|
|
|
|
);
|
|
|
|
}, [encryptionKeyPair]);
|
2022-06-17 00:48:15 +00:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!waku) return;
|
2022-09-20 04:21:52 +00:00
|
|
|
if (!privateMessageDecoder) return;
|
2022-06-17 00:48:15 +00:00
|
|
|
if (!address) return;
|
|
|
|
|
|
|
|
const observerPrivateMessage = handlePrivateMessage.bind(
|
|
|
|
{},
|
|
|
|
setMessages,
|
|
|
|
address
|
|
|
|
);
|
|
|
|
|
2022-08-20 08:49:48 +00:00
|
|
|
let unsubscribe: undefined | (() => Promise<void>);
|
|
|
|
|
2022-11-07 10:46:59 +00:00
|
|
|
waku.relay.addObserver(privateMessageDecoder, observerPrivateMessage);
|
2022-06-17 00:48:15 +00:00
|
|
|
|
|
|
|
return function cleanUp() {
|
2022-08-20 08:49:48 +00:00
|
|
|
if (typeof unsubscribe === "undefined") return;
|
|
|
|
unsubscribe().catch((e) => console.error("Failed to unsubscribe", e));
|
2022-06-17 00:48:15 +00:00
|
|
|
};
|
2022-09-20 04:21:52 +00:00
|
|
|
}, [waku, address, privateMessageDecoder]);
|
2022-06-17 00:48:15 +00:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!waku) return;
|
|
|
|
|
|
|
|
const interval = setInterval(async () => {
|
2022-11-07 10:46:59 +00:00
|
|
|
const peers = waku.relay.getPeers();
|
2022-06-17 00:48:15 +00:00
|
|
|
|
|
|
|
setPeerStats({
|
2022-11-07 10:46:59 +00:00
|
|
|
relayPeers: peers.length,
|
2022-06-17 00:48:15 +00:00
|
|
|
});
|
|
|
|
}, 1000);
|
|
|
|
return () => clearInterval(interval);
|
|
|
|
}, [waku]);
|
|
|
|
|
|
|
|
let addressDisplay = "";
|
|
|
|
if (address) {
|
|
|
|
addressDisplay =
|
|
|
|
address.substr(0, 6) + "..." + address.substr(address.length - 4, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<ThemeProvider theme={theme}>
|
|
|
|
<div className={classes.root}>
|
|
|
|
<AppBar className={classes.appBar} position="static">
|
|
|
|
<Toolbar>
|
|
|
|
<IconButton
|
|
|
|
edge="start"
|
|
|
|
className={classes.wakuStatus}
|
|
|
|
aria-label="waku-status"
|
|
|
|
>
|
|
|
|
<WifiIcon
|
|
|
|
color={waku ? undefined : "disabled"}
|
|
|
|
style={waku ? { color: green[500] } : {}}
|
|
|
|
/>
|
|
|
|
</IconButton>
|
|
|
|
<Typography className={classes.peers} aria-label="connected-peers">
|
2022-11-07 10:46:59 +00:00
|
|
|
(Relay) Peers: {peerStats.relayPeers}
|
2022-06-17 00:48:15 +00:00
|
|
|
</Typography>
|
|
|
|
<Typography variant="h6" className={classes.title}>
|
|
|
|
Ethereum Private Message
|
|
|
|
</Typography>
|
|
|
|
<Typography>{addressDisplay}</Typography>
|
|
|
|
</Toolbar>
|
|
|
|
</AppBar>
|
|
|
|
|
|
|
|
<div className={classes.container}>
|
|
|
|
<main className={classes.main}>
|
|
|
|
<fieldset>
|
|
|
|
<legend>Wallet</legend>
|
|
|
|
<ConnectWallet
|
|
|
|
setAddress={setAddress}
|
|
|
|
setProvider={setProvider}
|
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
|
|
<legend>Encryption Key Pair</legend>
|
|
|
|
<KeyPairHandling
|
|
|
|
encryptionKeyPair={encryptionKeyPair}
|
|
|
|
setEncryptionKeyPair={setEncryptionKeyPair}
|
|
|
|
/>
|
|
|
|
<BroadcastPublicKey
|
|
|
|
address={address}
|
2022-09-20 04:21:52 +00:00
|
|
|
encryptionKeyPair={encryptionKeyPair}
|
2022-06-17 00:48:15 +00:00
|
|
|
waku={waku}
|
2022-08-29 05:16:41 +00:00
|
|
|
signer={provider?.getSigner()}
|
2022-06-17 00:48:15 +00:00
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
|
|
<legend>Messaging</legend>
|
|
|
|
<Messaging
|
|
|
|
recipients={publicKeys}
|
|
|
|
waku={waku}
|
|
|
|
messages={messages}
|
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
</main>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</ThemeProvider>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default App;
|