diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index 28b988f5a..b1d551781 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect +const ethUtil = require('ethereumjs-util') const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') @@ -9,20 +10,83 @@ const ReadOnlyInput = require('../readonly-input') function mapStateToProps (state) { return { + warning: state.appState.warning, + privateKey: state.appState.accountDetail.privateKey, network: state.metamask.network, selectedIdentity: getSelectedIdentity(state), } } +function mapDispatchToProps (dispatch) { + return { + exportAccount: (password, address) => dispatch(actions.exportAccount(password, address)), + hideModal: () => dispatch(actions.hideModal()), + } +} + inherits(ExportPrivateKeyModal, Component) function ExportPrivateKeyModal () { Component.call(this) + + this.state = { + password: '' + } +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(ExportPrivateKeyModal) + +ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) { + return h('span.private-key-password-label', privateKey + ? 'This is your private key (click to copy)' + : 'Type Your Password' + ) +} + +ExportPrivateKeyModal.prototype.renderPasswordInput = function (privateKey) { + const plainKey = privateKey && ethUtil.stripHexPrefix(privateKey) + + return privateKey + ? h(ReadOnlyInput, { + wrapperClass: 'private-key-password-display-wrapper', + inputClass: 'private-key-password-display-textarea', + textarea: true, + value: plainKey, + }) + : h('input.private-key-password-input', { + type: 'password', + placeholder: 'Type password', + onChange: event => this.setState({ password: event.target.value }) + }) +} + +ExportPrivateKeyModal.prototype.renderButton = function (className, onClick, label) { + return h('button', { + className, + onClick, + }, label) } -module.exports = connect(mapStateToProps)(ExportPrivateKeyModal) +ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, address) { + const { hideModal, exportAccount } = this.props + + return h('div.export-private-key-buttons', {}, [ + !privateKey && this.renderButton('btn-clear btn-cancel', () => hideModal(), 'Cancel'), + + (privateKey + ? this.renderButton('btn-clear', () => hideModal(), 'Done') + : this.renderButton('btn-clear', () => exportAccount(this.state.password, address), 'Download') + ), + + ]) +} ExportPrivateKeyModal.prototype.render = function () { - const { selectedIdentity, network } = this.props + const { + selectedIdentity, + network, + privateKey, + warning, + } = this.props const { name, address } = selectedIdentity return h(AccountModalContainer, {}, [ @@ -31,7 +95,7 @@ ExportPrivateKeyModal.prototype.render = function () { h(ReadOnlyInput, { wrapperClass: 'ellip-address-wrapper', - inputClass: 'ellip-address', + inputClass: 'qr-ellip-address ellip-address', value: address, }), @@ -40,12 +104,11 @@ ExportPrivateKeyModal.prototype.render = function () { h('span.modal-body-title', 'Download Private Keys'), h('div.private-key-password', {}, [ - h('span.private-key-password-label', 'Type Your Password'), + this.renderPasswordLabel(privateKey), + + this.renderPasswordInput(privateKey), - h('input.private-key-password-input', { - type: 'password', - placeholder: 'Type password', - }), + !warning ? null : h('span.private-key-password-error', warning), ]), h('div.private-key-password-warning', `Warning: Never disclose this key. @@ -53,11 +116,7 @@ ExportPrivateKeyModal.prototype.render = function () { account.` ), - h('div.export-private-key-buttons', {}, [ - h('button.btn-clear.btn-cancel', {}, 'Cancel'), - - h('button.btn-clear', 'Download'), - ]), + this.renderButtons(privateKey, this.state.password, address), ]) } diff --git a/ui/app/components/readonly-input.js b/ui/app/components/readonly-input.js index 934cbefae..33b93b5a0 100644 --- a/ui/app/components/readonly-input.js +++ b/ui/app/components/readonly-input.js @@ -14,13 +14,17 @@ ReadOnlyInput.prototype.render = function () { wrapperClass = '', inputClass = '', value, + textarea, } = this.props + const inputType = textarea ? 'textarea' : 'input' + return h('div', {className: wrapperClass}, [ - h('input', { + h(inputType, { className: inputClass, value, readOnly: true, + onFocus: event => event.target.select(), }), ]) } diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss index 9cdfdec8f..00b6111f7 100644 --- a/ui/app/css/itcss/components/modal.scss +++ b/ui/app/css/itcss/components/modal.scss @@ -283,13 +283,18 @@ flex-direction: column; } -.private-key-password-label { +.private-key-password-label, .private-key-password-error { color: $scorpion; font-size: 14px; line-height: 18px; margin-bottom: 10px; } +.private-key-password-error { + color: $crimson; + margin-bottom: 0; +} + .private-key-password-input { padding: 10px 0 13px 17px; font-size: 16px; @@ -333,6 +338,27 @@ } } +.private-key-password-display-wrapper { + height: 80px; + width: 291px; + border: 1px solid $silver; + border-radius: 2px; +} + +.private-key-password-display-textarea { + color: $crimson; + font-family: "DIN OT"; + font-size: 16px; + line-height: 21px; + border: none; + height: 75px; + width: 253px; + overflow: hidden; + resize: none; + padding: 9px 13px 8px; + text-transform: uppercase; +} + // New Account Modal .new-account-modal-wrapper {