From 174dea8a2916dcc3aabe2bf5f6be5a95a653ce7a Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Fri, 2 Feb 2018 01:01:30 -0500 Subject: [PATCH] MEW-01-004 - Stronger Keystores (#981) * Add better password checking, confirm password, feedback, and up the minimum to 12. * Move wallet generation off to a web worker, and bump up the n value to 8192. Refactor workers a wee bit. * tscheck cleanup * Make keystore password a form. Replace text with spinner on load. * Center align again. * Hard code n factor of test wallet, fix some misspelled type definitions for IV3Wallet. --- common/components/PrintableWallet/index.tsx | 17 ++- common/components/TogglablePassword.tsx | 18 ++- common/config/data.tsx | 4 +- .../components/Keystore/DownloadWallet.tsx | 39 +----- .../components/Keystore/EnterPassword.scss | 17 ++- .../components/Keystore/EnterPassword.tsx | 132 +++++++++++++++--- .../components/Keystore/Keystore.tsx | 52 +++++-- .../components/Keystore/PaperWallet.tsx | 9 +- .../libs/wallet/non-deterministic/wallets.ts | 2 +- .../{scrypt-wrapper.ts => fromV3.ts} | 16 +-- common/libs/web-workers/generateKeystore.ts | 22 +++ common/libs/web-workers/index.ts | 2 + ...rypt-worker.worker.ts => fromV3.worker.ts} | 8 +- .../workers/generateKeystore.worker.ts | 19 +++ common/sass/styles/overrides/forms.scss | 14 ++ common/typescript/ethereumjs-wallet.d.ts | 6 +- package.json | 4 +- spec/sagas/wallet.spec.tsx | 10 +- webpack_config/config.js | 1 - 19 files changed, 282 insertions(+), 110 deletions(-) rename common/libs/web-workers/{scrypt-wrapper.ts => fromV3.ts} (54%) create mode 100644 common/libs/web-workers/generateKeystore.ts create mode 100644 common/libs/web-workers/index.ts rename common/libs/web-workers/workers/{scrypt-worker.worker.ts => fromV3.worker.ts} (62%) create mode 100644 common/libs/web-workers/workers/generateKeystore.worker.ts diff --git a/common/components/PrintableWallet/index.tsx b/common/components/PrintableWallet/index.tsx index f22d811c..f3db5211 100644 --- a/common/components/PrintableWallet/index.tsx +++ b/common/components/PrintableWallet/index.tsx @@ -1,5 +1,4 @@ import { PaperWallet } from 'components'; -import { IFullWallet } from 'ethereumjs-wallet'; import React from 'react'; import { translateRaw } from 'translations'; import printElement from 'utils/printElement'; @@ -26,23 +25,23 @@ export const print = (address: string, privateKey: string) => () => ` }); -const PrintableWallet: React.SFC<{ wallet: IFullWallet }> = ({ wallet }) => { - const address = wallet.getAddressString(); - const privateKey = stripHexPrefix(wallet.getPrivateKeyString()); +interface Props { + address: string; + privateKey: string; +} - if (!address || !privateKey) { - return null; - } +const PrintableWallet: React.SFC = ({ address, privateKey }) => { + const pkey = stripHexPrefix(privateKey); return (
- + {translateRaw('x_Print')} diff --git a/common/components/TogglablePassword.tsx b/common/components/TogglablePassword.tsx index 8c66fde7..a4e3243a 100644 --- a/common/components/TogglablePassword.tsx +++ b/common/components/TogglablePassword.tsx @@ -15,6 +15,7 @@ interface Props { toggleAriaLabel?: string; isValid?: boolean; isVisible?: boolean; + validity?: 'valid' | 'invalid' | 'semivalid'; // Textarea-only props isTextareaWhenVisible?: boolean; @@ -23,6 +24,8 @@ interface Props { // Shared callbacks onChange?(ev: React.FormEvent): void; + onFocus?(ev: React.FocusEvent): void; + onBlur?(ev: React.FocusEvent): void; handleToggleVisibility?(): void; } @@ -48,14 +51,19 @@ export default class TogglablePassword extends React.PureComponent name, disabled, ariaLabel, + toggleAriaLabel, + validity, isTextareaWhenVisible, isValid, onChange, + onFocus, + onBlur, handleToggleVisibility } = this.props; const { isVisible } = this.state; - const validClass = - isValid === null || isValid === undefined ? '' : isValid ? 'is-valid' : 'is-invalid'; + const validClass = validity + ? `is-${validity}` + : isValid === null || isValid === undefined ? '' : isValid ? 'is-valid' : 'is-invalid'; return (
@@ -67,6 +75,8 @@ export default class TogglablePassword extends React.PureComponent disabled={disabled} onChange={onChange} onKeyDown={this.handleTextareaKeyDown} + onFocus={onFocus} + onBlur={onBlur} placeholder={placeholder} rows={this.props.rows || 3} aria-label={ariaLabel} @@ -80,12 +90,14 @@ export default class TogglablePassword extends React.PureComponent className={`form-control ${validClass}`} placeholder={placeholder} onChange={onChange} + onFocus={onFocus} + onBlur={onBlur} aria-label={ariaLabel} /> )} diff --git a/common/config/data.tsx b/common/config/data.tsx index b23b0320..c7c1edf7 100644 --- a/common/config/data.tsx +++ b/common/config/data.tsx @@ -5,7 +5,7 @@ export const languages = require('./languages.json'); // Displays in the header export const VERSION = '4.0.0 (Alpha 0.1.0)'; -export const N_FACTOR = 1024; +export const N_FACTOR = 8192; // Displays at the top of the site, make message empty string to remove. // Type can be primary, warning, danger, success, or info. @@ -47,7 +47,7 @@ export const gasPriceDefaults = { gasPriceMaxGwei: 60 }; -export const MINIMUM_PASSWORD_LENGTH = 9; +export const MINIMUM_PASSWORD_LENGTH = 12; export const knowledgeBaseURL = 'https://myetherwallet.github.io/knowledge-base'; export const bityReferralURL = 'https://bity.com/af/jshkb37v'; diff --git a/common/containers/Tabs/GenerateWallet/components/Keystore/DownloadWallet.tsx b/common/containers/Tabs/GenerateWallet/components/Keystore/DownloadWallet.tsx index ac72b46c..f8a31387 100644 --- a/common/containers/Tabs/GenerateWallet/components/Keystore/DownloadWallet.tsx +++ b/common/containers/Tabs/GenerateWallet/components/Keystore/DownloadWallet.tsx @@ -1,42 +1,28 @@ -import { IFullWallet, IV3Wallet } from 'ethereumjs-wallet'; -import { toChecksumAddress } from 'ethereumjs-util'; +import { IV3Wallet } from 'ethereumjs-wallet'; import React, { Component } from 'react'; import translate from 'translations'; import { makeBlob } from 'utils/blob'; import './DownloadWallet.scss'; import Template from '../Template'; -import { N_FACTOR } from 'config'; interface Props { - wallet: IFullWallet; - password: string; + keystore: IV3Wallet; + filename: string; continue(): void; } interface State { hasDownloadedWallet: boolean; - keystore: IV3Wallet | null; } export default class DownloadWallet extends Component { public state: State = { - hasDownloadedWallet: false, - keystore: null + hasDownloadedWallet: false }; - public componentWillMount() { - this.setWallet(this.props.wallet, this.props.password); - } - - public componentWillUpdate(nextProps: Props) { - if (this.props.wallet !== nextProps.wallet) { - this.setWallet(nextProps.wallet, nextProps.password); - } - } - public render() { + const { filename } = this.props; const { hasDownloadedWallet } = this.state; - const filename = this.props.wallet.getV3Filename(); return (