mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 09:23:21 +01:00
Use new design for reveal seed screen. Persist seed words only in first time flow
This commit is contained in:
parent
477b74124d
commit
3082d2e4ef
@ -98,6 +98,9 @@
|
|||||||
"clickCopy": {
|
"clickCopy": {
|
||||||
"message": "Click to Copy"
|
"message": "Click to Copy"
|
||||||
},
|
},
|
||||||
|
"close": {
|
||||||
|
"message": "Close"
|
||||||
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"message": "Confirm"
|
"message": "Confirm"
|
||||||
},
|
},
|
||||||
@ -259,6 +262,9 @@
|
|||||||
"enterPasswordConfirm": {
|
"enterPasswordConfirm": {
|
||||||
"message": "Enter your password to confirm"
|
"message": "Enter your password to confirm"
|
||||||
},
|
},
|
||||||
|
"enterPasswordContinue": {
|
||||||
|
"message": "Enter password to continue"
|
||||||
|
},
|
||||||
"passwordNotLongEnough": {
|
"passwordNotLongEnough": {
|
||||||
"message": "Password not long enough"
|
"message": "Password not long enough"
|
||||||
},
|
},
|
||||||
@ -331,6 +337,9 @@
|
|||||||
"gasPriceRequired": {
|
"gasPriceRequired": {
|
||||||
"message": "Gas Price Required"
|
"message": "Gas Price Required"
|
||||||
},
|
},
|
||||||
|
"generatingTransaction": {
|
||||||
|
"message": "Generating transaction"
|
||||||
|
},
|
||||||
"getEther": {
|
"getEther": {
|
||||||
"message": "Get Ether"
|
"message": "Get Ether"
|
||||||
},
|
},
|
||||||
@ -476,6 +485,9 @@
|
|||||||
"metamaskDescription": {
|
"metamaskDescription": {
|
||||||
"message": "MetaMask is a secure identity vault for Ethereum."
|
"message": "MetaMask is a secure identity vault for Ethereum."
|
||||||
},
|
},
|
||||||
|
"metamaskSeedWords": {
|
||||||
|
"message": "MetaMask Seed Words"
|
||||||
|
},
|
||||||
"min": {
|
"min": {
|
||||||
"message": "Minimum"
|
"message": "Minimum"
|
||||||
},
|
},
|
||||||
@ -549,6 +561,9 @@
|
|||||||
"message": "or",
|
"message": "or",
|
||||||
"description": "choice between creating or importing a new account"
|
"description": "choice between creating or importing a new account"
|
||||||
},
|
},
|
||||||
|
"password": {
|
||||||
|
"message": "Password"
|
||||||
|
},
|
||||||
"passwordCorrect": {
|
"passwordCorrect": {
|
||||||
"message": "Please make sure your password is correct."
|
"message": "Please make sure your password is correct."
|
||||||
},
|
},
|
||||||
@ -634,8 +649,17 @@
|
|||||||
"revealSeedWords": {
|
"revealSeedWords": {
|
||||||
"message": "Reveal Seed Words"
|
"message": "Reveal Seed Words"
|
||||||
},
|
},
|
||||||
|
"revealSeedWordsTitle": {
|
||||||
|
"message": "Seed Phrase"
|
||||||
|
},
|
||||||
|
"revealSeedWordsDescription": {
|
||||||
|
"message": "If you ever change browsers or move computers, you will need this seed phrase to access your accounts. Save them somewhere safe and secret."
|
||||||
|
},
|
||||||
|
"revealSeedWordsWarningTitle": {
|
||||||
|
"message": "DO NOT share this phrase with anyone!"
|
||||||
|
},
|
||||||
"revealSeedWordsWarning": {
|
"revealSeedWordsWarning": {
|
||||||
"message": "Do not recover your seed words in a public place! These words can be used to steal all your accounts."
|
"message": "These words can be used to steal all your accounts."
|
||||||
},
|
},
|
||||||
"revert": {
|
"revert": {
|
||||||
"message": "Revert"
|
"message": "Revert"
|
||||||
@ -677,6 +701,9 @@
|
|||||||
"reprice_subtitle": {
|
"reprice_subtitle": {
|
||||||
"message": "Increase your gas price to attempt to overwrite and speed up your transaction"
|
"message": "Increase your gas price to attempt to overwrite and speed up your transaction"
|
||||||
},
|
},
|
||||||
|
"saveAsCsvFile": {
|
||||||
|
"message": "Save as CSV File"
|
||||||
|
},
|
||||||
"saveAsFile": {
|
"saveAsFile": {
|
||||||
"message": "Save as File",
|
"message": "Save as File",
|
||||||
"description": "Account export process"
|
"description": "Account export process"
|
||||||
@ -909,7 +936,7 @@
|
|||||||
"youSign": {
|
"youSign": {
|
||||||
"message": "You are signing"
|
"message": "You are signing"
|
||||||
},
|
},
|
||||||
"generatingTransaction": {
|
"yourPrivateSeedPhrase": {
|
||||||
"message": "Generating transaction"
|
"message": "Your private seed phrase"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
app/images/copy-to-clipboard.svg
Normal file
24
app/images/copy-to-clipboard.svg
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="18px" height="17px" viewBox="0 0 18 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: sketchtool 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>374E58A5-C29E-4921-83E7-889FA06D6408</title>
|
||||||
|
<desc>Created with sketchtool.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="Reveal-Seedphrase" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Seed-phrase-2" transform="translate(-39.000000, -379.000000)">
|
||||||
|
<g id="Group-2">
|
||||||
|
<g id="Group-8" transform="translate(16.000000, 248.000000)">
|
||||||
|
<g id="Group-6" transform="translate(23.336478, 120.000000)">
|
||||||
|
<g id="Group-5" transform="translate(0.408805, 11.000000)">
|
||||||
|
<g id="copy-to-clipboard">
|
||||||
|
<rect id="Rectangle-18" stroke="#3098DC" stroke-width="2" x="1" y="1" width="12.0220126" height="12"></rect>
|
||||||
|
<rect id="Rectangle-18-Copy-2" fill="#FFFFFF" x="2.1572327" y="2" width="14.0220126" height="14"></rect>
|
||||||
|
<rect id="Rectangle-18-Copy" stroke="#3098DC" stroke-width="2" x="4.23584906" y="4" width="12.0220126" height="12"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -1,15 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
<svg width="20px" height="18px" viewBox="0 0 20 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<!-- Generator: sketchtool 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
<title>50559280-0739-419A-8E87-3CDD16A6996A</title>
|
||||||
width="24.088px" height="24px" viewBox="138.01 0 24.088 24" enable-background="new 138.01 0 24.088 24" xml:space="preserve" fill="#F7861C">
|
<desc>Created with sketchtool.</desc>
|
||||||
<g>
|
<defs></defs>
|
||||||
<polygon fill="#F7861C" points="157.551,17.075 156.55,17.075 156.55,19.149 142.569,19.149 142.569,17.075 141.568,17.075
|
<g id="Reveal-Seedphrase" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
141.568,20.145 141.955,20.145 141.955,20.15 157.006,20.15 157.006,20.145 157.551,20.145 "/>
|
<g id="Seed-phrase-2" transform="translate(-212.000000, -379.000000)" stroke="#259DE5" stroke-width="2">
|
||||||
<polygon fill="#F7861C" points="152.555,10.275 152.555,11.26 152.555,11.268 151.562,11.268 151.562,12.252 150.565,12.252
|
<g id="Group-2">
|
||||||
150.565,4.171 149.564,4.171 149.564,12.236 148.564,12.236 148.564,11.252 147.564,11.252 147.564,11.236 147.564,11.221
|
<g id="Group-8" transform="translate(16.000000, 248.000000)">
|
||||||
147.564,10.236 146.563,10.236 146.563,11.221 146.563,11.236 146.563,12.221 147.563,12.221 147.563,12.236 147.563,12.252
|
<g id="Group-6" transform="translate(23.336478, 120.000000)">
|
||||||
147.563,13.236 148.563,13.236 148.563,14.221 149.564,14.221 149.564,15.725 150.565,15.725 150.565,14.236 151.563,14.236
|
<g id="Group-3" transform="translate(174.000000, 11.000000)">
|
||||||
151.563,13.252 152.563,13.252 152.563,12.268 152.563,12.26 153.556,12.26 153.556,11.275 153.556,11.26 153.556,10.275 "/>
|
<g id="Group-4">
|
||||||
</g>
|
<g id="download">
|
||||||
</svg>
|
<polyline id="Path-5" points="0 11 0 17 17 17 17 11"></polyline>
|
||||||
|
<path d="M8.5,0 L8.5,11" id="Path-6"></path>
|
||||||
|
<polyline id="Path-7" points="3.1875 7 8.5 11 13.8125 7"></polyline>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
22
app/images/warning.svg
Normal file
22
app/images/warning.svg
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="33px" height="32px" viewBox="0 0 33 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>Group 7</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="Reveal-Seedphrase" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Seed-phrase-2" transform="translate(-29.000000, -155.000000)">
|
||||||
|
<g id="Group-2" transform="translate(0.000000, 132.000000)">
|
||||||
|
<g id="Group" transform="translate(28.000000, 19.000000)">
|
||||||
|
<g id="Group-19-Copy-2" transform="translate(0.000000, 3.000000)">
|
||||||
|
<g id="Group-7">
|
||||||
|
<path d="M20.1321134,3.85444772 L32.5721829,26.6020033 C33.367162,28.0556794 32.8331826,29.8785746 31.3795065,30.6735537 C30.9381289,30.9149321 30.4431378,31.0414403 29.9400695,31.0414403 L5.05993054,31.0414403 C3.40307629,31.0414403 2.05993054,29.6982946 2.05993054,28.0414403 C2.05993054,27.538372 2.18643873,27.0433809 2.42781712,26.6020033 L14.8678866,3.85444772 C15.6628657,2.40077162 17.4857609,1.86679221 18.939437,2.66177133 C19.442875,2.93708896 19.8567958,3.35100977 20.1321134,3.85444772 Z" id="Triangle-2-Copy" stroke="#FF001F" stroke-width="2"></path>
|
||||||
|
<rect id="Rectangle-5" fill="#FF001F" x="16" y="9" width="3" height="13"></rect>
|
||||||
|
<rect id="Rectangle-5-Copy" fill="#FF001F" x="16" y="24" width="3" height="3"></rect>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
@ -247,7 +247,7 @@ gulp.task('dev:scss', createScssBuildTask({
|
|||||||
src: 'ui/app/css/index.scss',
|
src: 'ui/app/css/index.scss',
|
||||||
dest: 'ui/app/css/output',
|
dest: 'ui/app/css/output',
|
||||||
devMode: true,
|
devMode: true,
|
||||||
pattern: 'ui/app/css/**/*.scss',
|
pattern: 'ui/app/**/*.scss',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
function createScssBuildTask({ src, dest, devMode, pattern }) {
|
function createScssBuildTask({ src, dest, devMode, pattern }) {
|
||||||
|
@ -9,7 +9,7 @@ import Identicon from '../../../../ui/app/components/identicon'
|
|||||||
import { confirmSeedWords, showModal } from '../../../../ui/app/actions'
|
import { confirmSeedWords, showModal } from '../../../../ui/app/actions'
|
||||||
import Breadcrumbs from './breadcrumbs'
|
import Breadcrumbs from './breadcrumbs'
|
||||||
import LoadingScreen from './loading-screen'
|
import LoadingScreen from './loading-screen'
|
||||||
import { DEFAULT_ROUTE } from '../../../../ui/app/routes'
|
import { DEFAULT_ROUTE, INITIALIZE_BACKUP_PHRASE_ROUTE } from '../../../../ui/app/routes'
|
||||||
|
|
||||||
class ConfirmSeedScreen extends Component {
|
class ConfirmSeedScreen extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -53,7 +53,7 @@ class ConfirmSeedScreen extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { seedWords } = this.props
|
const { seedWords, history } = this.props
|
||||||
const { selectedSeeds, shuffledSeeds } = this.state
|
const { selectedSeeds, shuffledSeeds } = this.state
|
||||||
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
const isValid = seedWords === selectedSeeds.map(([_, seed]) => seed).join(' ')
|
||||||
|
|
||||||
@ -66,6 +66,16 @@ class ConfirmSeedScreen extends Component {
|
|||||||
<div className="first-view-main-wrapper">
|
<div className="first-view-main-wrapper">
|
||||||
<div className="first-view-main">
|
<div className="first-view-main">
|
||||||
<div className="backup-phrase">
|
<div className="backup-phrase">
|
||||||
|
<a
|
||||||
|
className="backup-phrase__back-button"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
history.push(INITIALIZE_BACKUP_PHRASE_ROUTE)
|
||||||
|
}}
|
||||||
|
href="#"
|
||||||
|
>
|
||||||
|
{`< Back`}
|
||||||
|
</a>
|
||||||
<Identicon address={this.props.address} diameter={70} />
|
<Identicon address={this.props.address} diameter={70} />
|
||||||
<div className="backup-phrase__content-wrapper">
|
<div className="backup-phrase__content-wrapper">
|
||||||
<div>
|
<div>
|
||||||
|
@ -83,7 +83,7 @@ var actions = {
|
|||||||
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
|
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
|
||||||
revealSeedConfirmation: revealSeedConfirmation,
|
revealSeedConfirmation: revealSeedConfirmation,
|
||||||
requestRevealSeed: requestRevealSeed,
|
requestRevealSeed: requestRevealSeed,
|
||||||
|
requestRevealSeedWords,
|
||||||
// unlock screen
|
// unlock screen
|
||||||
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
|
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
|
||||||
UNLOCK_FAILED: 'UNLOCK_FAILED',
|
UNLOCK_FAILED: 'UNLOCK_FAILED',
|
||||||
@ -427,6 +427,30 @@ function revealSeedConfirmation () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function verifyPassword (password) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
background.submitPassword(password, error => {
|
||||||
|
if (error) {
|
||||||
|
return reject(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifySeedPhrase () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
background.verifySeedPhrase((error, seedWords) => {
|
||||||
|
if (error) {
|
||||||
|
return reject(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(seedWords)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function requestRevealSeed (password) {
|
function requestRevealSeed (password) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
@ -454,6 +478,24 @@ function requestRevealSeed (password) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requestRevealSeedWords (password) {
|
||||||
|
return async dispatch => {
|
||||||
|
dispatch(actions.showLoadingIndication())
|
||||||
|
log.debug(`background.submitPassword`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await verifyPassword(password)
|
||||||
|
const seedWords = await verifySeedPhrase()
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
return seedWords
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
dispatch(actions.displayWarning(error.message))
|
||||||
|
throw new Error(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function resetAccount () {
|
function resetAccount () {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
background.resetAccount((err, account) => {
|
background.resetAccount((err, account) => {
|
||||||
|
@ -24,7 +24,7 @@ const Initialized = require('./components/pages/initialized')
|
|||||||
const Settings = require('./components/pages/settings')
|
const Settings = require('./components/pages/settings')
|
||||||
const UnlockPage = require('./components/pages/unlock')
|
const UnlockPage = require('./components/pages/unlock')
|
||||||
const RestoreVaultPage = require('./components/pages/keychains/restore-vault')
|
const RestoreVaultPage = require('./components/pages/keychains/restore-vault')
|
||||||
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
|
const RevealSeedConfirmation = require('./components/pages/keychains/reveal-seed')
|
||||||
const AddTokenPage = require('./components/pages/add-token')
|
const AddTokenPage = require('./components/pages/add-token')
|
||||||
const CreateAccountPage = require('./components/pages/create-account')
|
const CreateAccountPage = require('./components/pages/create-account')
|
||||||
const NoticeScreen = require('./components/pages/notice')
|
const NoticeScreen = require('./components/pages/notice')
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
const { Component } = require('react')
|
||||||
|
const PropTypes = require('prop-types')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const copyToClipboard = require('copy-to-clipboard')
|
||||||
|
const { exportAsFile } = require('../../util')
|
||||||
|
|
||||||
|
class ExportTextContainer extends Component {
|
||||||
|
render () {
|
||||||
|
const { text = '', filename = '' } = this.props
|
||||||
|
const { t } = this.context
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('.export-text-container', [
|
||||||
|
h('.export-text-container__text-container', [
|
||||||
|
h('.export-text-container__text', text),
|
||||||
|
]),
|
||||||
|
h('.export-text-container__buttons-container', [
|
||||||
|
h('.export-text-container__button.export-text-container__button--copy', {
|
||||||
|
onClick: () => copyToClipboard(text),
|
||||||
|
}, [
|
||||||
|
h('img', { src: 'images/copy-to-clipboard.svg' }),
|
||||||
|
h('.export-text-container__button-text', t('copyToClipboard')),
|
||||||
|
]),
|
||||||
|
h('.export-text-container__button', {
|
||||||
|
onClick: () => exportAsFile(filename, text),
|
||||||
|
}, [
|
||||||
|
h('img', { src: 'images/download.svg' }),
|
||||||
|
h('.export-text-container__button-text', t('saveAsCsvFile')),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportTextContainer.propTypes = {
|
||||||
|
text: PropTypes.string,
|
||||||
|
filename: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportTextContainer.contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ExportTextContainer
|
@ -0,0 +1,52 @@
|
|||||||
|
.export-text-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid $alto;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
&__text-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: $alabaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
resize: none;
|
||||||
|
border: none;
|
||||||
|
background: $alabaster;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__buttons-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
border-top: 1px solid $alto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
padding: 10px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $curious-blue;
|
||||||
|
|
||||||
|
&--copy {
|
||||||
|
border-right: 1px solid $alto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button-text {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
2
ui/app/components/export-text-container/index.js
Normal file
2
ui/app/components/export-text-container/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
const ExportTextContainer = require('./export-text-container.component')
|
||||||
|
module.exports = ExportTextContainer
|
@ -2,11 +2,27 @@ const { Component } = require('react')
|
|||||||
const { connect } = require('react-redux')
|
const { connect } = require('react-redux')
|
||||||
const PropTypes = require('prop-types')
|
const PropTypes = require('prop-types')
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const { exportAsFile } = require('../../../util')
|
const classnames = require('classnames')
|
||||||
const { requestRevealSeed, confirmSeedWords } = require('../../../actions')
|
|
||||||
|
const { requestRevealSeedWords } = require('../../../actions')
|
||||||
const { DEFAULT_ROUTE } = require('../../../routes')
|
const { DEFAULT_ROUTE } = require('../../../routes')
|
||||||
|
const ExportTextContainer = require('../../export-text-container')
|
||||||
|
|
||||||
|
const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN'
|
||||||
|
const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN'
|
||||||
|
|
||||||
class RevealSeedPage extends Component {
|
class RevealSeedPage extends Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
screen: PASSWORD_PROMPT_SCREEN,
|
||||||
|
password: '',
|
||||||
|
seedWords: null,
|
||||||
|
error: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const passwordBox = document.getElementById('password-box')
|
const passwordBox = document.getElementById('password-box')
|
||||||
if (passwordBox) {
|
if (passwordBox) {
|
||||||
@ -14,182 +30,135 @@ class RevealSeedPage extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkConfirmation (event) {
|
handleSubmit (event) {
|
||||||
if (event.key === 'Enter') {
|
event.preventDefault()
|
||||||
event.preventDefault()
|
this.setState({ seedWords: null, error: null })
|
||||||
this.revealSeedWords()
|
this.props.requestRevealSeedWords(this.state.password)
|
||||||
}
|
.then(seedWords => this.setState({ seedWords, screen: REVEAL_SEED_SCREEN }))
|
||||||
|
.catch(error => this.setState({ error: error.message }))
|
||||||
}
|
}
|
||||||
|
|
||||||
revealSeedWords () {
|
renderWarning () {
|
||||||
const password = document.getElementById('password-box').value
|
|
||||||
this.props.requestRevealSeed(password)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSeed () {
|
|
||||||
const { seedWords, confirmSeedWords, history } = this.props
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', [
|
h('.page-container__warning-container', [
|
||||||
|
h('img.page-container__warning-icon', {
|
||||||
h('h3.flex-center.text-transform-uppercase', {
|
src: 'images/warning.svg',
|
||||||
style: {
|
|
||||||
background: '#EBEBEB',
|
|
||||||
color: '#AEAEAE',
|
|
||||||
marginTop: 36,
|
|
||||||
marginBottom: 8,
|
|
||||||
width: '100%',
|
|
||||||
fontSize: '20px',
|
|
||||||
padding: 6,
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
'Vault Created',
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('div', {
|
|
||||||
style: {
|
|
||||||
fontSize: '1em',
|
|
||||||
marginTop: '10px',
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
h('span.error', 'These 12 words are the only way to restore your MetaMask accounts.\nSave them somewhere safe and secret.'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('textarea.twelve-word-phrase', {
|
|
||||||
readOnly: true,
|
|
||||||
value: seedWords,
|
|
||||||
}),
|
}),
|
||||||
|
h('.page-container__warning-message', [
|
||||||
h('button.primary', {
|
h('.page-container__warning-title', [this.context.t('revealSeedWordsWarningTitle')]),
|
||||||
onClick: () => confirmSeedWords().then(() => history.push(DEFAULT_ROUTE)),
|
h('div', [this.context.t('revealSeedWordsWarning')]),
|
||||||
style: {
|
]),
|
||||||
margin: '24px',
|
|
||||||
fontSize: '0.9em',
|
|
||||||
marginBottom: '10px',
|
|
||||||
},
|
|
||||||
}, 'I\'ve copied it somewhere safe'),
|
|
||||||
|
|
||||||
h('button.primary', {
|
|
||||||
onClick: () => exportAsFile(`MetaMask Seed Words`, seedWords),
|
|
||||||
style: {
|
|
||||||
margin: '10px',
|
|
||||||
fontSize: '0.9em',
|
|
||||||
},
|
|
||||||
}, 'Save Seed Words As File'),
|
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderConfirmation () {
|
renderContent () {
|
||||||
const { history, warning, inProgress } = this.props
|
return this.state.screen === PASSWORD_PROMPT_SCREEN
|
||||||
|
? this.renderPasswordPromptContent()
|
||||||
|
: this.renderRevealSeedContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPasswordPromptContent () {
|
||||||
|
const { t } = this.context
|
||||||
|
|
||||||
return (
|
return (
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', {
|
h('form', {
|
||||||
style: { maxWidth: '420px' },
|
onSubmit: event => this.handleSubmit(event),
|
||||||
}, [
|
}, [
|
||||||
|
h('label.input-label', {
|
||||||
h('h3.flex-center.text-transform-uppercase', {
|
htmlFor: 'password-box',
|
||||||
style: {
|
}, t('enterPasswordContinue')),
|
||||||
background: '#EBEBEB',
|
h('.input-group', [
|
||||||
color: '#AEAEAE',
|
h('input.form-control', {
|
||||||
marginBottom: 24,
|
|
||||||
width: '100%',
|
|
||||||
fontSize: '20px',
|
|
||||||
padding: 6,
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
'Reveal Seed Words',
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('.div', {
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
padding: '20px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
|
|
||||||
h('h4', 'Do not recover your seed words in a public place! These words can be used to steal all your accounts.'),
|
|
||||||
|
|
||||||
// confirmation
|
|
||||||
h('input.large-input.letter-spacey', {
|
|
||||||
type: 'password',
|
type: 'password',
|
||||||
|
placeholder: t('password'),
|
||||||
id: 'password-box',
|
id: 'password-box',
|
||||||
placeholder: 'Enter your password to confirm',
|
value: this.state.password,
|
||||||
onKeyPress: this.checkConfirmation.bind(this),
|
onChange: event => this.setState({ password: event.target.value }),
|
||||||
style: {
|
className: classnames({ 'form-control--error': this.state.error }),
|
||||||
width: 260,
|
|
||||||
marginTop: '12px',
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
h('.flex-row.flex-start', {
|
|
||||||
style: {
|
|
||||||
marginTop: 30,
|
|
||||||
width: '50%',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
// cancel
|
|
||||||
h('button.primary', {
|
|
||||||
onClick: () => history.push(DEFAULT_ROUTE),
|
|
||||||
}, 'CANCEL'),
|
|
||||||
|
|
||||||
// submit
|
|
||||||
h('button.primary', {
|
|
||||||
style: { marginLeft: '10px' },
|
|
||||||
onClick: this.revealSeedWords.bind(this),
|
|
||||||
}, 'OK'),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
warning && (
|
|
||||||
h('span.error', {
|
|
||||||
style: {
|
|
||||||
margin: '20px',
|
|
||||||
},
|
|
||||||
}, warning.split('-'))
|
|
||||||
),
|
|
||||||
|
|
||||||
inProgress && (
|
|
||||||
h('span.in-progress-notification', 'Generating Seed...')
|
|
||||||
),
|
|
||||||
]),
|
]),
|
||||||
|
this.state.error && h('.reveal-seed__error', this.state.error),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRevealSeedContent () {
|
||||||
|
const { t } = this.context
|
||||||
|
|
||||||
|
return (
|
||||||
|
h('div', [
|
||||||
|
h('label.reveal-seed__label', t('yourPrivateSeedPhrase')),
|
||||||
|
h(ExportTextContainer, {
|
||||||
|
text: this.state.seedWords,
|
||||||
|
filename: t('metamaskSeedWords'),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFooter () {
|
||||||
|
return this.state.screen === PASSWORD_PROMPT_SCREEN
|
||||||
|
? this.renderPasswordPromptFooter()
|
||||||
|
: this.renderRevealSeedFooter()
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPasswordPromptFooter () {
|
||||||
|
return (
|
||||||
|
h('.page-container__footer', [
|
||||||
|
h('button.btn-secondary--lg.page-container__footer-button', {
|
||||||
|
onClick: () => this.props.history.push(DEFAULT_ROUTE),
|
||||||
|
}, this.context.t('cancel')),
|
||||||
|
h('button.btn-primary--lg.page-container__footer-button', {
|
||||||
|
onClick: event => this.handleSubmit(event),
|
||||||
|
disabled: this.state.password === '',
|
||||||
|
}, this.context.t('next')),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRevealSeedFooter () {
|
||||||
|
return (
|
||||||
|
h('.page-container__footer', [
|
||||||
|
h('button.btn-secondary--lg.page-container__footer-button', {
|
||||||
|
onClick: () => this.props.history.push(DEFAULT_ROUTE),
|
||||||
|
}, this.context.t('close')),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return this.props.seedWords
|
return (
|
||||||
? this.renderSeed()
|
h('.page-container', [
|
||||||
: this.renderConfirmation()
|
h('.page-container__header', [
|
||||||
|
h('.page-container__title', this.context.t('revealSeedWordsTitle')),
|
||||||
|
h('.page-container__subtitle', this.context.t('revealSeedWordsDescription')),
|
||||||
|
]),
|
||||||
|
h('.page-container__content', [
|
||||||
|
this.renderWarning(),
|
||||||
|
h('.reveal-seed__content', [
|
||||||
|
this.renderContent(),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
this.renderFooter(),
|
||||||
|
])
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RevealSeedPage.propTypes = {
|
RevealSeedPage.propTypes = {
|
||||||
requestRevealSeed: PropTypes.func,
|
requestRevealSeedWords: PropTypes.func,
|
||||||
confirmSeedWords: PropTypes.func,
|
|
||||||
seedWords: PropTypes.string,
|
|
||||||
inProgress: PropTypes.bool,
|
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
warning: PropTypes.string,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
RevealSeedPage.contextTypes = {
|
||||||
const { appState: { warning }, metamask: { seedWords } } = state
|
t: PropTypes.func,
|
||||||
|
|
||||||
return {
|
|
||||||
warning,
|
|
||||||
seedWords,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
requestRevealSeed: password => dispatch(requestRevealSeed(password)),
|
requestRevealSeedWords: password => dispatch(requestRevealSeedWords(password)),
|
||||||
confirmSeedWords: () => dispatch(confirmSeedWords()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(RevealSeedPage)
|
module.exports = connect(null, mapDispatchToProps)(RevealSeedPage)
|
||||||
|
@ -61,3 +61,5 @@
|
|||||||
@import './welcome-screen.scss';
|
@import './welcome-screen.scss';
|
||||||
|
|
||||||
@import './sender-to-recipient.scss';
|
@import './sender-to-recipient.scss';
|
||||||
|
|
||||||
|
@import '../../../components/export-text-container/export-text-container.scss';
|
||||||
|
@ -1 +1,3 @@
|
|||||||
@import './unlock.scss';
|
@import './unlock.scss';
|
||||||
|
|
||||||
|
@import './reveal-seed.scss';
|
||||||
|
17
ui/app/css/itcss/components/pages/reveal-seed.scss
Normal file
17
ui/app/css/itcss/components/pages/reveal-seed.scss
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.reveal-seed {
|
||||||
|
&__content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
font-weight: 400;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__error {
|
||||||
|
color: $crimson;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
@ -207,6 +207,27 @@ input.large-input {
|
|||||||
&__content {
|
&__content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
min-height: 250px;
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__warning-container {
|
||||||
|
background: $linen;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__warning-message {
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__warning-title {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__warning-icon {
|
||||||
|
padding-top: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,3 +258,49 @@ input.large-input {
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 576px) {
|
||||||
|
.page-container {
|
||||||
|
height: 600px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-label {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
font-weight: 400;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.form-control {
|
||||||
|
padding-left: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 40px;
|
||||||
|
border: 1px solid $alto;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&::-webkit-input-placeholder {
|
||||||
|
font-weight: 100;
|
||||||
|
color: $dusty-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-moz-placeholder {
|
||||||
|
font-weight: 100;
|
||||||
|
color: $dusty-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:-ms-input-placeholder {
|
||||||
|
font-weight: 100;
|
||||||
|
color: $dusty-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:-moz-placeholder {
|
||||||
|
font-weight: 100;
|
||||||
|
color: $dusty-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
border: 1px solid $monzo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -54,6 +54,7 @@ $saffron: #f6c343;
|
|||||||
$dodger-blue: #3099f2;
|
$dodger-blue: #3099f2;
|
||||||
$zumthor: #edf7ff;
|
$zumthor: #edf7ff;
|
||||||
$ecstasy: #f7861c;
|
$ecstasy: #f7861c;
|
||||||
|
$linen: #fdf4f4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Z-Indicies
|
Z-Indicies
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
const inherits = require('util').inherits
|
|
||||||
const Component = require('react').Component
|
|
||||||
const PropTypes = require('prop-types')
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const actions = require('../../../actions')
|
|
||||||
const { withRouter } = require('react-router-dom')
|
|
||||||
const { compose } = require('recompose')
|
|
||||||
const {
|
|
||||||
DEFAULT_ROUTE,
|
|
||||||
INITIALIZE_BACKUP_PHRASE_ROUTE,
|
|
||||||
} = require('../../../routes')
|
|
||||||
|
|
||||||
RevealSeedConfirmation.contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = compose(
|
|
||||||
withRouter,
|
|
||||||
connect(mapStateToProps)
|
|
||||||
)(RevealSeedConfirmation)
|
|
||||||
|
|
||||||
|
|
||||||
inherits(RevealSeedConfirmation, Component)
|
|
||||||
function RevealSeedConfirmation () {
|
|
||||||
Component.call(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
return {
|
|
||||||
warning: state.appState.warning,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.render = function () {
|
|
||||||
const props = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', {
|
|
||||||
style: { maxWidth: '420px' },
|
|
||||||
}, [
|
|
||||||
|
|
||||||
h('h3.flex-center.text-transform-uppercase', {
|
|
||||||
style: {
|
|
||||||
background: '#EBEBEB',
|
|
||||||
color: '#AEAEAE',
|
|
||||||
marginBottom: 24,
|
|
||||||
width: '100%',
|
|
||||||
fontSize: '20px',
|
|
||||||
padding: 6,
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
'Reveal Seed Words',
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('.div', {
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
padding: '20px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
|
|
||||||
h('h4', this.context.t('revealSeedWordsWarning')),
|
|
||||||
|
|
||||||
// confirmation
|
|
||||||
h('input.large-input.letter-spacey', {
|
|
||||||
type: 'password',
|
|
||||||
id: 'password-box',
|
|
||||||
placeholder: this.context.t('enterPasswordConfirm'),
|
|
||||||
onKeyPress: this.checkConfirmation.bind(this),
|
|
||||||
style: {
|
|
||||||
width: 260,
|
|
||||||
marginTop: '12px',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
h('.flex-row.flex-start', {
|
|
||||||
style: {
|
|
||||||
marginTop: 30,
|
|
||||||
width: '50%',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
// cancel
|
|
||||||
h('button.primary', {
|
|
||||||
onClick: this.goHome.bind(this),
|
|
||||||
}, 'CANCEL'),
|
|
||||||
|
|
||||||
// submit
|
|
||||||
h('button.primary', {
|
|
||||||
style: { marginLeft: '10px' },
|
|
||||||
onClick: this.revealSeedWords.bind(this),
|
|
||||||
}, 'OK'),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
(props.warning) && (
|
|
||||||
h('span.error', {
|
|
||||||
style: {
|
|
||||||
margin: '20px',
|
|
||||||
},
|
|
||||||
}, props.warning.split('-'))
|
|
||||||
),
|
|
||||||
|
|
||||||
props.inProgress && (
|
|
||||||
h('span.in-progress-notification', this.context.t('generatingSeed'))
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.componentDidMount = function () {
|
|
||||||
document.getElementById('password-box').focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.goHome = function () {
|
|
||||||
this.props.dispatch(actions.showConfigPage(false))
|
|
||||||
this.props.dispatch(actions.confirmSeedWords())
|
|
||||||
.then(() => this.props.history.push(DEFAULT_ROUTE))
|
|
||||||
}
|
|
||||||
|
|
||||||
// create vault
|
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.checkConfirmation = function (event) {
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
event.preventDefault()
|
|
||||||
this.revealSeedWords()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.revealSeedWords = function () {
|
|
||||||
var password = document.getElementById('password-box').value
|
|
||||||
this.props.dispatch(actions.requestRevealSeed(password))
|
|
||||||
.then(() => this.props.history.push(INITIALIZE_BACKUP_PHRASE_ROUTE))
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user