Add Check and Change Password for an Account (#2861)
* Added new RPC endpoints to JSAPI (#2389) * Added modal in Account Page to test & modify password (#2389) * Modify hint with password change // Better tabs (#2556)
This commit is contained in:
parent
e71c752210
commit
2d2e9c4d6e
@ -33,6 +33,11 @@ export default class Personal {
|
|||||||
.execute('personal_confirmRequest', inNumber16(requestId), options, password);
|
.execute('personal_confirmRequest', inNumber16(requestId), options, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changePassword (account, password, newPassword) {
|
||||||
|
return this._transport
|
||||||
|
.execute('personal_changePassword', inAddress(account), password, newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
generateAuthorizationToken () {
|
generateAuthorizationToken () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('personal_generateAuthorizationToken');
|
.execute('personal_generateAuthorizationToken');
|
||||||
@ -105,6 +110,11 @@ export default class Personal {
|
|||||||
.execute('personal_signerEnabled');
|
.execute('personal_signerEnabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testPassword (account, password) {
|
||||||
|
return this._transport
|
||||||
|
.execute('personal_testPassword', inAddress(account), password);
|
||||||
|
}
|
||||||
|
|
||||||
unlockAccount (account, password, duration = 1) {
|
unlockAccount (account, password, duration = 1) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('personal_unlockAccount', inAddress(account), password, inNumber10(duration));
|
.execute('personal_unlockAccount', inAddress(account), password, inNumber10(duration));
|
||||||
|
17
js/src/modals/PasswordManager/index.js
Normal file
17
js/src/modals/PasswordManager/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './passwordManager.js';
|
73
js/src/modals/PasswordManager/passwordManager.css
Normal file
73
js/src/modals/PasswordManager/passwordManager.css
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.accountContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountInfos {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountInfos > * {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hintLabel {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountAddress {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountName {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passwordHint {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
margin-top: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
height: 2.5rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 2.5rem;
|
||||||
|
transition: height 350ms 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hideMessage {
|
||||||
|
height: 0;
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 0 0.5rem 1rem;
|
||||||
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
383
js/src/modals/PasswordManager/passwordManager.js
Normal file
383
js/src/modals/PasswordManager/passwordManager.js
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import ContentClear from 'material-ui/svg-icons/content/clear';
|
||||||
|
import CheckIcon from 'material-ui/svg-icons/navigation/check';
|
||||||
|
import SendIcon from 'material-ui/svg-icons/content/send';
|
||||||
|
|
||||||
|
import { Tabs, Tab } from 'material-ui/Tabs';
|
||||||
|
import Paper from 'material-ui/Paper';
|
||||||
|
|
||||||
|
import Form, { Input } from '../../ui/Form';
|
||||||
|
import { Button, Modal, IdentityName, IdentityIcon } from '../../ui';
|
||||||
|
|
||||||
|
import styles from './passwordManager.css';
|
||||||
|
|
||||||
|
const TEST_ACTION = 'TEST_ACTION';
|
||||||
|
const CHANGE_ACTION = 'CHANGE_ACTION';
|
||||||
|
|
||||||
|
export default class PasswordManager extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
api: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
account: PropTypes.object.isRequired,
|
||||||
|
onClose: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
action: TEST_ACTION,
|
||||||
|
waiting: false,
|
||||||
|
showMessage: false,
|
||||||
|
message: { value: '', success: true },
|
||||||
|
currentPass: '',
|
||||||
|
newPass: '',
|
||||||
|
repeatNewPass: '',
|
||||||
|
repeatValid: true,
|
||||||
|
passwordHint: this.props.account.meta && this.props.account.meta.passwordHint || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
actions={ this.renderDialogActions() }
|
||||||
|
title='Password Manager'
|
||||||
|
visible>
|
||||||
|
{ this.renderAccount() }
|
||||||
|
{ this.renderPage() }
|
||||||
|
{ this.renderMessage() }
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMessage () {
|
||||||
|
const { message, showMessage } = this.state;
|
||||||
|
|
||||||
|
const style = message.success
|
||||||
|
? {
|
||||||
|
backgroundColor: 'rgba(174, 213, 129, 0.75)'
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
backgroundColor: 'rgba(229, 115, 115, 0.75)'
|
||||||
|
};
|
||||||
|
|
||||||
|
const classes = [ styles.message ];
|
||||||
|
|
||||||
|
if (!showMessage) {
|
||||||
|
classes.push(styles.hideMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper
|
||||||
|
zDepth={ 1 }
|
||||||
|
style={ style }
|
||||||
|
className={ classes.join(' ') }>
|
||||||
|
{ message.value }
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAccount () {
|
||||||
|
const { account } = this.props;
|
||||||
|
const { address, meta } = account;
|
||||||
|
|
||||||
|
const passwordHint = meta && meta.passwordHint
|
||||||
|
? (
|
||||||
|
<span className={ styles.passwordHint }>
|
||||||
|
<span className={ styles.hintLabel }>Hint </span>
|
||||||
|
{ meta.passwordHint }
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.accountContainer }>
|
||||||
|
<IdentityIcon
|
||||||
|
address={ address }
|
||||||
|
/>
|
||||||
|
<div className={ styles.accountInfos }>
|
||||||
|
<IdentityName
|
||||||
|
className={ styles.accountName }
|
||||||
|
address={ address }
|
||||||
|
unknown
|
||||||
|
/>
|
||||||
|
<span className={ styles.accountAddress }>
|
||||||
|
{ address }
|
||||||
|
</span>
|
||||||
|
{ passwordHint }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPage () {
|
||||||
|
const { account } = this.props;
|
||||||
|
const { waiting, repeatValid } = this.state;
|
||||||
|
const disabled = !!waiting;
|
||||||
|
|
||||||
|
const repeatError = repeatValid
|
||||||
|
? null
|
||||||
|
: 'the two passwords differ';
|
||||||
|
|
||||||
|
const { meta } = account;
|
||||||
|
const passwordHint = meta && meta.passwordHint || '';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
inkBarStyle={ {
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.55)'
|
||||||
|
} }
|
||||||
|
tabItemContainerStyle={ {
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.05)'
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
<Tab
|
||||||
|
onActive={ this.handleTestActive }
|
||||||
|
label='Test Password'
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
className={ styles.form }
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
label='password'
|
||||||
|
hint='your current password for this account'
|
||||||
|
type='password'
|
||||||
|
submitOnBlur={ false }
|
||||||
|
disabled={ disabled }
|
||||||
|
onSubmit={ this.handleTestPassword }
|
||||||
|
onChange={ this.onEditCurrent } />
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</Tab>
|
||||||
|
<Tab
|
||||||
|
onActive={ this.handleChangeActive }
|
||||||
|
label='Change Password'
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
className={ styles.form }
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
label='current password'
|
||||||
|
hint='your current password for this account'
|
||||||
|
type='password'
|
||||||
|
submitOnBlur={ false }
|
||||||
|
disabled={ disabled }
|
||||||
|
onSubmit={ this.handleChangePassword }
|
||||||
|
onChange={ this.onEditCurrent } />
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label='new password'
|
||||||
|
hint='the new password for this account'
|
||||||
|
type='password'
|
||||||
|
submitOnBlur={ false }
|
||||||
|
disabled={ disabled }
|
||||||
|
onSubmit={ this.handleChangePassword }
|
||||||
|
onChange={ this.onEditNew } />
|
||||||
|
<Input
|
||||||
|
label='repeat new password'
|
||||||
|
hint='repeat the new password for this account'
|
||||||
|
type='password'
|
||||||
|
submitOnBlur={ false }
|
||||||
|
error={ repeatError }
|
||||||
|
disabled={ disabled }
|
||||||
|
onSubmit={ this.handleChangePassword }
|
||||||
|
onChange={ this.onEditRepeatNew } />
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label='new password hint'
|
||||||
|
hint='hint for the new password'
|
||||||
|
submitOnBlur={ false }
|
||||||
|
value={ passwordHint }
|
||||||
|
disabled={ disabled }
|
||||||
|
onSubmit={ this.handleChangePassword }
|
||||||
|
onChange={ this.onEditHint } />
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDialogActions () {
|
||||||
|
const { onClose } = this.props;
|
||||||
|
const { action, waiting, repeatValid } = this.state;
|
||||||
|
|
||||||
|
const cancelBtn = (
|
||||||
|
<Button
|
||||||
|
icon={ <ContentClear /> }
|
||||||
|
label='Cancel'
|
||||||
|
onClick={ onClose } />
|
||||||
|
);
|
||||||
|
|
||||||
|
if (waiting) {
|
||||||
|
const waitingBtn = (
|
||||||
|
<Button
|
||||||
|
disabled
|
||||||
|
label='Wait...' />
|
||||||
|
);
|
||||||
|
|
||||||
|
return [ cancelBtn, waitingBtn ];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === TEST_ACTION) {
|
||||||
|
const testBtn = (
|
||||||
|
<Button
|
||||||
|
icon={ <CheckIcon /> }
|
||||||
|
label='Test'
|
||||||
|
onClick={ this.handleTestPassword } />
|
||||||
|
);
|
||||||
|
|
||||||
|
return [ cancelBtn, testBtn ];
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeBtn = (
|
||||||
|
<Button
|
||||||
|
disabled={ !repeatValid }
|
||||||
|
icon={ <SendIcon /> }
|
||||||
|
label='Change'
|
||||||
|
onClick={ this.handleChangePassword } />
|
||||||
|
);
|
||||||
|
|
||||||
|
return [ cancelBtn, changeBtn ];
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditCurrent = (event, value) => {
|
||||||
|
this.setState({
|
||||||
|
currentPass: value,
|
||||||
|
showMessage: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditNew = (event, value) => {
|
||||||
|
const repeatValid = value === this.state.repeatNewPass;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
newPass: value,
|
||||||
|
showMessage: false,
|
||||||
|
repeatValid
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditRepeatNew = (event, value) => {
|
||||||
|
const repeatValid = value === this.state.newPass;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
repeatNewPass: value,
|
||||||
|
showMessage: false,
|
||||||
|
repeatValid
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditHint = (event, value) => {
|
||||||
|
this.setState({
|
||||||
|
passwordHint: value,
|
||||||
|
showMessage: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTestActive = () => {
|
||||||
|
this.setState({
|
||||||
|
action: TEST_ACTION,
|
||||||
|
showMessage: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangeActive = () => {
|
||||||
|
this.setState({
|
||||||
|
action: CHANGE_ACTION,
|
||||||
|
showMessage: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTestPassword = () => {
|
||||||
|
const { account } = this.props;
|
||||||
|
const { currentPass } = this.state;
|
||||||
|
|
||||||
|
this.setState({ waiting: true, showMessage: false });
|
||||||
|
|
||||||
|
this.context
|
||||||
|
.api.personal
|
||||||
|
.testPassword(account.address, currentPass)
|
||||||
|
.then(correct => {
|
||||||
|
const message = correct
|
||||||
|
? { value: 'This password is correct', success: true }
|
||||||
|
: { value: 'This password is not correct', success: false };
|
||||||
|
|
||||||
|
this.setState({ waiting: false, message, showMessage: true });
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error('passwordManager::handleTestPassword', e);
|
||||||
|
this.setState({ waiting: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangePassword = () => {
|
||||||
|
const { account } = this.props;
|
||||||
|
const { currentPass, newPass, repeatNewPass, passwordHint } = this.state;
|
||||||
|
|
||||||
|
if (repeatNewPass !== newPass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ waiting: true, showMessage: false });
|
||||||
|
|
||||||
|
this.context
|
||||||
|
.api.personal
|
||||||
|
.testPassword(account.address, currentPass)
|
||||||
|
.then(correct => {
|
||||||
|
if (!correct) {
|
||||||
|
const message = {
|
||||||
|
value: 'This provided current password is not correct',
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setState({ waiting: false, message, showMessage: true });
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = Object.assign({}, account.meta, {
|
||||||
|
passwordHint
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
this.context
|
||||||
|
.api.personal
|
||||||
|
.setAccountMeta(account.address, meta),
|
||||||
|
|
||||||
|
this.context
|
||||||
|
.api.personal
|
||||||
|
.changePassword(account.address, currentPass, newPass)
|
||||||
|
])
|
||||||
|
.then(() => {
|
||||||
|
const message = {
|
||||||
|
value: 'Your password has been successfully changed',
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setState({ waiting: false, message, showMessage: true });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error('passwordManager::handleChangePassword', e);
|
||||||
|
this.setState({ waiting: false });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ import ExecuteContract from './ExecuteContract';
|
|||||||
import FirstRun from './FirstRun';
|
import FirstRun from './FirstRun';
|
||||||
import Shapeshift from './Shapeshift';
|
import Shapeshift from './Shapeshift';
|
||||||
import Transfer from './Transfer';
|
import Transfer from './Transfer';
|
||||||
|
import PasswordManager from './PasswordManager';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
AddAddress,
|
AddAddress,
|
||||||
@ -33,5 +34,6 @@ export {
|
|||||||
ExecuteContract,
|
ExecuteContract,
|
||||||
FirstRun,
|
FirstRun,
|
||||||
Shapeshift,
|
Shapeshift,
|
||||||
Transfer
|
Transfer,
|
||||||
|
PasswordManager
|
||||||
};
|
};
|
||||||
|
@ -44,13 +44,18 @@ export default class Input extends Component {
|
|||||||
onSubmit: PropTypes.func,
|
onSubmit: PropTypes.func,
|
||||||
rows: PropTypes.number,
|
rows: PropTypes.number,
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
|
submitOnBlur: PropTypes.bool,
|
||||||
value: PropTypes.oneOfType([
|
value: PropTypes.oneOfType([
|
||||||
PropTypes.number, PropTypes.string
|
PropTypes.number, PropTypes.string
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
submitOnBlur: true
|
||||||
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: this.props.value
|
value: this.props.value || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (newProps) {
|
componentWillReceiveProps (newProps) {
|
||||||
@ -97,8 +102,11 @@ export default class Input extends Component {
|
|||||||
|
|
||||||
onBlur = (event) => {
|
onBlur = (event) => {
|
||||||
const { value } = event.target;
|
const { value } = event.target;
|
||||||
|
const { submitOnBlur } = this.props;
|
||||||
|
|
||||||
this.onSubmit(value);
|
if (submitOnBlur) {
|
||||||
|
this.onSubmit(value);
|
||||||
|
}
|
||||||
|
|
||||||
this.props.onBlur && this.props.onBlur(event);
|
this.props.onBlur && this.props.onBlur(event);
|
||||||
}
|
}
|
||||||
|
@ -20,15 +20,23 @@ import styles from './form.css';
|
|||||||
|
|
||||||
export default class Form extends Component {
|
export default class Form extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node
|
children: PropTypes.node,
|
||||||
|
className: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
const { className } = this.props;
|
||||||
|
const classes = [ styles.form ];
|
||||||
|
|
||||||
|
if (className) {
|
||||||
|
classes.push(className);
|
||||||
|
}
|
||||||
|
|
||||||
// HACK: hidden inputs to disable Chrome's autocomplete
|
// HACK: hidden inputs to disable Chrome's autocomplete
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
autoComplete='new-password'
|
autoComplete='new-password'
|
||||||
className={ styles.form }>
|
className={ classes.join(' ') }>
|
||||||
<div className={ styles.autofill }>
|
<div className={ styles.autofill }>
|
||||||
<input type='text' name='fakeusernameremembered' />
|
<input type='text' name='fakeusernameremembered' />
|
||||||
<input type='password' name='fakepasswordremembered' />
|
<input type='password' name='fakepasswordremembered' />
|
||||||
|
@ -22,6 +22,7 @@ const defaultName = 'UNNAMED';
|
|||||||
|
|
||||||
class IdentityName extends Component {
|
class IdentityName extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
address: PropTypes.string,
|
address: PropTypes.string,
|
||||||
accountsInfo: PropTypes.object,
|
accountsInfo: PropTypes.object,
|
||||||
tokens: PropTypes.object,
|
tokens: PropTypes.object,
|
||||||
@ -31,7 +32,7 @@ class IdentityName extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { address, accountsInfo, tokens, empty, shorten, unknown } = this.props;
|
const { address, accountsInfo, tokens, empty, shorten, unknown, className } = this.props;
|
||||||
const account = accountsInfo[address] || tokens[address];
|
const account = accountsInfo[address] || tokens[address];
|
||||||
const hasAccount = account && (!account.meta || !account.meta.deleted);
|
const hasAccount = account && (!account.meta || !account.meta.deleted);
|
||||||
|
|
||||||
@ -47,7 +48,9 @@ class IdentityName extends Component {
|
|||||||
: fallback;
|
: fallback;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>{ name && name.length ? name : fallback }</span>
|
<span className={ className }>
|
||||||
|
{ name && name.length ? name : fallback }
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,9 @@ import { connect } from 'react-redux';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import ContentCreate from 'material-ui/svg-icons/content/create';
|
import ContentCreate from 'material-ui/svg-icons/content/create';
|
||||||
import ContentSend from 'material-ui/svg-icons/content/send';
|
import ContentSend from 'material-ui/svg-icons/content/send';
|
||||||
|
import LockIcon from 'material-ui/svg-icons/action/lock';
|
||||||
|
|
||||||
import { EditMeta, Shapeshift, Transfer } from '../../modals';
|
import { EditMeta, Shapeshift, Transfer, PasswordManager } from '../../modals';
|
||||||
import { Actionbar, Button, Page } from '../../ui';
|
import { Actionbar, Button, Page } from '../../ui';
|
||||||
|
|
||||||
import shapeshiftBtn from '../../../assets/images/shapeshift-btn.png';
|
import shapeshiftBtn from '../../../assets/images/shapeshift-btn.png';
|
||||||
@ -44,7 +45,8 @@ class Account extends Component {
|
|||||||
state = {
|
state = {
|
||||||
showEditDialog: false,
|
showEditDialog: false,
|
||||||
showFundDialog: false,
|
showFundDialog: false,
|
||||||
showTransferDialog: false
|
showTransferDialog: false,
|
||||||
|
showPasswordDialog: false
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@ -63,6 +65,7 @@ class Account extends Component {
|
|||||||
{ this.renderEditDialog(account) }
|
{ this.renderEditDialog(account) }
|
||||||
{ this.renderFundDialog() }
|
{ this.renderFundDialog() }
|
||||||
{ this.renderTransferDialog() }
|
{ this.renderTransferDialog() }
|
||||||
|
{ this.renderPasswordDialog() }
|
||||||
{ this.renderActionbar() }
|
{ this.renderActionbar() }
|
||||||
<Page>
|
<Page>
|
||||||
<Header
|
<Header
|
||||||
@ -93,7 +96,12 @@ class Account extends Component {
|
|||||||
key='editmeta'
|
key='editmeta'
|
||||||
icon={ <ContentCreate /> }
|
icon={ <ContentCreate /> }
|
||||||
label='edit'
|
label='edit'
|
||||||
onClick={ this.onEditClick } />
|
onClick={ this.onEditClick } />,
|
||||||
|
<Button
|
||||||
|
key='passwordManager'
|
||||||
|
icon={ <LockIcon /> }
|
||||||
|
label='password'
|
||||||
|
onClick={ this.onPasswordClick } />
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -156,6 +164,24 @@ class Account extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderPasswordDialog () {
|
||||||
|
const { showPasswordDialog } = this.state;
|
||||||
|
|
||||||
|
if (!showPasswordDialog) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { address } = this.props.params;
|
||||||
|
const { accounts } = this.props;
|
||||||
|
const account = accounts[address];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PasswordManager
|
||||||
|
account={ account }
|
||||||
|
onClose={ this.onPasswordClose } />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
onEditClick = () => {
|
onEditClick = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showEditDialog: !this.state.showEditDialog
|
showEditDialog: !this.state.showEditDialog
|
||||||
@ -181,6 +207,16 @@ class Account extends Component {
|
|||||||
onTransferClose = () => {
|
onTransferClose = () => {
|
||||||
this.onTransferClick();
|
this.onTransferClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPasswordClick = () => {
|
||||||
|
this.setState({
|
||||||
|
showPasswordDialog: !this.state.showPasswordDialog
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onPasswordClose = () => {
|
||||||
|
this.onPasswordClick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
|
Loading…
Reference in New Issue
Block a user