Prompt user to re-enter seed phrase during wallet creation and log out
This commit is contained in:
parent
afd9be9bc1
commit
ef996b5265
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import DialogForm from './DialogForm';
|
||||
import { forgetWallet } from '../utils/wallet-seed';
|
||||
import { forgetWallet, normalizeMnemonic, useUnlockedMnemonicAndSeed } from '../utils/wallet-seed';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import { DialogContentText } from '@material-ui/core';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
|
@ -8,7 +8,8 @@ import TextField from '@material-ui/core/TextField';
|
|||
import Button from '@material-ui/core/Button';
|
||||
|
||||
export default function DeleteMnemonicDialog({ open, onClose }) {
|
||||
const [deleteCheck, setDeleteCheck] = useState('');
|
||||
const [seedCheck, setSeedCheck] = useState('');
|
||||
const [mnemKey] = useUnlockedMnemonicAndSeed();
|
||||
return (
|
||||
<>
|
||||
<DialogForm
|
||||
|
@ -35,16 +36,17 @@ export default function DeleteMnemonicDialog({ open, onClose }) {
|
|||
<br />
|
||||
<strong>
|
||||
To prevent loss of funds, please ensure you have the seed phrase
|
||||
and the private key for all current accounts.
|
||||
and the private key for all current accounts. You can view it by selecting
|
||||
"Export Mnemonic" in the user menu.
|
||||
</strong>
|
||||
</div>
|
||||
<TextField
|
||||
label={`Please type "delete" to confirm`}
|
||||
label={`Please type your seed phrase to confirm`}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
value={deleteCheck}
|
||||
onChange={(e) => setDeleteCheck(e.target.value.trim())}
|
||||
value={seedCheck}
|
||||
onChange={(e) => setSeedCheck(e.target.value)}
|
||||
/>
|
||||
</DialogContentText>
|
||||
<DialogActions>
|
||||
|
@ -52,7 +54,7 @@ export default function DeleteMnemonicDialog({ open, onClose }) {
|
|||
<Button
|
||||
type="submit"
|
||||
color="secondary"
|
||||
disabled={deleteCheck !== 'delete'}
|
||||
disabled={normalizeMnemonic(seedCheck) !== mnemKey.mnemonic}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
loadMnemonicAndSeed,
|
||||
mnemonicToSeed,
|
||||
storeMnemonicAndSeed,
|
||||
normalizeMnemonic,
|
||||
} from '../utils/wallet-seed';
|
||||
import {
|
||||
getAccountFromSeed,
|
||||
|
@ -15,7 +16,7 @@ import LoadingIndicator from '../components/LoadingIndicator';
|
|||
import { BalanceListItem } from '../components/BalancesList.js';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { DialogActions, DialogContentText, DialogTitle, Typography } from '@material-ui/core';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
|
@ -27,6 +28,7 @@ import MenuItem from '@material-ui/core/MenuItem';
|
|||
import { useCallAsync } from '../utils/notifications';
|
||||
import Link from '@material-ui/core/Link';
|
||||
import { validateMnemonic } from 'bip39';
|
||||
import DialogForm from '../components/DialogForm';
|
||||
|
||||
export default function LoginPage() {
|
||||
const [restore, setRestore] = useState(false);
|
||||
|
@ -97,60 +99,100 @@ function CreateWalletForm() {
|
|||
|
||||
function SeedWordsForm({ mnemonicAndSeed, goForward }) {
|
||||
const [confirmed, setConfirmed] = useState(false);
|
||||
const [showDialog, setShowDialog] = useState(false);
|
||||
const [seedCheck, setSeedCheck] = useState('');
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Create New Wallet
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
Create a new wallet to hold Solana and SPL tokens.
|
||||
</Typography>
|
||||
<Typography>
|
||||
Please write down the following twenty four words and keep them in a
|
||||
safe place:
|
||||
</Typography>
|
||||
{mnemonicAndSeed ? (
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
margin="normal"
|
||||
value={mnemonicAndSeed.mnemonic}
|
||||
label="Seed Words"
|
||||
onFocus={(e) => e.currentTarget.select()}
|
||||
/>
|
||||
) : (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
<Typography paragraph>
|
||||
Your private keys are only stored on your current computer or device.
|
||||
You will need these words to restore your wallet if your browser's
|
||||
storage is cleared or your device is damaged or lost.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
By default, sollet will use <code>m/44'/501'/0'/0'</code> as the
|
||||
derivation path for the main wallet. To use an alternative path, try
|
||||
restoring an existing wallet.
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={confirmed}
|
||||
disabled={!mnemonicAndSeed}
|
||||
onChange={(e) => setConfirmed(e.target.checked)}
|
||||
<>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Create New Wallet
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
Create a new wallet to hold Solana and SPL tokens.
|
||||
</Typography>
|
||||
<Typography>
|
||||
Please write down the following twenty four words and keep them in a
|
||||
safe place:
|
||||
</Typography>
|
||||
{mnemonicAndSeed ? (
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
margin="normal"
|
||||
value={mnemonicAndSeed.mnemonic}
|
||||
label="Seed Words"
|
||||
onFocus={(e) => e.currentTarget.select()}
|
||||
/>
|
||||
}
|
||||
label="I have saved these words in a safe place."
|
||||
/>
|
||||
</CardContent>
|
||||
<CardActions style={{ justifyContent: 'flex-end' }}>
|
||||
<Button color="primary" disabled={!confirmed} onClick={goForward}>
|
||||
Continue
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
) : (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
<Typography paragraph>
|
||||
Your private keys are only stored on your current computer or device.
|
||||
You will need these words to restore your wallet if your browser's
|
||||
storage is cleared or your device is damaged or lost.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
By default, sollet will use <code>m/44'/501'/0'/0'</code> as the
|
||||
derivation path for the main wallet. To use an alternative path, try
|
||||
restoring an existing wallet.
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={confirmed}
|
||||
disabled={!mnemonicAndSeed}
|
||||
onChange={(e) => setConfirmed(e.target.checked)}
|
||||
/>
|
||||
}
|
||||
label="I have saved these words in a safe place."
|
||||
/>
|
||||
</CardContent>
|
||||
<CardActions style={{ justifyContent: 'flex-end' }}>
|
||||
<Button color="primary" disabled={!confirmed} onClick={() => setShowDialog(true)}>
|
||||
Continue
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
<DialogForm
|
||||
open={showDialog}
|
||||
onClose={() => setShowDialog(false)}
|
||||
onSubmit={goForward}
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle>{'Confirm Mnemonic'}</DialogTitle>
|
||||
<DialogContentText style={{ margin: 20 }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
Please re-enter your seed phrase to confirm that you have saved it.
|
||||
</div>
|
||||
<TextField
|
||||
label={`Please type your seed phrase to confirm`}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
value={seedCheck}
|
||||
onChange={(e) => setSeedCheck(e.target.value)}
|
||||
/>
|
||||
</DialogContentText>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setShowDialog(false)}>Close</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
color="secondary"
|
||||
disabled={normalizeMnemonic(seedCheck) !== mnemonicAndSeed?.mnemonic}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogForm>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -264,11 +306,13 @@ function LoginForm() {
|
|||
}
|
||||
|
||||
function RestoreWalletForm({ goBack }) {
|
||||
const [mnemonic, setMnemonic] = useState('');
|
||||
const [rawMnemonic, setRawMnemonic] = useState('');
|
||||
const [seed, setSeed] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [passwordConfirm, setPasswordConfirm] = useState('');
|
||||
const [next, setNext] = useState(false);
|
||||
|
||||
const mnemonic = normalizeMnemonic(rawMnemonic);
|
||||
const isNextBtnEnabled =
|
||||
password === passwordConfirm && validateMnemonic(mnemonic);
|
||||
|
||||
|
@ -303,8 +347,8 @@ function RestoreWalletForm({ goBack }) {
|
|||
rows={3}
|
||||
margin="normal"
|
||||
label="Seed Words"
|
||||
value={mnemonic}
|
||||
onChange={(e) => setMnemonic(e.target.value)}
|
||||
value={rawMnemonic}
|
||||
onChange={(e) => setRawMnemonic(e.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
|
|
|
@ -6,6 +6,10 @@ import { EventEmitter } from 'events';
|
|||
import { isExtension } from './utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function normalizeMnemonic(mnemonic) {
|
||||
return mnemonic.trim().split(/\s+/g).join(" ");
|
||||
}
|
||||
|
||||
export async function generateMnemonicAndSeed() {
|
||||
const bip39 = await import('bip39');
|
||||
const mnemonic = bip39.generateMnemonic(256);
|
||||
|
|
Loading…
Reference in New Issue