Merge pull request #75 from waku-org/upgrade-js-waku-eth-pm
This commit is contained in:
commit
878b37e761
|
@ -5,7 +5,8 @@
|
||||||
- Private Messaging
|
- Private Messaging
|
||||||
- React/TypeScript
|
- React/TypeScript
|
||||||
- Waku Light Push
|
- Waku Light Push
|
||||||
- Signature with Web3
|
- Waku Filter
|
||||||
|
- Signature with Web3 (EIP-712, sign typed data)
|
||||||
- Asymmetric Encryption
|
- Asymmetric Encryption
|
||||||
- Symmetric Encryption
|
- Symmetric Encryption
|
||||||
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
const webpack = require('webpack');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
dev: (config) => {
|
|
||||||
// Override webpack 5 config from react-scripts to load polyfills
|
|
||||||
if (!config.resolve) config.resolve = {};
|
|
||||||
if (!config.resolve.fallback) config.resolve.fallback = {};
|
|
||||||
Object.assign(config.resolve.fallback, {
|
|
||||||
buffer: require.resolve('buffer'),
|
|
||||||
crypto: false,
|
|
||||||
stream: require.resolve('stream-browserify'),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!config.plugins) config.plugins = [];
|
|
||||||
config.plugins.push(
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.ENV': JSON.stringify('dev'),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
config.plugins.push(
|
|
||||||
new webpack.ProvidePlugin({
|
|
||||||
process: 'process/browser.js',
|
|
||||||
Buffer: ['buffer', 'Buffer'],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
|
||||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
|
||||||
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
prod: (config) => {
|
|
||||||
// Override webpack 5 config from react-scripts to load polyfills
|
|
||||||
if (!config.resolve) config.resolve = {};
|
|
||||||
if (!config.resolve.fallback) config.resolve.fallback = {};
|
|
||||||
Object.assign(config.resolve.fallback, {
|
|
||||||
buffer: require.resolve('buffer'),
|
|
||||||
crypto: false,
|
|
||||||
stream: require.resolve('stream-browserify'),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!config.plugins) config.plugins = [];
|
|
||||||
config.plugins.push(
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.ENV': JSON.stringify('prod'),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
config.plugins.push(
|
|
||||||
new webpack.ProvidePlugin({
|
|
||||||
process: 'process/browser.js',
|
|
||||||
Buffer: ['buffer', 'Buffer'],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
|
||||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
|
||||||
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -2,25 +2,24 @@
|
||||||
"name": "eth-pm",
|
"name": "eth-pm",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "/examples/eth-pm",
|
"homepage": "/eth-pm",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersproject/providers": "^5.6.8",
|
"@ethersproject/abstract-signer": "5.7.0",
|
||||||
|
"@ethersproject/providers": "5.7.0",
|
||||||
"@material-ui/core": "^4.12.3",
|
"@material-ui/core": "^4.12.3",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"eth-sig-util": "^3.0.1",
|
"ethers": "5.7.0",
|
||||||
"ethers": "^5.5.4",
|
|
||||||
"fontsource-roboto": "^4.0.0",
|
"fontsource-roboto": "^4.0.0",
|
||||||
"js-waku": "^0.24.0",
|
"js-waku": "0.24.0-cdd0752",
|
||||||
"protobufjs": "^6.11.2",
|
"protobufjs": "^6.11.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"uint8arrays": "^3.1.0"
|
"uint8arrays": "^3.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cra-webpack-rewired start",
|
"start": "react-scripts start",
|
||||||
"build": "run-s build:*",
|
"build": "react-scripts build",
|
||||||
"build:react": "cra-webpack-rewired build",
|
"eject": "react-scripts eject",
|
||||||
"eject": "cra-webpack-rewired eject",
|
|
||||||
"fix": "run-s fix:*",
|
"fix": "run-s fix:*",
|
||||||
"test": "run-s build test:*",
|
"test": "run-s build test:*",
|
||||||
"test:lint": "eslint src --ext .ts --ext .tsx",
|
"test:lint": "eslint src --ext .ts --ext .tsx",
|
||||||
|
@ -55,16 +54,11 @@
|
||||||
"@types/node": "^17.0.19",
|
"@types/node": "^17.0.19",
|
||||||
"@types/react": "^17.0.39",
|
"@types/react": "^17.0.39",
|
||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.11",
|
||||||
"assert": "^2.0.0",
|
|
||||||
"buffer": "^6.0.3",
|
|
||||||
"cra-webpack-rewired": "^1.0.1",
|
|
||||||
"cspell": "^6.0.0",
|
"cspell": "^6.0.0",
|
||||||
"eslint": "^8.9.0",
|
"eslint": "^8.9.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"process": "^0.11.10",
|
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.0",
|
||||||
"stream-browserify": "^3.0.0",
|
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.5.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@ import {
|
||||||
} from "./waku";
|
} from "./waku";
|
||||||
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
|
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
|
||||||
import ConnectWallet from "./ConnectWallet";
|
import ConnectWallet from "./ConnectWallet";
|
||||||
|
import { waku_message } from "js-waku";
|
||||||
|
|
||||||
const theme = createMuiTheme({
|
const theme = createMuiTheme({
|
||||||
palette: {
|
palette: {
|
||||||
|
@ -77,10 +78,10 @@ function App() {
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
const [address, setAddress] = useState<string>();
|
const [address, setAddress] = useState<string>();
|
||||||
const [peerStats, setPeerStats] = useState<{
|
const [peerStats, setPeerStats] = useState<{
|
||||||
relayPeers: number;
|
filterPeers: number;
|
||||||
lightPushPeers: number;
|
lightPushPeers: number;
|
||||||
}>({
|
}>({
|
||||||
relayPeers: 0,
|
filterPeers: 0,
|
||||||
lightPushPeers: 0,
|
lightPushPeers: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -88,15 +89,15 @@ function App() {
|
||||||
|
|
||||||
// Waku initialization
|
// Waku initialization
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (waku) return;
|
(async () => {
|
||||||
initWaku()
|
if (waku) return;
|
||||||
.then((_waku) => {
|
|
||||||
console.log("waku: ready");
|
const _waku = await initWaku();
|
||||||
setWaku(_waku);
|
console.log("waku: ready");
|
||||||
})
|
setWaku(_waku);
|
||||||
.catch((e) => {
|
})().catch((e) => {
|
||||||
console.error("Failed to initiate Waku", e);
|
console.error("Failed to initiate Waku", e);
|
||||||
});
|
});
|
||||||
}, [waku]);
|
}, [waku]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -108,16 +109,34 @@ function App() {
|
||||||
setPublicKeys
|
setPublicKeys
|
||||||
);
|
);
|
||||||
|
|
||||||
waku.relay.addDecryptionKey(PublicKeyMessageEncryptionKey);
|
let unsubscribe: undefined | (() => Promise<void>);
|
||||||
waku.relay.addObserver(observerPublicKeyMessage, [PublicKeyContentTopic]);
|
|
||||||
|
waku.filter.addDecryptionKey(PublicKeyMessageEncryptionKey, {
|
||||||
|
method: waku_message.DecryptionMethod.Symmetric,
|
||||||
|
contentTopics: [PublicKeyContentTopic],
|
||||||
|
});
|
||||||
|
waku.filter
|
||||||
|
.subscribe(observerPublicKeyMessage, [PublicKeyContentTopic])
|
||||||
|
.then(
|
||||||
|
(_unsubscribe) => {
|
||||||
|
console.log("subscribed to ", PublicKeyContentTopic);
|
||||||
|
unsubscribe = _unsubscribe;
|
||||||
|
},
|
||||||
|
(e) => {
|
||||||
|
console.error("Failed to subscribe", e);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return function cleanUp() {
|
return function cleanUp() {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
|
waku.filter.deleteDecryptionKey(PublicKeyMessageEncryptionKey);
|
||||||
waku.relay.deleteDecryptionKey(PublicKeyMessageEncryptionKey);
|
if (typeof unsubscribe === "undefined") return;
|
||||||
waku.relay.deleteObserver(observerPublicKeyMessage, [
|
unsubscribe().then(
|
||||||
PublicKeyContentTopic,
|
() => {
|
||||||
]);
|
console.log("unsubscribed to ", PublicKeyContentTopic);
|
||||||
|
},
|
||||||
|
(e) => console.error("Failed to unsubscribe", e)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}, [waku, address]);
|
}, [waku, address]);
|
||||||
|
|
||||||
|
@ -125,13 +144,16 @@ function App() {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!encryptionKeyPair) return;
|
if (!encryptionKeyPair) return;
|
||||||
|
|
||||||
waku.relay.addDecryptionKey(encryptionKeyPair.privateKey);
|
waku.filter.addDecryptionKey(encryptionKeyPair.privateKey, {
|
||||||
|
method: waku_message.DecryptionMethod.Asymmetric,
|
||||||
|
contentTopics: [PrivateMessageContentTopic],
|
||||||
|
});
|
||||||
|
|
||||||
return function cleanUp() {
|
return function cleanUp() {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!encryptionKeyPair) return;
|
if (!encryptionKeyPair) return;
|
||||||
|
|
||||||
waku.relay.deleteDecryptionKey(encryptionKeyPair.privateKey);
|
waku.filter.deleteDecryptionKey(encryptionKeyPair.privateKey);
|
||||||
};
|
};
|
||||||
}, [waku, encryptionKeyPair]);
|
}, [waku, encryptionKeyPair]);
|
||||||
|
|
||||||
|
@ -146,16 +168,23 @@ function App() {
|
||||||
address
|
address
|
||||||
);
|
);
|
||||||
|
|
||||||
waku.relay.addObserver(observerPrivateMessage, [
|
let unsubscribe: undefined | (() => Promise<void>);
|
||||||
PrivateMessageContentTopic,
|
|
||||||
]);
|
waku.filter
|
||||||
|
.subscribe(observerPrivateMessage, [PrivateMessageContentTopic])
|
||||||
|
.then(
|
||||||
|
(_unsubscribe) => {
|
||||||
|
unsubscribe = _unsubscribe;
|
||||||
|
},
|
||||||
|
(e) => {
|
||||||
|
console.error("Failed to subscribe", e);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return function cleanUp() {
|
return function cleanUp() {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!observerPrivateMessage) return;
|
if (typeof unsubscribe === "undefined") return;
|
||||||
waku.relay.deleteObserver(observerPrivateMessage, [
|
unsubscribe().catch((e) => console.error("Failed to unsubscribe", e));
|
||||||
PrivateMessageContentTopic,
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
}, [waku, address, encryptionKeyPair]);
|
}, [waku, address, encryptionKeyPair]);
|
||||||
|
|
||||||
|
@ -163,15 +192,12 @@ function App() {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
|
|
||||||
const interval = setInterval(async () => {
|
const interval = setInterval(async () => {
|
||||||
let lightPushPeers = 0;
|
const lightPushPeers = await waku.store.peers();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
const filterPeers = await waku.filter.peers();
|
||||||
for await (const _peer of waku.store.peers) {
|
|
||||||
lightPushPeers++;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPeerStats({
|
setPeerStats({
|
||||||
relayPeers: waku.relay.getPeers().size,
|
filterPeers: filterPeers.length,
|
||||||
lightPushPeers,
|
lightPushPeers: lightPushPeers.length,
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
|
@ -199,7 +225,7 @@ function App() {
|
||||||
/>
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography className={classes.peers} aria-label="connected-peers">
|
<Typography className={classes.peers} aria-label="connected-peers">
|
||||||
Peers: {peerStats.relayPeers} relay, {peerStats.lightPushPeers}{" "}
|
Peers: {peerStats.filterPeers} filter, {peerStats.lightPushPeers}{" "}
|
||||||
light push
|
light push
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6" className={classes.title}>
|
<Typography variant="h6" className={classes.title}>
|
||||||
|
@ -228,7 +254,7 @@ function App() {
|
||||||
address={address}
|
address={address}
|
||||||
EncryptionKeyPair={encryptionKeyPair}
|
EncryptionKeyPair={encryptionKeyPair}
|
||||||
waku={waku}
|
waku={waku}
|
||||||
providerRequest={provider?.provider?.request}
|
signer={provider?.getSigner()}
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
|
@ -8,21 +8,20 @@ import {
|
||||||
import { PublicKeyMessage } from "./messaging/wire";
|
import { PublicKeyMessage } from "./messaging/wire";
|
||||||
import { WakuMessage, Waku } from "js-waku";
|
import { WakuMessage, Waku } from "js-waku";
|
||||||
import { PublicKeyContentTopic } from "./waku";
|
import { PublicKeyContentTopic } from "./waku";
|
||||||
|
import type { TypedDataSigner } from "@ethersproject/abstract-signer";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
EncryptionKeyPair: KeyPair | undefined;
|
EncryptionKeyPair: KeyPair | undefined;
|
||||||
waku: Waku | undefined;
|
waku: Waku | undefined;
|
||||||
address: string | undefined;
|
address: string | undefined;
|
||||||
providerRequest:
|
signer: TypedDataSigner | undefined;
|
||||||
| ((request: { method: string; params?: Array<any> }) => Promise<any>)
|
|
||||||
| undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BroadcastPublicKey({
|
export default function BroadcastPublicKey({
|
||||||
EncryptionKeyPair,
|
EncryptionKeyPair,
|
||||||
waku,
|
waku,
|
||||||
address,
|
address,
|
||||||
providerRequest,
|
signer,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [publicKeyMsg, setPublicKeyMsg] = useState<PublicKeyMessage>();
|
const [publicKeyMsg, setPublicKeyMsg] = useState<PublicKeyMessage>();
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ export default function BroadcastPublicKey({
|
||||||
if (!EncryptionKeyPair) return;
|
if (!EncryptionKeyPair) return;
|
||||||
if (!address) return;
|
if (!address) return;
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!providerRequest) return;
|
if (!signer) return;
|
||||||
|
|
||||||
if (publicKeyMsg) {
|
if (publicKeyMsg) {
|
||||||
encodePublicKeyWakuMessage(publicKeyMsg)
|
encodePublicKeyWakuMessage(publicKeyMsg)
|
||||||
|
@ -43,11 +42,7 @@ export default function BroadcastPublicKey({
|
||||||
console.log("Failed to encode Public Key Message in Waku Message", e);
|
console.log("Failed to encode Public Key Message in Waku Message", e);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
createPublicKeyMessage(
|
createPublicKeyMessage(address, EncryptionKeyPair.publicKey, signer)
|
||||||
address,
|
|
||||||
EncryptionKeyPair.publicKey,
|
|
||||||
providerRequest
|
|
||||||
)
|
|
||||||
.then((msg) => {
|
.then((msg) => {
|
||||||
setPublicKeyMsg(msg);
|
setPublicKeyMsg(msg);
|
||||||
encodePublicKeyWakuMessage(msg)
|
encodePublicKeyWakuMessage(msg)
|
||||||
|
@ -77,7 +72,7 @@ export default function BroadcastPublicKey({
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={broadcastPublicKey}
|
onClick={broadcastPublicKey}
|
||||||
disabled={!EncryptionKeyPair || !waku || !address || !providerRequest}
|
disabled={!EncryptionKeyPair || !waku || !address || !signer}
|
||||||
>
|
>
|
||||||
Broadcast Encryption Public Key
|
Broadcast Encryption Public Key
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -11,17 +11,14 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ConnectWallet({ setAddress, setProvider }: Props) {
|
export default function ConnectWallet({ setAddress, setProvider }: Props) {
|
||||||
const connectWallet = () => {
|
const connectWallet = async () => {
|
||||||
try {
|
try {
|
||||||
window.ethereum
|
const provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||||
.request({ method: "eth_requestAccounts" })
|
const accounts = await provider.send("eth_requestAccounts", []);
|
||||||
.then((accounts: string[]) => {
|
setAddress(accounts[0]);
|
||||||
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
setProvider(provider);
|
||||||
setAddress(accounts[0]);
|
|
||||||
setProvider(_provider);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("No web3 provider available");
|
console.error("No web3 provider available", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@ import "@ethersproject/shims";
|
||||||
|
|
||||||
import { PublicKeyMessage } from "./messaging/wire";
|
import { PublicKeyMessage } from "./messaging/wire";
|
||||||
import { generatePrivateKey, getPublicKey, utils } from "js-waku";
|
import { generatePrivateKey, getPublicKey, utils } from "js-waku";
|
||||||
import * as sigUtil from "eth-sig-util";
|
|
||||||
import { PublicKeyContentTopic } from "./waku";
|
import { PublicKeyContentTopic } from "./waku";
|
||||||
import { keccak256 } from "ethers/lib/utils";
|
import { keccak256, _TypedDataEncoder, recoverAddress } from "ethers/lib/utils";
|
||||||
import { equals } from "uint8arrays/equals";
|
import { equals } from "uint8arrays/equals";
|
||||||
|
import type { TypedDataSigner } from "@ethersproject/abstract-signer";
|
||||||
|
|
||||||
export const PublicKeyMessageEncryptionKey = utils.hexToBytes(
|
export const PublicKeyMessageEncryptionKey = utils.hexToBytes(
|
||||||
keccak256(Buffer.from(PublicKeyContentTopic, "utf-8"))
|
keccak256(utils.utf8ToBytes(PublicKeyContentTopic))
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface KeyPair {
|
export interface KeyPair {
|
||||||
|
@ -33,15 +33,12 @@ export async function generateEncryptionKeyPair(): Promise<KeyPair> {
|
||||||
export async function createPublicKeyMessage(
|
export async function createPublicKeyMessage(
|
||||||
address: string,
|
address: string,
|
||||||
encryptionPublicKey: Uint8Array,
|
encryptionPublicKey: Uint8Array,
|
||||||
providerRequest: (request: {
|
signer: TypedDataSigner
|
||||||
method: string;
|
|
||||||
params?: Array<any>;
|
|
||||||
}) => Promise<any>
|
|
||||||
): Promise<PublicKeyMessage> {
|
): Promise<PublicKeyMessage> {
|
||||||
const signature = await signEncryptionKey(
|
const signature = await signEncryptionKey(
|
||||||
encryptionPublicKey,
|
encryptionPublicKey,
|
||||||
address,
|
address,
|
||||||
providerRequest
|
signer
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("Asking wallet to sign Public Key Message");
|
console.log("Asking wallet to sign Public Key Message");
|
||||||
|
@ -55,12 +52,12 @@ export async function createPublicKeyMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) {
|
function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) {
|
||||||
return JSON.stringify({
|
return {
|
||||||
domain: {
|
domain: {
|
||||||
name: "Ethereum Private Message over Waku",
|
name: "Ethereum Private Message over Waku",
|
||||||
version: "1",
|
version: "1",
|
||||||
},
|
},
|
||||||
message: {
|
value: {
|
||||||
message:
|
message:
|
||||||
"By signing this message you certify that messages addressed to `ownerAddress` must be encrypted with `encryptionPublicKey`",
|
"By signing this message you certify that messages addressed to `ownerAddress` must be encrypted with `encryptionPublicKey`",
|
||||||
encryptionPublicKey: utils.bytesToHex(encryptionPublicKey),
|
encryptionPublicKey: utils.bytesToHex(encryptionPublicKey),
|
||||||
|
@ -69,35 +66,26 @@ function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) {
|
||||||
// Refers to the keys of the *types* object below.
|
// Refers to the keys of the *types* object below.
|
||||||
primaryType: "PublishEncryptionPublicKey",
|
primaryType: "PublishEncryptionPublicKey",
|
||||||
types: {
|
types: {
|
||||||
EIP712Domain: [
|
|
||||||
{ name: "name", type: "string" },
|
|
||||||
{ name: "version", type: "string" },
|
|
||||||
],
|
|
||||||
PublishEncryptionPublicKey: [
|
PublishEncryptionPublicKey: [
|
||||||
{ name: "message", type: "string" },
|
{ name: "message", type: "string" },
|
||||||
{ name: "encryptionPublicKey", type: "string" },
|
{ name: "encryptionPublicKey", type: "string" },
|
||||||
{ name: "ownerAddress", type: "string" },
|
{ name: "ownerAddress", type: "string" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function signEncryptionKey(
|
export async function signEncryptionKey(
|
||||||
encryptionPublicKey: Uint8Array,
|
encryptionPublicKey: Uint8Array,
|
||||||
fromAddress: string,
|
fromAddress: string,
|
||||||
providerRequest: (request: {
|
signer: TypedDataSigner
|
||||||
method: string;
|
|
||||||
params?: Array<any>;
|
|
||||||
from?: string;
|
|
||||||
}) => Promise<any>
|
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
const msgParams = buildMsgParams(encryptionPublicKey, fromAddress);
|
const { domain, types, value } = buildMsgParams(
|
||||||
|
encryptionPublicKey,
|
||||||
|
fromAddress
|
||||||
|
);
|
||||||
|
|
||||||
const result = await providerRequest({
|
const result = await signer._signTypedData(domain, types, value);
|
||||||
method: "eth_signTypedData_v4",
|
|
||||||
params: [fromAddress, msgParams],
|
|
||||||
from: fromAddress,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
||||||
|
|
||||||
|
@ -108,18 +96,21 @@ export async function signEncryptionKey(
|
||||||
* Validate that the Encryption Public Key was signed by the holder of the given Ethereum address.
|
* Validate that the Encryption Public Key was signed by the holder of the given Ethereum address.
|
||||||
*/
|
*/
|
||||||
export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
||||||
const recovered = sigUtil.recoverTypedSignature_v4({
|
const { domain, types, value } = buildMsgParams(
|
||||||
data: JSON.parse(
|
msg.encryptionPublicKey,
|
||||||
buildMsgParams(
|
"0x" + utils.bytesToHex(msg.ethAddress)
|
||||||
msg.encryptionPublicKey,
|
);
|
||||||
"0x" + utils.bytesToHex(msg.ethAddress)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
sig: "0x" + utils.bytesToHex(msg.signature),
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Recovered", recovered);
|
try {
|
||||||
console.log("ethAddress", "0x" + utils.bytesToHex(msg.ethAddress));
|
const hash = _TypedDataEncoder.hash(domain, types, value);
|
||||||
|
|
||||||
return equals(utils.hexToBytes(recovered), msg.ethAddress);
|
const recovered = recoverAddress(hash, msg.signature);
|
||||||
|
console.log("Recovered", recovered);
|
||||||
|
console.log("ethAddress", "0x" + utils.bytesToHex(msg.ethAddress));
|
||||||
|
|
||||||
|
return equals(utils.hexToBytes(recovered.toLowerCase()), msg.ethAddress);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not recover public key from signature", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ function sendMessage(
|
||||||
.push(msg)
|
.push(msg)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log("Message sent", res);
|
console.log("Message sent", res);
|
||||||
callback(res ? res.isSuccess : false);
|
callback(res?.isSuccess ?? false);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error("Failed to send message", e);
|
console.error("Failed to send message", e);
|
||||||
|
|
|
@ -29,9 +29,7 @@ export class PublicKeyMessage {
|
||||||
return PublicKeyMessage.Type.encode(message).finish();
|
return PublicKeyMessage.Type.encode(message).finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static decode(
|
public static decode(bytes: Uint8Array): PublicKeyMessage | undefined {
|
||||||
bytes: Uint8Array | Buffer
|
|
||||||
): PublicKeyMessage | undefined {
|
|
||||||
const payload = PublicKeyMessage.Type.decode(
|
const payload = PublicKeyMessage.Type.decode(
|
||||||
bytes
|
bytes
|
||||||
) as unknown as PublicKeyMessagePayload;
|
) as unknown as PublicKeyMessagePayload;
|
||||||
|
@ -80,7 +78,7 @@ export class PrivateMessage {
|
||||||
return PrivateMessage.Type.encode(message).finish();
|
return PrivateMessage.Type.encode(message).finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static decode(bytes: Uint8Array | Buffer): PrivateMessage | undefined {
|
public static decode(bytes: Uint8Array): PrivateMessage | undefined {
|
||||||
const payload = PrivateMessage.Type.decode(
|
const payload = PrivateMessage.Type.decode(
|
||||||
bytes
|
bytes
|
||||||
) as unknown as PrivateMessagePayload;
|
) as unknown as PrivateMessagePayload;
|
||||||
|
|
|
@ -1,26 +1,35 @@
|
||||||
import { Dispatch, SetStateAction } from "react";
|
import { Dispatch, SetStateAction } from "react";
|
||||||
import { utils, Waku, WakuMessage } from "js-waku";
|
import {
|
||||||
|
Protocols,
|
||||||
|
utils,
|
||||||
|
waitForRemotePeer,
|
||||||
|
Waku,
|
||||||
|
WakuMessage,
|
||||||
|
} from "js-waku";
|
||||||
import { PrivateMessage, PublicKeyMessage } from "./messaging/wire";
|
import { PrivateMessage, PublicKeyMessage } from "./messaging/wire";
|
||||||
import { validatePublicKeyMessage } from "./crypto";
|
import { validatePublicKeyMessage } from "./crypto";
|
||||||
import { Message } from "./messaging/Messages";
|
import { Message } from "./messaging/Messages";
|
||||||
import { equals } from "uint8arrays/equals";
|
import { equals } from "uint8arrays/equals";
|
||||||
|
import { createWaku } from "js-waku/lib/create_waku";
|
||||||
|
import { PeerDiscoveryStaticPeers } from "js-waku/lib/peer_discovery_static_list";
|
||||||
|
import {
|
||||||
|
getPredefinedBootstrapNodes,
|
||||||
|
Fleet,
|
||||||
|
} from "js-waku/lib/predefined_bootstrap_nodes";
|
||||||
|
|
||||||
export const PublicKeyContentTopic = "/eth-pm/1/public-key/proto";
|
export const PublicKeyContentTopic = "/eth-pm/1/public-key/proto";
|
||||||
export const PrivateMessageContentTopic = "/eth-pm/1/private-message/proto";
|
export const PrivateMessageContentTopic = "/eth-pm/1/private-message/proto";
|
||||||
|
|
||||||
export async function initWaku(): Promise<Waku> {
|
export async function initWaku(): Promise<Waku> {
|
||||||
const waku = await Waku.create({ bootstrap: { default: true } });
|
const waku = await createWaku({
|
||||||
|
libp2p: {
|
||||||
// Wait to be connected to at least one peer
|
peerDiscovery: [
|
||||||
await new Promise((resolve, reject) => {
|
new PeerDiscoveryStaticPeers(getPredefinedBootstrapNodes(Fleet.Test)),
|
||||||
// If we are not connected to any peer within 10sec let's just reject
|
],
|
||||||
// As we are not implementing connection management in this example
|
},
|
||||||
|
|
||||||
setTimeout(reject, 10000);
|
|
||||||
waku.libp2p.connectionManager.on("peer:connect", () => {
|
|
||||||
resolve(null);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
await waku.start();
|
||||||
|
await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]);
|
||||||
|
|
||||||
return waku;
|
return waku;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue