mirror of
https://github.com/status-im/js-waku.git
synced 2025-02-23 02:18:25 +00:00
Merge pull request #263 from status-im/eth-dm-cleanup-for-metamask
This commit is contained in:
commit
85fd5f8f9f
@ -3,7 +3,6 @@ import '@ethersproject/shims';
|
|||||||
import React, { useEffect, useState } from 'react';
|
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 { Signer } from '@ethersproject/abstract-signer';
|
import { Signer } from '@ethersproject/abstract-signer';
|
||||||
import { KeyPair } from './crypto';
|
import { KeyPair } from './crypto';
|
||||||
import { Message } from './messaging/Messages';
|
import { Message } from './messaging/Messages';
|
||||||
@ -26,8 +25,7 @@ import {
|
|||||||
initWaku,
|
initWaku,
|
||||||
PublicKeyContentTopic,
|
PublicKeyContentTopic,
|
||||||
} from './waku';
|
} from './waku';
|
||||||
|
import ConnectWallet from './ConnectWallet';
|
||||||
declare let window: any;
|
|
||||||
|
|
||||||
const theme = createMuiTheme({
|
const theme = createMuiTheme({
|
||||||
palette: {
|
palette: {
|
||||||
@ -70,27 +68,17 @@ const useStyles = makeStyles({
|
|||||||
function App() {
|
function App() {
|
||||||
const [waku, setWaku] = useState<Waku>();
|
const [waku, setWaku] = useState<Waku>();
|
||||||
const [signer, setSigner] = useState<Signer>();
|
const [signer, setSigner] = useState<Signer>();
|
||||||
const [ethDmKeyPair, setEthDmKeyPair] = useState<KeyPair | undefined>();
|
const [EncryptionKeyPair, setEncryptionKeyPair] = useState<
|
||||||
const [publicKeys, setPublicKeys] = useState<Map<string, string>>(new Map());
|
KeyPair | undefined
|
||||||
|
>();
|
||||||
|
const [publicKeys, setPublicKeys] = useState<Map<string, Uint8Array>>(
|
||||||
|
new Map()
|
||||||
|
);
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
const [address, setAddress] = useState<string>();
|
const [address, setAddress] = useState<string>();
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
try {
|
|
||||||
window.ethereum
|
|
||||||
.request({ method: 'eth_requestAccounts' })
|
|
||||||
.then((accounts: string[]) => {
|
|
||||||
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
|
||||||
setAddress(accounts[0]);
|
|
||||||
setSigner(_provider.getSigner());
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error('No web3 provider available');
|
|
||||||
}
|
|
||||||
}, [address, signer]);
|
|
||||||
|
|
||||||
// Waku initialization
|
// Waku initialization
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (waku) return;
|
if (waku) return;
|
||||||
@ -106,7 +94,6 @@ function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!address) return;
|
|
||||||
|
|
||||||
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
|
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
|
||||||
{},
|
{},
|
||||||
@ -126,27 +113,26 @@ function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!ethDmKeyPair) return;
|
if (!EncryptionKeyPair) return;
|
||||||
|
|
||||||
waku.relay.addDecryptionKey(ethDmKeyPair.privateKey);
|
waku.relay.addDecryptionKey(EncryptionKeyPair.privateKey);
|
||||||
|
|
||||||
return function cleanUp() {
|
return function cleanUp() {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!ethDmKeyPair) return;
|
if (!EncryptionKeyPair) return;
|
||||||
|
|
||||||
waku.relay.deleteDecryptionKey(ethDmKeyPair.privateKey);
|
waku.relay.deleteDecryptionKey(EncryptionKeyPair.privateKey);
|
||||||
};
|
};
|
||||||
}, [waku, ethDmKeyPair]);
|
}, [waku, EncryptionKeyPair]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
if (!ethDmKeyPair) return;
|
if (!EncryptionKeyPair) return;
|
||||||
if (!address) return;
|
if (!address) return;
|
||||||
|
|
||||||
const observerDirectMessage = handleDirectMessage.bind(
|
const observerDirectMessage = handleDirectMessage.bind(
|
||||||
{},
|
{},
|
||||||
setMessages,
|
setMessages,
|
||||||
ethDmKeyPair.privateKey,
|
|
||||||
address
|
address
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -159,7 +145,7 @@ function App() {
|
|||||||
DirectMessageContentTopic,
|
DirectMessageContentTopic,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
}, [waku, address, ethDmKeyPair]);
|
}, [waku, address, EncryptionKeyPair]);
|
||||||
|
|
||||||
let relayPeers = 0;
|
let relayPeers = 0;
|
||||||
let lightPushPeers = 0;
|
let lightPushPeers = 0;
|
||||||
@ -202,14 +188,18 @@ function App() {
|
|||||||
<div className={classes.container}>
|
<div className={classes.container}>
|
||||||
<main className={classes.main}>
|
<main className={classes.main}>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Eth-DM Key Pair</legend>
|
<legend>Wallet</legend>
|
||||||
|
<ConnectWallet setAddress={setAddress} setSigner={setSigner} />
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Encryption Key Pair</legend>
|
||||||
<KeyPairHandling
|
<KeyPairHandling
|
||||||
ethDmKeyPair={ethDmKeyPair}
|
encryptionKeyPair={EncryptionKeyPair}
|
||||||
setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)}
|
setEncryptionKeyPair={setEncryptionKeyPair}
|
||||||
/>
|
/>
|
||||||
<BroadcastPublicKey
|
<BroadcastPublicKey
|
||||||
signer={signer}
|
signer={signer}
|
||||||
ethDmKeyPair={ethDmKeyPair}
|
EncryptionKeyPair={EncryptionKeyPair}
|
||||||
waku={waku}
|
waku={waku}
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -7,20 +7,20 @@ import { Signer } from '@ethersproject/abstract-signer';
|
|||||||
import { PublicKeyContentTopic } from './waku';
|
import { PublicKeyContentTopic } from './waku';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
ethDmKeyPair: KeyPair | undefined;
|
EncryptionKeyPair: KeyPair | undefined;
|
||||||
waku: Waku | undefined;
|
waku: Waku | undefined;
|
||||||
signer: Signer | undefined;
|
signer: Signer | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BroadcastPublicKey({
|
export default function BroadcastPublicKey({
|
||||||
signer,
|
signer,
|
||||||
ethDmKeyPair,
|
EncryptionKeyPair,
|
||||||
waku,
|
waku,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [publicKeyMsg, setPublicKeyMsg] = useState<PublicKeyMessage>();
|
const [publicKeyMsg, setPublicKeyMsg] = useState<PublicKeyMessage>();
|
||||||
|
|
||||||
const broadcastPublicKey = () => {
|
const broadcastPublicKey = () => {
|
||||||
if (!ethDmKeyPair) return;
|
if (!EncryptionKeyPair) return;
|
||||||
if (!signer) return;
|
if (!signer) return;
|
||||||
if (!waku) return;
|
if (!waku) return;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export default function BroadcastPublicKey({
|
|||||||
console.log('Failed to encode Public Key Message in Waku Message');
|
console.log('Failed to encode Public Key Message in Waku Message');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
createPublicKeyMessage(signer, ethDmKeyPair.publicKey)
|
createPublicKeyMessage(signer, EncryptionKeyPair.publicKey)
|
||||||
.then((msg) => {
|
.then((msg) => {
|
||||||
setPublicKeyMsg(msg);
|
setPublicKeyMsg(msg);
|
||||||
encodePublicKeyWakuMessage(msg)
|
encodePublicKeyWakuMessage(msg)
|
||||||
@ -64,9 +64,9 @@ export default function BroadcastPublicKey({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={broadcastPublicKey}
|
onClick={broadcastPublicKey}
|
||||||
disabled={!ethDmKeyPair || !waku}
|
disabled={!EncryptionKeyPair || !waku}
|
||||||
>
|
>
|
||||||
Broadcast Eth-DM Public Key
|
Broadcast Encryption Public Key
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
33
examples/eth-dm/src/ConnectWallet.tsx
Normal file
33
examples/eth-dm/src/ConnectWallet.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Button } from '@material-ui/core';
|
||||||
|
import React from 'react';
|
||||||
|
import { Signer } from '@ethersproject/abstract-signer';
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
|
||||||
|
declare let window: any;
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
setAddress: (address: string) => void;
|
||||||
|
setSigner: (signer: Signer) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ConnectWallet({ setAddress, setSigner }: Props) {
|
||||||
|
const connectWallet = () => {
|
||||||
|
try {
|
||||||
|
window.ethereum
|
||||||
|
.request({ method: 'eth_requestAccounts' })
|
||||||
|
.then((accounts: string[]) => {
|
||||||
|
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||||
|
setAddress(accounts[0]);
|
||||||
|
setSigner(_provider.getSigner());
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('No web3 provider available');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button variant="contained" color="primary" onClick={connectWallet}>
|
||||||
|
Connect Wallet
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
@ -16,7 +16,7 @@ export interface KeyPair {
|
|||||||
* the entropy for the EthCrypto keypair. Note that the entropy is hashed with keccak256
|
* the entropy for the EthCrypto keypair. Note that the entropy is hashed with keccak256
|
||||||
* to make the private key.
|
* to make the private key.
|
||||||
*/
|
*/
|
||||||
export async function generateEthDmKeyPair(): Promise<KeyPair> {
|
export async function generateEncryptionKeyPair(): Promise<KeyPair> {
|
||||||
const privateKey = generatePrivateKey();
|
const privateKey = generatePrivateKey();
|
||||||
const publicKey = getPublicKey(privateKey);
|
const publicKey = getPublicKey(privateKey);
|
||||||
return { privateKey, publicKey };
|
return { privateKey, publicKey };
|
||||||
@ -29,25 +29,25 @@ export async function generateEthDmKeyPair(): Promise<KeyPair> {
|
|||||||
*/
|
*/
|
||||||
export async function createPublicKeyMessage(
|
export async function createPublicKeyMessage(
|
||||||
web3Signer: Signer,
|
web3Signer: Signer,
|
||||||
ethDmPublicKey: Uint8Array
|
encryptionPublicKey: Uint8Array
|
||||||
): Promise<PublicKeyMessage> {
|
): Promise<PublicKeyMessage> {
|
||||||
const ethAddress = await web3Signer.getAddress();
|
const ethAddress = await web3Signer.getAddress();
|
||||||
const signature = await web3Signer.signMessage(
|
const signature = await web3Signer.signMessage(
|
||||||
formatPublicKeyForSignature(ethDmPublicKey)
|
formatPublicKeyForSignature(encryptionPublicKey)
|
||||||
);
|
);
|
||||||
|
|
||||||
return new PublicKeyMessage({
|
return new PublicKeyMessage({
|
||||||
ethDmPublicKey: ethDmPublicKey,
|
encryptionPublicKey: encryptionPublicKey,
|
||||||
ethAddress: hexToBuf(ethAddress),
|
ethAddress: hexToBuf(ethAddress),
|
||||||
signature: hexToBuf(signature),
|
signature: hexToBuf(signature),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate that the EthDm 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 formattedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey);
|
const formattedMsg = formatPublicKeyForSignature(msg.encryptionPublicKey);
|
||||||
try {
|
try {
|
||||||
const sigAddress = ethers.utils.verifyMessage(formattedMsg, msg.signature);
|
const sigAddress = ethers.utils.verifyMessage(formattedMsg, msg.signature);
|
||||||
return equalByteArrays(sigAddress, msg.ethAddress);
|
return equalByteArrays(sigAddress, msg.ethAddress);
|
||||||
@ -63,13 +63,13 @@ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare Eth-Dm Public key to be signed for publication.
|
* Prepare Eth-Dm Public key to be signed for publication.
|
||||||
* The public key is set in on Object `{ ethDmPublicKey: string; }`, converted
|
* The public key is set in on Object `{ encryptionPublicKey: string; }`, converted
|
||||||
* to JSON and then hashed with Keccak256.
|
* to JSON and then hashed with Keccak256.
|
||||||
* The usage of the object helps ensure the signature is only used in an Eth-DM
|
* The usage of the object helps ensure the signature is only used in an Eth-DM
|
||||||
* context.
|
* context.
|
||||||
*/
|
*/
|
||||||
function formatPublicKeyForSignature(ethDmPublicKey: Uint8Array): string {
|
function formatPublicKeyForSignature(encryptionPublicKey: Uint8Array): string {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
ethDmPublicKey: bufToHex(ethDmPublicKey),
|
encryptionPublicKey: bufToHex(encryptionPublicKey),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Button } from '@material-ui/core';
|
|||||||
import { LoadKeyPair } from './LoadKeyPair';
|
import { LoadKeyPair } from './LoadKeyPair';
|
||||||
import { SaveKeyPair } from './SaveKeyPair';
|
import { SaveKeyPair } from './SaveKeyPair';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { generateEthDmKeyPair, KeyPair } from '../crypto';
|
import { generateEncryptionKeyPair, KeyPair } from '../crypto';
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
import PasswordInput from './PasswordInput';
|
import PasswordInput from './PasswordInput';
|
||||||
|
|
||||||
@ -29,24 +29,24 @@ const useStyles = makeStyles({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
ethDmKeyPair: KeyPair | undefined;
|
encryptionKeyPair: KeyPair | undefined;
|
||||||
setEthDmKeyPair: (keyPair: KeyPair) => void;
|
setEncryptionKeyPair: (keyPair: KeyPair) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function KeyPairHandling({
|
export default function KeyPairHandling({
|
||||||
ethDmKeyPair,
|
encryptionKeyPair,
|
||||||
setEthDmKeyPair,
|
setEncryptionKeyPair,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const [password, setPassword] = useState<string>();
|
const [password, setPassword] = useState<string>();
|
||||||
|
|
||||||
const generateKeyPair = () => {
|
const generateKeyPair = () => {
|
||||||
if (ethDmKeyPair) return;
|
if (encryptionKeyPair) return;
|
||||||
|
|
||||||
generateEthDmKeyPair()
|
generateEncryptionKeyPair()
|
||||||
.then((keyPair) => {
|
.then((keyPair) => {
|
||||||
setEthDmKeyPair(keyPair);
|
setEncryptionKeyPair(keyPair);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error('Failed to generate Key Pair', e);
|
console.error('Failed to generate Key Pair', e);
|
||||||
@ -60,9 +60,9 @@ export default function KeyPairHandling({
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={generateKeyPair}
|
onClick={generateKeyPair}
|
||||||
disabled={!!ethDmKeyPair}
|
disabled={!!encryptionKeyPair}
|
||||||
>
|
>
|
||||||
Generate Eth-DM Key Pair
|
Generate Encryption Key Pair
|
||||||
</Button>
|
</Button>
|
||||||
<div className={classes.storage}>
|
<div className={classes.storage}>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
@ -72,13 +72,16 @@ export default function KeyPairHandling({
|
|||||||
<div className={classes.loadSave}>
|
<div className={classes.loadSave}>
|
||||||
<div className={classes.loadSaveButton}>
|
<div className={classes.loadSaveButton}>
|
||||||
<LoadKeyPair
|
<LoadKeyPair
|
||||||
setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)}
|
setEncryptionKeyPair={(keyPair) => setEncryptionKeyPair(keyPair)}
|
||||||
disabled={!!ethDmKeyPair}
|
disabled={!!encryptionKeyPair}
|
||||||
password={password}
|
password={password}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.loadSaveButton}>
|
<div className={classes.loadSaveButton}>
|
||||||
<SaveKeyPair ethDmKeyPair={ethDmKeyPair} password={password} />
|
<SaveKeyPair
|
||||||
|
EncryptionKeyPair={encryptionKeyPair}
|
||||||
|
password={password}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,19 +4,23 @@ import { loadKeyPairFromStorage } from './key_pair_storage';
|
|||||||
import { KeyPair } from '../crypto';
|
import { KeyPair } from '../crypto';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
setEthDmKeyPair: (keyPair: KeyPair) => void;
|
setEncryptionKeyPair: (keyPair: KeyPair) => void;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
password: string | undefined;
|
password: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LoadKeyPair({ password, disabled, setEthDmKeyPair }: Props) {
|
export function LoadKeyPair({
|
||||||
|
password,
|
||||||
|
disabled,
|
||||||
|
setEncryptionKeyPair,
|
||||||
|
}: Props) {
|
||||||
const loadKeyPair = () => {
|
const loadKeyPair = () => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
if (!password) return;
|
if (!password) return;
|
||||||
loadKeyPairFromStorage(password).then((keyPair: KeyPair | undefined) => {
|
loadKeyPairFromStorage(password).then((keyPair: KeyPair | undefined) => {
|
||||||
if (!keyPair) return;
|
if (!keyPair) return;
|
||||||
console.log('EthDm KeyPair loaded from storage');
|
console.log('Encryption KeyPair loaded from storage');
|
||||||
setEthDmKeyPair(keyPair);
|
setEncryptionKeyPair(keyPair);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,7 +31,7 @@ export function LoadKeyPair({ password, disabled, setEthDmKeyPair }: Props) {
|
|||||||
onClick={loadKeyPair}
|
onClick={loadKeyPair}
|
||||||
disabled={!password || disabled}
|
disabled={!password || disabled}
|
||||||
>
|
>
|
||||||
Load Eth-DM Key Pair from storage
|
Load Encryption Key Pair from storage
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,16 @@ import { KeyPair } from '../crypto';
|
|||||||
import { saveKeyPairToStorage } from './key_pair_storage';
|
import { saveKeyPairToStorage } from './key_pair_storage';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
ethDmKeyPair: KeyPair | undefined;
|
EncryptionKeyPair: KeyPair | undefined;
|
||||||
password: string | undefined;
|
password: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SaveKeyPair({ password, ethDmKeyPair }: Props) {
|
export function SaveKeyPair({ password, EncryptionKeyPair }: Props) {
|
||||||
const saveKeyPair = () => {
|
const saveKeyPair = () => {
|
||||||
if (!ethDmKeyPair) return;
|
if (!EncryptionKeyPair) return;
|
||||||
if (!password) return;
|
if (!password) return;
|
||||||
saveKeyPairToStorage(ethDmKeyPair, password).then(() => {
|
saveKeyPairToStorage(EncryptionKeyPair, password).then(() => {
|
||||||
console.log('EthDm KeyPair saved to storage');
|
console.log('Encryption KeyPair saved to storage');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -22,9 +22,9 @@ export function SaveKeyPair({ password, ethDmKeyPair }: Props) {
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={saveKeyPair}
|
onClick={saveKeyPair}
|
||||||
disabled={!password || !ethDmKeyPair}
|
disabled={!password || !EncryptionKeyPair}
|
||||||
>
|
>
|
||||||
Save Eth-DM Key Pair to storage
|
Save Encryption Key Pair to storage
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@ import { bufToHex, hexToBuf } from 'js-waku/lib/utils';
|
|||||||
* Save keypair to storage, encrypted with password
|
* Save keypair to storage, encrypted with password
|
||||||
*/
|
*/
|
||||||
export async function saveKeyPairToStorage(
|
export async function saveKeyPairToStorage(
|
||||||
ethDmKeyPair: KeyPair,
|
EncryptionKeyPair: KeyPair,
|
||||||
password: string
|
password: string
|
||||||
) {
|
) {
|
||||||
const { salt, iv, cipher } = await encryptKey(ethDmKeyPair, password);
|
const { salt, iv, cipher } = await encryptKey(EncryptionKeyPair, password);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
salt: bufToHex(salt),
|
salt: bufToHex(salt),
|
||||||
@ -16,7 +16,7 @@ export async function saveKeyPairToStorage(
|
|||||||
cipher: bufToHex(cipher),
|
cipher: bufToHex(cipher),
|
||||||
};
|
};
|
||||||
|
|
||||||
localStorage.setItem('cipherEthDmKeyPair', JSON.stringify(data));
|
localStorage.setItem('cipherEncryptionKeyPair', JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +25,7 @@ export async function saveKeyPairToStorage(
|
|||||||
export async function loadKeyPairFromStorage(
|
export async function loadKeyPairFromStorage(
|
||||||
password: string
|
password: string
|
||||||
): Promise<KeyPair | undefined> {
|
): Promise<KeyPair | undefined> {
|
||||||
const str = localStorage.getItem('cipherEthDmKeyPair');
|
const str = localStorage.getItem('cipherEncryptionKeyPair');
|
||||||
if (!str) return;
|
if (!str) return;
|
||||||
const data = JSON.parse(str);
|
const data = JSON.parse(str);
|
||||||
|
|
||||||
@ -71,13 +71,13 @@ function getWrapKey(keyMaterial: CryptoKey, salt: Uint8Array) {
|
|||||||
/**
|
/**
|
||||||
* Encrypt Eth-DM KeyPair using provided password
|
* Encrypt Eth-DM KeyPair using provided password
|
||||||
*/
|
*/
|
||||||
async function encryptKey(ethDmKeyPair: KeyPair, password: string) {
|
async function encryptKey(encryptionKeyPair: KeyPair, password: string) {
|
||||||
const keyMaterial = await getKeyMaterial(password);
|
const keyMaterial = await getKeyMaterial(password);
|
||||||
const salt = window.crypto.getRandomValues(new Uint8Array(16));
|
const salt = window.crypto.getRandomValues(new Uint8Array(16));
|
||||||
const wrappingKey = await getWrapKey(keyMaterial, salt);
|
const wrappingKey = await getWrapKey(keyMaterial, salt);
|
||||||
|
|
||||||
const enc = new TextEncoder();
|
const enc = new TextEncoder();
|
||||||
const encodedKeyPair = enc.encode(JSON.stringify(ethDmKeyPair));
|
const encodedKeyPair = enc.encode(JSON.stringify(encryptionKeyPair));
|
||||||
|
|
||||||
const iv = window.crypto.getRandomValues(new Uint8Array(12));
|
const iv = window.crypto.getRandomValues(new Uint8Array(12));
|
||||||
const cipher = await window.crypto.subtle.encrypt(
|
const cipher = await window.crypto.subtle.encrypt(
|
||||||
|
@ -14,7 +14,7 @@ const useStyles = makeStyles({
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
waku: Waku | undefined;
|
waku: Waku | undefined;
|
||||||
recipients: Map<string, string>;
|
recipients: Map<string, Uint8Array>;
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
waku: Waku | undefined;
|
waku: Waku | undefined;
|
||||||
// address, public key
|
// address, public key
|
||||||
recipients: Map<string, string>;
|
recipients: Map<string, Uint8Array>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SendMessage({ waku, recipients }: Props) {
|
export default function SendMessage({ waku, recipients }: Props) {
|
||||||
@ -106,7 +106,7 @@ export default function SendMessage({ waku, recipients }: Props) {
|
|||||||
|
|
||||||
async function encodeEncryptedWakuMessage(
|
async function encodeEncryptedWakuMessage(
|
||||||
message: string,
|
message: string,
|
||||||
publicKey: string,
|
publicKey: Uint8Array,
|
||||||
address: string
|
address: string
|
||||||
): Promise<WakuMessage> {
|
): Promise<WakuMessage> {
|
||||||
const directMsg = new DirectMessage({
|
const directMsg = new DirectMessage({
|
||||||
@ -123,7 +123,7 @@ async function encodeEncryptedWakuMessage(
|
|||||||
function sendMessage(
|
function sendMessage(
|
||||||
waku: Waku,
|
waku: Waku,
|
||||||
recipientAddress: string,
|
recipientAddress: string,
|
||||||
recipientPublicKey: string,
|
recipientPublicKey: Uint8Array,
|
||||||
message: string,
|
message: string,
|
||||||
callback: (res: boolean) => void
|
callback: (res: boolean) => void
|
||||||
) {
|
) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as protobuf from 'protobufjs/light';
|
import * as protobuf from 'protobufjs/light';
|
||||||
|
|
||||||
export interface PublicKeyMessagePayload {
|
export interface PublicKeyMessagePayload {
|
||||||
ethDmPublicKey: Uint8Array;
|
encryptionPublicKey: Uint8Array;
|
||||||
ethAddress: Uint8Array;
|
ethAddress: Uint8Array;
|
||||||
signature: Uint8Array;
|
signature: Uint8Array;
|
||||||
}
|
}
|
||||||
@ -15,7 +15,7 @@ const Root = protobuf.Root,
|
|||||||
*/
|
*/
|
||||||
export class PublicKeyMessage {
|
export class PublicKeyMessage {
|
||||||
private static Type = new Type('PublicKeyMessage')
|
private static Type = new Type('PublicKeyMessage')
|
||||||
.add(new Field('ethDmPublicKey', 1, 'bytes'))
|
.add(new Field('encryptionPublicKey', 1, 'bytes'))
|
||||||
.add(new Field('ethAddress', 2, 'bytes'))
|
.add(new Field('ethAddress', 2, 'bytes'))
|
||||||
.add(new Field('signature', 3, 'bytes'));
|
.add(new Field('signature', 3, 'bytes'));
|
||||||
private static Root = new Root()
|
private static Root = new Root()
|
||||||
@ -35,15 +35,19 @@ export class PublicKeyMessage {
|
|||||||
const payload = PublicKeyMessage.Type.decode(
|
const payload = PublicKeyMessage.Type.decode(
|
||||||
bytes
|
bytes
|
||||||
) as unknown as PublicKeyMessagePayload;
|
) as unknown as PublicKeyMessagePayload;
|
||||||
if (!payload.signature || !payload.ethDmPublicKey || !payload.ethAddress) {
|
if (
|
||||||
|
!payload.signature ||
|
||||||
|
!payload.encryptionPublicKey ||
|
||||||
|
!payload.ethAddress
|
||||||
|
) {
|
||||||
console.log('Field missing on decoded Public Key Message', payload);
|
console.log('Field missing on decoded Public Key Message', payload);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return new PublicKeyMessage(payload);
|
return new PublicKeyMessage(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
get ethDmPublicKey(): Uint8Array {
|
get encryptionPublicKey(): Uint8Array {
|
||||||
return this.payload.ethDmPublicKey;
|
return this.payload.encryptionPublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
get ethAddress(): Uint8Array {
|
get ethAddress(): Uint8Array {
|
||||||
|
@ -33,24 +33,25 @@ export async function initWaku(): Promise<Waku> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function handlePublicKeyMessage(
|
export function handlePublicKeyMessage(
|
||||||
myAddress: string,
|
myAddress: string | undefined,
|
||||||
setter: Dispatch<SetStateAction<Map<string, string>>>,
|
setter: Dispatch<SetStateAction<Map<string, Uint8Array>>>,
|
||||||
msg: WakuMessage
|
msg: WakuMessage
|
||||||
) {
|
) {
|
||||||
console.log('Public Key Message received:', msg);
|
console.log('Public Key Message received:', msg);
|
||||||
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 = bufToHex(publicKeyMsg.ethDmPublicKey);
|
|
||||||
console.log(ethDmPublicKey, myAddress);
|
|
||||||
if (myAddress && equalByteArrays(publicKeyMsg.ethAddress, myAddress)) return;
|
if (myAddress && equalByteArrays(publicKeyMsg.ethAddress, myAddress)) return;
|
||||||
|
|
||||||
const res = validatePublicKeyMessage(publicKeyMsg);
|
const res = validatePublicKeyMessage(publicKeyMsg);
|
||||||
console.log('Is Public Key Message valid?', res);
|
console.log('Is Public Key Message valid?', res);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
setter((prevPks: Map<string, string>) => {
|
setter((prevPks: Map<string, Uint8Array>) => {
|
||||||
prevPks.set(bufToHex(publicKeyMsg.ethAddress), ethDmPublicKey);
|
prevPks.set(
|
||||||
|
bufToHex(publicKeyMsg.ethAddress),
|
||||||
|
publicKeyMsg.encryptionPublicKey
|
||||||
|
);
|
||||||
return new Map(prevPks);
|
return new Map(prevPks);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -58,7 +59,6 @@ export function handlePublicKeyMessage(
|
|||||||
|
|
||||||
export async function handleDirectMessage(
|
export async function handleDirectMessage(
|
||||||
setter: Dispatch<SetStateAction<Message[]>>,
|
setter: Dispatch<SetStateAction<Message[]>>,
|
||||||
privateKey: Uint8Array,
|
|
||||||
address: string,
|
address: string,
|
||||||
wakuMsg: WakuMessage
|
wakuMsg: WakuMessage
|
||||||
) {
|
) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user