From e933100867d80d9724dc4a4efd9da5f2bd68c374 Mon Sep 17 00:00:00 2001 From: agix Date: Mon, 28 Aug 2017 18:12:13 +0200 Subject: [PATCH 1/5] Add form to change master password in settings --- src/actions/OptionsActions.js | 20 ++++++++- src/components/options/OptionsContainer.js | 49 +++++++++++++++++++++- src/stores/OptionsStore.js | 44 +++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/actions/OptionsActions.js b/src/actions/OptionsActions.js index 2e22337..56a2aa7 100644 --- a/src/actions/OptionsActions.js +++ b/src/actions/OptionsActions.js @@ -24,7 +24,11 @@ class OptionsActions { 'changeDelaySuccess', 'changeDelayFailure', 'showRescueCodesSuccess', - 'hideRescueCodes' + 'hideRescueCodes', + 'changeNewPass1', + 'changeNewPass2', + 'changePasswordSuccess', + 'changePasswordFailure' ); } @@ -93,6 +97,20 @@ class OptionsActions { }; } + changePassword({ newPass }) { + return dispatch => { + dispatch(); + secretin + .changePassword(newPass) + .then(() => { + this.changePasswordSuccess(); + }) + .catch(() => { + this.changePasswordFailure(); + }); + }; + } + toggleTotp({ checked }) { if (checked) { return true; diff --git a/src/components/options/OptionsContainer.js b/src/components/options/OptionsContainer.js index eddc698..c2f089a 100644 --- a/src/components/options/OptionsContainer.js +++ b/src/components/options/OptionsContainer.js @@ -20,6 +20,7 @@ import OptionsStore from 'stores/OptionsStore'; class OptionsContainer extends Component { static propTypes = { options: PropTypes.instanceOf(Immutable.Map), + newPass: PropTypes.instanceOf(Immutable.Map), }; static getStores() { @@ -29,18 +30,31 @@ class OptionsContainer extends Component { static getPropsFromStores() { return { options: OptionsStore.getOptions(), + newPass: OptionsStore.getNewPass(), }; } + constructor(props) { + super(props); + + this.onChangePassword = this.onChangePassword.bind(this); + } + onChangeTimeToClose({ value }) { OptionsActions.changeTimeToClose({ timeToClose: parseInt(value, 10) || 0, }); } + onChangePassword() { + OptionsActions.changePassword({ + newPass: this.props.newPass.toJS().newPass1, + }); + } + render() { const { options } = this.props; - + const { newPass1, newPass2, loading } = this.props.newPass.toJS(); return (
@@ -117,6 +131,39 @@ class OptionsContainer extends Component {
}
+
+
+
+ + {newPass1.length > 0 && + } +
+ {newPass1.length > 0 && + newPass1 === newPass2 && + } +
+

Imports

diff --git a/src/stores/OptionsStore.js b/src/stores/OptionsStore.js index cbc28c5..e6b858e 100644 --- a/src/stores/OptionsStore.js +++ b/src/stores/OptionsStore.js @@ -11,6 +11,12 @@ const OptionsState = new Record({ showQRCode: false, showShortLogin: false, showRescueCodes: false, + newPass: new Immutable.Map({ + newPass1: '', + newPass2: '', + error: '', + loading: false, + }), rescueCodes: new Immutable.List(), loading: false, import: Immutable.fromJS({ @@ -175,6 +181,40 @@ class OptionsStore { this.setState(this.state.setIn(['options', 'timeToClose'], timeToClose)); } + onChangeNewPass1(newPass1) { + this.setState(this.state.setIn(['newPass', 'newPass1'], newPass1.value)); + } + + onChangeNewPass2(newPass2) { + this.setState(this.state.setIn(['newPass', 'newPass2'], newPass2.value)); + } + + onChangePassword() { + this.setState( + this.state + .setIn(['newPass', 'loading'], true) + .setIn(['newPass', 'error'], '') + ); + } + + onChangePasswordSuccess() { + this.setState( + this.state + .setIn(['newPass', 'newPass1'], '') + .setIn(['newPass', 'newPass2'], '') + .setIn(['newPass', 'error'], '') + .setIn(['newPass', 'loading'], false) + ); + } + + onChangePasswordFailure() { + this.setState( + this.state + .setIn(['newPass', 'error'], 'Password change failed') + .setIn(['newPass', 'loading'], false) + ); + } + onShowRescueCodesSuccess({ rescueCodes }) { this.setState( this.state.merge({ @@ -196,6 +236,10 @@ class OptionsStore { static getOptions() { return this.getState().get('options'); } + + static getNewPass() { + return this.getState().get('newPass'); + } } export default alt.createStore(makeImmutable(OptionsStore), 'OptionsStore'); From 14726ca302e8bbe54e39ab494bade0fd581c7c66 Mon Sep 17 00:00:00 2001 From: agix Date: Mon, 28 Aug 2017 18:52:46 +0200 Subject: [PATCH 2/5] Put change password in modal --- src/actions/OptionsActions.js | 2 + src/components/options/ChangePasswordShow.js | 128 +++++++++++++++++++ src/components/options/OptionsContainer.js | 53 ++------ src/stores/OptionsStore.js | 23 ++++ 4 files changed, 163 insertions(+), 43 deletions(-) create mode 100644 src/components/options/ChangePasswordShow.js diff --git a/src/actions/OptionsActions.js b/src/actions/OptionsActions.js index 56a2aa7..af5289d 100644 --- a/src/actions/OptionsActions.js +++ b/src/actions/OptionsActions.js @@ -16,6 +16,8 @@ class OptionsActions { 'deactivateShortLoginFailure', 'showImportKeepass', 'hideImportKeepass', + 'showChangePassword', + 'hideChangePassword', 'importKeepassProgress', 'importKeepassSuccess', 'importKeepassFailure', diff --git a/src/components/options/ChangePasswordShow.js b/src/components/options/ChangePasswordShow.js new file mode 100644 index 0000000..4817f24 --- /dev/null +++ b/src/components/options/ChangePasswordShow.js @@ -0,0 +1,128 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import connectToStores from 'alt-utils/lib/connectToStores'; + +import Modal from 'components/utilities/Modal'; +import Button from 'components/utilities/Button'; +import Input from 'components/utilities/Input'; + +import OptionsStore from 'stores/OptionsStore'; +import OptionsActions from 'actions/OptionsActions'; + +class ChangePasswordShow extends Component { + static propTypes = { + shown: PropTypes.bool, + loading: PropTypes.bool, + error: PropTypes.string, + newPass1: PropTypes.string, + newPass2: PropTypes.string, + }; + + static defaultProps = { + shown: false, + loading: false, + newPass1: '', + newPass2: '', + error: '', + }; + + static getStores() { + return [OptionsStore]; + } + + static getPropsFromStores() { + const state = OptionsStore.getNewPass(); + + return { + errors: state.get('error'), + shown: state.get('shown'), + loading: state.get('loading'), + newPass1: state.get('newPass1'), + newPass2: state.get('newPass2'), + }; + } + + constructor(props) { + super(props); + + this.state = { + success: false, + }; + this.handleChangePassword = this.handleChangePassword.bind(this); + } + + handleChangePassword() { + OptionsActions.changePassword({ + newPass: this.props.newPass1, + }); + } + + componentWillReceiveProps(nextProps) { + if (this.props.loading && !nextProps.loading && nextProps.error === '') { + this.setState({ + success: true, + }); + setTimeout(() => { + this.setState({ + success: false, + }); + }, 1000); + } + } + + render() { + return ( + + + Change master password + + + + + {this.props.newPass1.length > 0 && + } + {this.state.success &&
Success
} +
+ + + + {this.props.newPass1.length > 0 && + this.props.newPass1 === this.props.newPass2 && + } + +
+ ); + } +} + +export default connectToStores(ChangePasswordShow); diff --git a/src/components/options/OptionsContainer.js b/src/components/options/OptionsContainer.js index c2f089a..ed1da22 100644 --- a/src/components/options/OptionsContainer.js +++ b/src/components/options/OptionsContainer.js @@ -8,6 +8,7 @@ import ShortLoginShow from 'components/options/ShortLoginShow'; import QRCodeShow from 'components/options/QRCodeShow'; import RescueCodesShow from 'components/options/RescueCodesShow'; import ImportKeepassShow from 'components/options/ImportKeepassShow'; +import ChangePasswordShow from 'components/options/ChangePasswordShow'; import Title from 'components/utilities/Title'; import Checkbox from 'components/utilities/Checkbox'; import Input from 'components/utilities/Input'; @@ -30,31 +31,17 @@ class OptionsContainer extends Component { static getPropsFromStores() { return { options: OptionsStore.getOptions(), - newPass: OptionsStore.getNewPass(), }; } - constructor(props) { - super(props); - - this.onChangePassword = this.onChangePassword.bind(this); - } - onChangeTimeToClose({ value }) { OptionsActions.changeTimeToClose({ timeToClose: parseInt(value, 10) || 0, }); } - onChangePassword() { - OptionsActions.changePassword({ - newPass: this.props.newPass.toJS().newPass1, - }); - } - render() { const { options } = this.props; - const { newPass1, newPass2, loading } = this.props.newPass.toJS(); return (
@@ -133,35 +120,15 @@ class OptionsContainer extends Component {
-
- - {newPass1.length > 0 && - } -
- {newPass1.length > 0 && - newPass1 === newPass2 && - } + +
diff --git a/src/stores/OptionsStore.js b/src/stores/OptionsStore.js index e6b858e..587e5b5 100644 --- a/src/stores/OptionsStore.js +++ b/src/stores/OptionsStore.js @@ -12,6 +12,7 @@ const OptionsState = new Record({ showShortLogin: false, showRescueCodes: false, newPass: new Immutable.Map({ + shown: false, newPass1: '', newPass2: '', error: '', @@ -189,6 +190,28 @@ class OptionsStore { this.setState(this.state.setIn(['newPass', 'newPass2'], newPass2.value)); } + onShowChangePassword() { + this.setState( + this.state + .setIn(['newPass', 'newPass1'], '') + .setIn(['newPass', 'newPass2'], '') + .setIn(['newPass', 'error'], '') + .setIn(['newPass', 'loading'], false) + .setIn(['newPass', 'shown'], true) + ); + } + + onHideChangePassword() { + this.setState( + this.state + .setIn(['newPass', 'newPass1'], '') + .setIn(['newPass', 'newPass2'], '') + .setIn(['newPass', 'error'], '') + .setIn(['newPass', 'loading'], false) + .setIn(['newPass', 'shown'], false) + ); + } + onChangePassword() { this.setState( this.state From 7f4de47e5868ea424984b6751f3a5a3df642b0f0 Mon Sep 17 00:00:00 2001 From: agix Date: Tue, 29 Aug 2017 12:27:41 +0200 Subject: [PATCH 3/5] Missing css --- src/components/options/ChangePasswordShow.js | 30 ++++++++++++------- src/components/options/OptionsContainer.js | 2 +- src/components/utilities/Button.js | 8 ++++- src/stylesheets/application.sass | 1 + .../components/options/ChangePassword.sass | 2 ++ .../components/utilities/Button.sass | 11 ++++++- 6 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 src/stylesheets/components/options/ChangePassword.sass diff --git a/src/components/options/ChangePasswordShow.js b/src/components/options/ChangePasswordShow.js index 4817f24..d88901e 100644 --- a/src/components/options/ChangePasswordShow.js +++ b/src/components/options/ChangePasswordShow.js @@ -90,15 +90,24 @@ class ChangePasswordShow extends Component { disabled={this.props.loading} /> {this.props.newPass1.length > 0 && - } - {this.state.success &&
Success
} + + + } +
+ {!this.state.success && + this.props.newPass1.length > 0 && + this.props.newPass1 !== this.props.newPass2 && + 'Passwords mismatch'} + {this.state.success && 'Success'} + {this.props.error !== '' && this.props.error} +
@@ -110,12 +119,11 @@ class ChangePasswordShow extends Component { Close {this.props.newPass1.length > 0 && - this.props.newPass1 === this.props.newPass2 && } diff --git a/src/components/options/OptionsContainer.js b/src/components/options/OptionsContainer.js index ed1da22..78965a9 100644 --- a/src/components/options/OptionsContainer.js +++ b/src/components/options/OptionsContainer.js @@ -123,7 +123,7 @@ class OptionsContainer extends Component {
-
-

Imports

-
- - -
-
);