mirror of https://github.com/waku-org/js-waku.git
Publish public key to waku network
This commit is contained in:
parent
ee38388326
commit
3bd6b76916
|
@ -54,6 +54,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@ethereum-waffle/jest": "^3.2.2",
|
||||
"ethereum-waffle": "^3.3.0"
|
||||
"@ethersproject/shims": "^5.3.0",
|
||||
"ethereum-waffle": "^3.3.0",
|
||||
"react-native-get-random-values": "^1.7.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
|
||||
export interface Props {
|
||||
sendMessage: (message: string) => void;
|
||||
}
|
||||
function MessageInput(props: Props) {
|
||||
const [inputText, setInputText] = useState("");
|
||||
const [inputText, setInputText] = useState('');
|
||||
|
||||
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setInputText(event.target.value);
|
||||
};
|
||||
|
||||
const onKeyDown = (event: { key: string; }) => {
|
||||
if (event.key === "Enter") {
|
||||
const onKeyDown = (event: { key: string }) => {
|
||||
if (event.key === 'Enter') {
|
||||
props.sendMessage(inputText);
|
||||
setInputText("");
|
||||
setInputText('');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,26 +1,81 @@
|
|||
import 'react-native-get-random-values';
|
||||
|
||||
import '@ethersproject/shims';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import './App.css';
|
||||
import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { ethers } from 'ethers';
|
||||
import { Web3Provider } from '@ethersproject/providers';
|
||||
import {
|
||||
createPublicKeyMessage,
|
||||
PublicKeyMessage,
|
||||
generateEthDmKeyPair,
|
||||
KeyPair,
|
||||
} from './crypto';
|
||||
|
||||
const ContentTopic = '/eth-dm/1/public-key/json';
|
||||
|
||||
declare let window: any;
|
||||
|
||||
function App() {
|
||||
const [waku, setWaku] = useState<Waku>();
|
||||
// const [provider, setProvider] = useState(new ethers.providers.Web3Provider(window.ethereum));
|
||||
const [provider, setProvider] = useState<Web3Provider>();
|
||||
const [ethDmKeyPair, setEthDmKeyPair] = useState<KeyPair>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!waku) {
|
||||
initWaku().then((wakuNode) => {
|
||||
if (provider) return;
|
||||
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||
setProvider(_provider);
|
||||
}, [provider]);
|
||||
|
||||
useEffect(() => {
|
||||
if (waku) return;
|
||||
initWaku()
|
||||
.then((wakuNode) => {
|
||||
setWaku(wakuNode);
|
||||
}).catch(e => {
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to initiate Waku', e);
|
||||
});
|
||||
}
|
||||
}, [waku]);
|
||||
|
||||
useEffect(() => {
|
||||
if (ethDmKeyPair) return;
|
||||
if (!provider) return;
|
||||
|
||||
generateEthDmKeyPair(provider.getSigner())
|
||||
.then((keyPair) => {
|
||||
setEthDmKeyPair(keyPair);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to generate Key Pair', e);
|
||||
});
|
||||
}, [ethDmKeyPair, provider]);
|
||||
|
||||
const onClick = () => {
|
||||
if (!ethDmKeyPair) return;
|
||||
if (!provider) return;
|
||||
if (!waku) return;
|
||||
|
||||
createPublicKeyMessage(provider.getSigner(), ethDmKeyPair.publicKey)
|
||||
.then((msg) => {
|
||||
const wakuMsg = createWakuMessage(msg);
|
||||
waku.relay.send(wakuMsg).catch((e) => {
|
||||
console.error('Failed to send Public Key Message');
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to creat Eth-Dm Publication message', e);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='App'>
|
||||
<header className='App-header'>
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<button onClick={onClick} disabled={!ethDmKeyPair || !waku}>
|
||||
Broadcast Eth-DM Public Key
|
||||
</button>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
|
@ -49,3 +104,8 @@ function getNodes() {
|
|||
return getStatusFleetNodes(Environment.Prod);
|
||||
}
|
||||
}
|
||||
|
||||
function createWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage {
|
||||
const payload = Buffer.from(JSON.stringify(ethDmMsg));
|
||||
return WakuMessage.fromBytes(payload, ContentTopic);
|
||||
}
|
||||
|
|
|
@ -1,24 +1,30 @@
|
|||
import 'react-native-get-random-values';
|
||||
|
||||
import '@ethersproject/shims';
|
||||
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
import {
|
||||
createEthDmPublicationMessage,
|
||||
createPublicKeyMessage,
|
||||
generateEthDmKeyPair,
|
||||
verifyEthDmPublicKey
|
||||
verifyEthDmPublicKey,
|
||||
} from './crypto';
|
||||
import { MockProvider } from "ethereum-waffle";
|
||||
import { MockProvider } from 'ethereum-waffle';
|
||||
import { waffleJest } from '@ethereum-waffle/jest';
|
||||
|
||||
expect.extend(waffleJest);
|
||||
|
||||
test('Signature of Eth-DM key is verifiable', async () => {
|
||||
console.log("get wallet")
|
||||
console.log('get wallet');
|
||||
const [wallet] = new MockProvider().getWallets();
|
||||
console.log("Generate Keys")
|
||||
console.log('Generate Keys');
|
||||
const ethDmKeys = await generateEthDmKeyPair(wallet);
|
||||
|
||||
console.log("Create EthDm message")
|
||||
const ethDmMsg = await createEthDmPublicationMessage(wallet, ethDmKeys.publicKey);
|
||||
console.log('Create EthDm message');
|
||||
const ethDmMsg = await createPublicKeyMessage(wallet, ethDmKeys.publicKey);
|
||||
|
||||
console.log("Verify EthDm message")
|
||||
const res = verifyEthDmPublicKey(ethDmMsg)
|
||||
console.log('Verify EthDm message');
|
||||
const res = verifyEthDmPublicKey(ethDmMsg);
|
||||
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
|
|
@ -1,17 +1,30 @@
|
|||
import 'react-native-get-random-values';
|
||||
|
||||
import '@ethersproject/shims';
|
||||
|
||||
import * as EthCrypto from 'eth-crypto';
|
||||
import { toUtf8Bytes } from '@ethersproject/strings';
|
||||
import { ethers } from 'ethers';
|
||||
import { Signer } from '@ethersproject/abstract-signer';
|
||||
|
||||
const Salt = EthCrypto.hash.keccak256("Salt for Eth-Dm, do not share a signature of this message or other could decrypt your messages");
|
||||
const Salt =
|
||||
'Salt for Eth-Dm, do not share a signature of this message or others could decrypt your messages';
|
||||
|
||||
export interface KeyPair {
|
||||
privateKey: string;
|
||||
publicKey: string;
|
||||
address: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the signature of the Salt (keccak256 hash of the sentence "Salt for eth-dm..." as
|
||||
* Use the signature of the Salt ("Salt for eth-dm...") as
|
||||
* the entropy for the EthCrypto keypair. Note that the entropy is hashed with keccak256
|
||||
* to make the private key.
|
||||
*/
|
||||
export async function generateEthDmKeyPair(web3Signer: Signer) {
|
||||
const signature = await web3Signer.signMessage(Salt)
|
||||
export async function generateEthDmKeyPair(
|
||||
web3Signer: Signer
|
||||
): Promise<KeyPair> {
|
||||
const signature = await web3Signer.signMessage(Salt);
|
||||
const entropy = Buffer.from(toUtf8Bytes(signature));
|
||||
const keys = EthCrypto.createIdentity(entropy);
|
||||
return keys;
|
||||
|
@ -20,7 +33,7 @@ export async function generateEthDmKeyPair(web3Signer: Signer) {
|
|||
/**
|
||||
* Message used to communicate the Eth-Dm public key linked to a given Ethereum account
|
||||
*/
|
||||
export interface EthDmPublicationMessage {
|
||||
export interface PublicKeyMessage {
|
||||
ethDmPublicKey: string;
|
||||
ethAddress: string;
|
||||
sig: string;
|
||||
|
@ -31,21 +44,28 @@ export interface EthDmPublicationMessage {
|
|||
* users know to use this Eth-DM public key to encrypt messages destinated to the
|
||||
* Web3 account holder (ie, Ethereum Address holder).
|
||||
*/
|
||||
export async function createEthDmPublicationMessage(web3Signer: Signer, ethDmPublicKey: string): Promise<EthDmPublicationMessage> {
|
||||
export async function createPublicKeyMessage(
|
||||
web3Signer: Signer,
|
||||
ethDmPublicKey: string
|
||||
): Promise<PublicKeyMessage> {
|
||||
const ethAddress = await web3Signer.getAddress();
|
||||
const sig = await web3Signer.signMessage(formatEthDmPublicKeyForSig(ethDmPublicKey))
|
||||
const sig = await web3Signer.signMessage(
|
||||
formatPublicKeyForSignature(ethDmPublicKey)
|
||||
);
|
||||
return { ethDmPublicKey, ethAddress, sig };
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the EthDm Public Key was signed by the holder of the given Ethereum address.
|
||||
*/
|
||||
export function verifyEthDmPublicKey(msg: EthDmPublicationMessage): boolean {
|
||||
export function verifyEthDmPublicKey(msg: PublicKeyMessage): boolean {
|
||||
try {
|
||||
const sigAddress = ethers.utils.verifyMessage(formatEthDmPublicKeyForSig(msg.ethDmPublicKey), msg.sig);
|
||||
return sigAddress == msg.ethAddress;
|
||||
}
|
||||
catch (e) {
|
||||
const sigAddress = ethers.utils.verifyMessage(
|
||||
formatPublicKeyForSignature(msg.ethDmPublicKey),
|
||||
msg.sig
|
||||
);
|
||||
return sigAddress === msg.ethAddress;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -57,8 +77,9 @@ export function verifyEthDmPublicKey(msg: EthDmPublicationMessage): boolean {
|
|||
* The usage of the object helps ensure the signature is only used in an Eth-DM
|
||||
* context.
|
||||
*/
|
||||
function formatEthDmPublicKeyForSig(ethDmPublicKey: string): string {
|
||||
return EthCrypto.hash.keccak256(JSON.stringify({
|
||||
ethDmPublicKey
|
||||
}))
|
||||
function formatPublicKeyForSignature(ethDmPublicKey: string): string {
|
||||
const txt = JSON.stringify({
|
||||
ethDmPublicKey,
|
||||
});
|
||||
return txt;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
|
@ -20,7 +16,5 @@
|
|||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
|
@ -4,4 +4,3 @@
|
|||
"sourceDirectory": "./contracts",
|
||||
"outputDirectory": "./contracts_build"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue