Browse Source

Add change password, fix unlocked when you don't have accounts

master
Loëck Vézien 7 years ago
committed by meriadec
parent
commit
2093dfed32
No known key found for this signature in database GPG Key ID: 1D2FC2305E2CB399
  1. 14
      package.json
  2. 4
      src/components/IsUnlocked.js
  3. 56
      src/components/SettingsPage/PasswordModal.js
  4. 2
      src/components/SettingsPage/index.js
  5. 54
      src/components/SettingsPage/sections/Profile.js
  6. 10
      src/components/base/CheckBox/index.js
  7. 35
      src/components/base/InputPassword/index.js
  8. 4
      src/reducers/accounts.js
  9. 54
      yarn.lock

14
package.json

@ -57,7 +57,7 @@
"bs58check": "^2.1.1",
"color": "^3.0.0",
"cross-env": "^5.1.4",
"d3": "^5.0.0",
"d3": "^5.0.1",
"debug": "^3.1.0",
"downshift": "^1.31.7",
"electron-store": "^1.3.0",
@ -74,8 +74,8 @@
"qs": "^6.5.1",
"raven": "^2.5.0",
"raven-js": "^3.24.1",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-flip-ticker": "^0.3.0",
"react-i18next": "^7.6.0",
"react-mortal": "^3.2.0",
@ -92,7 +92,7 @@
"smooth-scrollbar": "^8.2.7",
"source-map": "0.7.2",
"source-map-support": "^0.5.4",
"styled-components": "^3.2.5",
"styled-components": "^3.2.6",
"styled-system": "^2.2.1",
"tippy.js": "^2.5.2",
"ws": "^5.1.1",
@ -117,7 +117,7 @@
"babel-loader": "^8.0.0-beta.2",
"babel-plugin-module-resolver": "^3.1.1",
"babel-plugin-styled-components": "^1.5.0",
"chalk": "^2.3.1",
"chalk": "^2.4.0",
"chance": "^1.0.13",
"concurrently": "^3.5.1",
"dotenv": "^5.0.1",
@ -142,9 +142,9 @@
"js-yaml": "^3.10.0",
"lint-staged": "^7.0.4",
"node-loader": "^0.6.0",
"prettier": "^1.12.0",
"prettier": "^1.12.1",
"react-hot-loader": "^4.0.1",
"react-test-renderer": "^16.3.1",
"react-test-renderer": "^16.3.2",
"webpack": "^4.5.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.0.14",

4
src/components/IsUnlocked.js

@ -25,7 +25,7 @@ import { isLocked, unlock } from 'reducers/application'
import { getCounterValueCode } from 'reducers/settings'
import Box from 'components/base/Box'
import Input from 'components/base/Input'
import InputPassword from 'components/base/InputPassword'
type InputValue = {
password: string,
@ -141,7 +141,7 @@ class IsUnlocked extends Component<Props, State> {
<Box sticky alignItems="center" justifyContent="center" onClick={this.handleFocusInput}>
<form onSubmit={this.handleSubmit}>
<Box>
<Input
<InputPassword
autoFocus
innerRef={(n: any) => (this._input = n)}
placeholder={t('common:password')}

56
src/components/SettingsPage/PasswordModal.js

@ -8,7 +8,7 @@ import { unlock } from 'reducers/application'
import Box from 'components/base/Box'
import Button from 'components/base/Button'
import Input from 'components/base/Input'
import InputPassword from 'components/base/InputPassword'
import Label from 'components/base/Label'
import { Modal, ModalContent, ModalBody, ModalTitle, ModalFooter } from 'components/base/Modal'
@ -30,15 +30,15 @@ type Props = {
type State = {
currentPassword: string,
newPassword: string,
repeatPassword: string,
}
const INITIAL_STATE = {
currentPassword: '',
newPassword: '',
}
class PasswordModal extends PureComponent<Props, State> {
state = {
currentPassword: '',
newPassword: '',
repeatPassword: '',
}
state = INITIAL_STATE
handleSave = (e: SyntheticEvent<HTMLFormElement>) => {
if (e) {
@ -47,32 +47,35 @@ class PasswordModal extends PureComponent<Props, State> {
if (!this.isValid()) {
return
}
const { currentPassword, newPassword, repeatPassword } = this.state
const { currentPassword, newPassword } = this.state
const { isPasswordEnabled, currentPasswordHash, onChangePassword } = this.props
if (isPasswordEnabled) {
const calculatedPasswordHash = bcrypt.hashSync(currentPassword, 8)
if (calculatedPasswordHash !== currentPasswordHash) {
if (!bcrypt.compareSync(currentPassword, currentPasswordHash)) {
return
}
onChangePassword(newPassword)
} else if (newPassword === repeatPassword) {
} else {
onChangePassword(newPassword)
}
}
handleInputChange = key => value => this.setState({ [key]: value })
handleReset = () => this.setState(INITIAL_STATE)
isValid = () => {
const { newPassword, repeatPassword } = this.state
return newPassword && newPassword === repeatPassword
const { newPassword } = this.state
return newPassword
}
render() {
const { t, isPasswordEnabled, onClose, ...props } = this.props
const { currentPassword, newPassword } = this.state
const isValid = this.isValid()
return (
<Modal
{...props}
onHide={this.handleReset}
onClose={onClose}
render={({ onClose }) => (
<form onSubmit={this.handleSave}>
@ -90,35 +93,28 @@ class PasswordModal extends PureComponent<Props, State> {
<Label htmlFor="password">
{t('settings:profile.passwordModalPasswordInput')}
</Label>
<Input
<InputPassword
type="password"
placeholder={t('settings:profile.passwordModalPasswordInput')}
autoFocus
id="password"
onChange={this.handleInputChange('currentPassword')}
value={currentPassword}
/>
</Box>
)}
<Box flow={1}>
<Label htmlFor="newPassword">
{t('settings:profile.passwordModalNewPasswordInput')}
</Label>
<Input
type="password"
{isPasswordEnabled && (
<Label htmlFor="newPassword">
{t('settings:profile.passwordModalNewPasswordInput')}
</Label>
)}
<InputPassword
placeholder={t('settings:profile.passwordModalNewPasswordInput')}
id="newPassword"
onChange={this.handleInputChange('newPassword')}
/>
</Box>
<Box flow={1}>
<Label htmlFor="repeatPassword">
{t('settings:profile.passwordModalRepeatPasswordInput')}
</Label>
<Input
type="password"
placeholder={t('settings:profile.passwordModalRepeatPasswordInput')}
id="repeatPassword"
onChange={this.handleInputChange('repeatPassword')}
value={newPassword}
withStrength
/>
</Box>
</Box>

2
src/components/SettingsPage/index.js

@ -43,7 +43,7 @@ type State = {
class SettingsPage extends PureComponent<Props, State> {
state = {
tab: 2,
tab: 0,
}
_items = []

54
src/components/SettingsPage/sections/Profile.js

@ -7,6 +7,8 @@ import bcrypt from 'bcryptjs'
import type { Settings, T } from 'types/common'
import debounce from 'lodash/debounce'
import { unlock } from 'reducers/application'
import db, { setEncryptionKey } from 'helpers/db'
@ -32,11 +34,13 @@ const mapDispatchToProps = {
type Props = {
t: T,
settings: Settings,
unlock: Function,
saveSettings: Function,
}
type State = {
isHardResetModalOpened: boolean,
isPasswordModalOpened: boolean,
username: string,
}
@ -44,14 +48,29 @@ class TabProfile extends PureComponent<Props, State> {
state = {
username: this.props.settings.username,
isHardResetModalOpened: false,
isPasswordModalOpened: false,
}
setPassword = hash => {
const { saveSettings, unlock } = this.props
setEncryptionKey('accounts', hash)
saveSettings({
password: {
isEnabled: hash !== undefined,
value: hash,
},
})
unlock()
}
debounceSaveUsername = debounce(
v => this.props.saveSettings({ username: v.trim() || 'Anonymous' }),
250,
)
handleChangeUsername = username => {
const { saveSettings } = this.props
this.setState({ username })
window.requestIdleCallback(() => {
saveSettings({ username: username.trim() || 'Anonymous' })
})
this.debounceSaveUsername(username)
}
handleOpenHardResetModal = () => this.setState({ isHardResetModalOpened: true })
@ -69,23 +88,16 @@ class TabProfile extends PureComponent<Props, State> {
if (isChecked) {
this.handleOpenPasswordModal()
} else {
// console.log(`decrypting data`)
this.setPassword(undefined)
}
}
handleChangePassword = (password: ?string) => {
const { saveSettings, unlock } = this.props
const hash = bcrypt.hashSync(password, 8)
setEncryptionKey('accounts', password)
window.requestIdleCallback(() => {
saveSettings({
password: {
isEnabled: hash !== undefined,
value: hash,
},
})
unlock()
})
if (password) {
const hash = bcrypt.hashSync(password, 8)
this.setPassword(hash)
this.handleClosePasswordModal()
}
}
render() {
@ -110,7 +122,11 @@ class TabProfile extends PureComponent<Props, State> {
</Row>
<Row title={t('settings:profile.password')} desc={t('settings:profile.passwordDesc')}>
<Box horizontal flow={2} align="center">
{isPasswordEnabled && <Button>{t('settings:profile.changePassword')}</Button>}
{isPasswordEnabled && (
<Button onClick={this.handleOpenPasswordModal}>
{t('settings:profile.changePassword')}
</Button>
)}
<CheckBox isChecked={isPasswordEnabled} onChange={this.handleChangePasswordCheck} />
</Box>
</Row>
@ -140,7 +156,7 @@ class TabProfile extends PureComponent<Props, State> {
<PasswordModal
t={t}
isOpened={true || isPasswordModalOpened}
isOpened={isPasswordModalOpened}
onClose={this.handleClosePasswordModal}
onChangePassword={this.handleChangePassword}
isPasswordEnabled={isPasswordEnabled}

10
src/components/base/CheckBox/index.js

@ -7,14 +7,14 @@ import styled from 'styled-components'
import { Tabbable } from 'components/base/Box'
const Base = styled(Tabbable).attrs({
bg: p => (p.isChecked ? 'wallet' : 'fog'),
bg: p => (p.isChecked ? 'wallet' : 'lightFog'),
horizontal: true,
align: 'center',
})`
backround: red;
width: 50px;
height: 24px;
border-radius: 16px;
height: 26px;
border-radius: 13px;
transition: 250ms linear background-color;
cursor: pointer;
&:focus {
@ -28,9 +28,9 @@ const Ball = styled.div`
height: 20px;
border-radius: 50%;
background: white;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.15);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2);
transition: 250ms ease-in-out transform;
transform: translate3d(${p => (p.isChecked ? '28px' : '2px')}, 0, 0);
transform: translate3d(${p => (p.isChecked ? '27px' : '3px')}, 0, 0);
`
type Props = {

35
src/components/base/InputPassword/index.js

@ -1,6 +1,6 @@
// @flow
import React, { PureComponent } from 'react'
import React, { Fragment, PureComponent } from 'react'
import styled from 'styled-components'
import { translate } from 'react-i18next'
import zxcvbn from 'zxcvbn'
@ -50,6 +50,7 @@ type Props = {
onChange: Function,
t: T,
value: string,
withStrength: boolean,
}
class InputPassword extends PureComponent<Props, State> {
@ -84,7 +85,7 @@ class InputPassword extends PureComponent<Props, State> {
}
render() {
const { t, value, maxLength } = this.props
const { t, value, maxLength, withStrength } = this.props
const { passwordStrength, inputType } = this.state
const hasValue = value.trim() !== ''
@ -102,19 +103,23 @@ class InputPassword extends PureComponent<Props, State> {
</InputRight>
}
/>
<Box flow={1} horizontal>
{[0, 1, 2, 3, 4].map(v => (
<Strength
key={v}
warning={passwordStrength <= 1}
activated={hasValue && passwordStrength >= v}
/>
))}
</Box>
{hasValue && (
<Warning passwordStrength={passwordStrength}>
{t(`password:warning_${passwordStrength}`)}
</Warning>
{withStrength && (
<Fragment>
<Box flow={1} horizontal>
{[0, 1, 2, 3, 4].map(v => (
<Strength
key={v}
warning={passwordStrength <= 1}
activated={hasValue && passwordStrength >= v}
/>
))}
</Box>
{hasValue && (
<Warning passwordStrength={passwordStrength}>
{t(`password:warning_${passwordStrength}`)}
</Warning>
)}
</Fragment>
)}
</Box>
)

4
src/reducers/accounts.js

@ -94,10 +94,10 @@ export function canCreateAccount(state: State): boolean {
// such a simple thing, let's put any, right? I don't care.
export function serializeAccounts(accounts: any): Account[] {
// ensure that accounts are always wrapped in data key
if (accounts.length && !accounts[0].data) {
if (accounts && accounts.length && !accounts[0].data) {
accounts = accounts.map(account => ({ data: account }))
}
return accounts.map(accountModel.decode)
return accounts ? accounts.map(accountModel.decode) : []
}
export function deserializeAccounts(accounts: Account[]) {

54
yarn.lock

@ -3362,6 +3362,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52"
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
@ -4321,9 +4329,9 @@ d3-zoom@1:
d3-selection "1"
d3-transition "1"
d3@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/d3/-/d3-5.0.0.tgz#b373ce8ccc953cbe09cef4c1e7e2223b42441df9"
d3@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/d3/-/d3-5.0.1.tgz#c74743964deff2eedf2a10e6119fbeb77825af7a"
dependencies:
d3-array "1"
d3-axis "1"
@ -8013,6 +8021,9 @@ ledger-test-library@KhalilBellakrid/ledger-test-library-nodejs#7d37482:
dependencies:
axios "^0.17.1"
bindings "^1.3.0"
electron "^1.8.2"
electron-builder "^20.0.4"
electron-rebuild "^1.7.3"
nan "^2.6.2"
prebuild-install "^2.2.2"
@ -9792,9 +9803,9 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
prettier@^1.12.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.0.tgz#d26fc5894b9230de97629b39cae225b503724ce8"
prettier@^1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325"
prettier@^1.5.3:
version "1.11.1"
@ -10132,9 +10143,9 @@ react-docgen@^3.0.0-beta11:
node-dir "^0.1.10"
recast "^0.12.6"
react-dom@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.1.tgz#6a3c90a4fb62f915bdbcf6204422d93a7d4ca573"
react-dom@^16.3.2:
version "16.3.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.2.tgz#cb90f107e09536d683d84ed5d4888e9640e0e4df"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
@ -10205,6 +10216,10 @@ react-is@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.1.tgz#ee66e6d8283224a83b3030e110056798488359ba"
react-is@^16.3.2:
version "16.3.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22"
react-modal@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.3.2.tgz#b13da9490653a7c76bc0e9600323eb1079c620e7"
@ -10308,14 +10323,14 @@ react-style-proptype@^3.0.0:
dependencies:
prop-types "^15.5.4"
react-test-renderer@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.1.tgz#d9257936d8535bd40f57f3d5a84e7b0452fb17f2"
react-test-renderer@^16.3.2:
version "16.3.2"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.2.tgz#3d1ed74fda8db42521fdf03328e933312214749a"
dependencies:
fbjs "^0.8.16"
object-assign "^4.1.1"
prop-types "^15.6.0"
react-is "^16.3.1"
react-is "^16.3.2"
react-textarea-autosize@^5.2.1:
version "5.2.1"
@ -10353,9 +10368,9 @@ react@^16.0.0, react@^16.2.0:
object-assign "^4.1.1"
prop-types "^15.6.0"
react@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react/-/react-16.3.1.tgz#4a2da433d471251c69b6033ada30e2ed1202cfd8"
react@^16.3.2:
version "16.3.2"
resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
@ -11704,9 +11719,9 @@ style-loader@^0.20.3:
loader-utils "^1.1.0"
schema-utils "^0.4.5"
styled-components@^3.2.5:
version "3.2.5"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.2.5.tgz#b5d5d7d618ab240ff10602b5ca5886b8db3d0a0d"
styled-components@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.2.6.tgz#99e6e75a746bdedd295a17e03dd1493055a1cc3b"
dependencies:
buffer "^5.0.3"
css-to-react-native "^2.0.3"
@ -11714,6 +11729,7 @@ styled-components@^3.2.5:
hoist-non-react-statics "^2.5.0"
is-plain-object "^2.0.1"
prop-types "^15.5.4"
react-is "^16.3.1"
stylis "^3.5.0"
stylis-rule-sheet "^0.0.10"
supports-color "^3.2.3"

Loading…
Cancel
Save