Browse Source

Merge pull request #1409 from juan-cortes/auto-lock

Added Auto-Lock functionality
gre-patch-1
Gaëtan Renaudeau 6 years ago
committed by GitHub
parent
commit
2b43c669a1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/actions/settings.js
  2. 66
      src/components/Idler.js
  3. 63
      src/components/SettingsPage/PasswordAutoLockSelect.js
  4. 23
      src/components/SettingsPage/sections/Display.js
  5. 2
      src/components/layout/Default.js
  6. 3
      src/reducers/settings.js
  7. 8
      static/i18n/en/app.json

1
src/actions/settings.js

@ -15,6 +15,7 @@ export const setDeveloperMode = (developerMode: boolean) => saveSettings({ devel
export const setSentryLogs = (sentryLogs: boolean) => saveSettings({ sentryLogs })
export const setShareAnalytics = (shareAnalytics: boolean) => saveSettings({ shareAnalytics })
export const setMarketIndicator = (marketIndicator: *) => saveSettings({ marketIndicator })
export const setAutoLockTimeout = (autoLockTimeout: *) => saveSettings({ autoLockTimeout })
export const setCounterValue = (counterValue: string) =>
saveSettings({
counterValue,

66
src/components/Idler.js

@ -0,0 +1,66 @@
// @flow
import { PureComponent } from 'react'
import { createStructuredSelector } from 'reselect'
import { connect } from 'react-redux'
import { hasPasswordSelector, autoLockTimeoutSelector } from 'reducers/settings'
import debounce from 'lodash/debounce'
import { lock } from 'reducers/application'
type Props = {
autoLockTimeout: number,
hasPassword: boolean,
lock: Function,
}
const mapStateToProps = createStructuredSelector({
autoLockTimeout: autoLockTimeoutSelector,
hasPassword: hasPasswordSelector,
})
const mapDispatchToProps = {
lock,
}
class Idler extends PureComponent<Props> {
componentDidMount() {
window.addEventListener('keydown', this.debounceOnChange)
window.addEventListener('mouseover', this.debounceOnChange)
this.interval = setInterval(this.checkForAutoLock, 10000)
}
componentWillUnmount() {
window.removeEventListener('keydown', this.debounceOnChange)
window.removeEventListener('mouseover', this.debounceOnChange)
clearInterval(this.interval)
this.debounceOnChange.cancel()
}
interval: IntervalID
lastAction: number = -1
debounceOnChange = debounce(_ => this.idleTimeHandler(), 1000)
checkForAutoLock = _ => {
const timeout = this.props.autoLockTimeout
if (this.props.hasPassword && timeout && timeout !== -1) {
if (Date.now() - (this.lastAction + timeout * 60000) > 0) {
this.props.lock()
}
}
}
idleTimeHandler = _ => {
this.lastAction = Date.now()
}
render() {
return null
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(Idler)

63
src/components/SettingsPage/PasswordAutoLockSelect.js

@ -0,0 +1,63 @@
// @flow
import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import { createStructuredSelector } from 'reselect'
import { connect } from 'react-redux'
import { setAutoLockTimeout, saveSettings } from 'actions/settings'
import Select from 'components/base/Select'
import type { T } from 'types/common'
import { autoLockTimeoutSelector } from 'reducers/settings'
type Props = {
autoLockTimeout: string,
setAutoLockTimeout: (?number) => void,
t: T,
}
const mapStateToProps = createStructuredSelector({
autoLockTimeout: autoLockTimeoutSelector,
})
const mapDispatchToProps = {
saveSettings,
setAutoLockTimeout,
}
class PasswordAutoLockSelect extends PureComponent<Props> {
handleChangeTimeout = ({ value: timeoutKey }: *) => {
this.props.setAutoLockTimeout(+timeoutKey)
}
timeouts = [
{ value: 1, label: `1 ${this.props.t('app:time.minute')}` },
{ value: 10, label: `10 ${this.props.t('app:time.minute')}s` },
{ value: 30, label: `30 ${this.props.t('app:time.minute')}s` },
{ value: 60, label: `1 ${this.props.t('app:time.hour')}` },
{ value: -1, label: this.props.t(`app:common.never`) },
]
render() {
const { autoLockTimeout } = this.props
const currentTimeout = this.timeouts.find(l => l.value === autoLockTimeout)
return (
<Select
small
minWidth={250}
isSearchable={false}
onChange={this.handleChangeTimeout}
renderSelected={item => item && item.name}
value={currentTimeout}
options={this.timeouts}
/>
)
}
}
export default translate()(
connect(
mapStateToProps,
mapDispatchToProps,
)(PasswordAutoLockSelect),
)

23
src/components/SettingsPage/sections/Display.js

@ -4,7 +4,11 @@ import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import { connect } from 'react-redux'
import { createSelector } from 'reselect'
import { langAndRegionSelector, counterValueCurrencySelector } from 'reducers/settings'
import {
hasPasswordSelector,
langAndRegionSelector,
counterValueCurrencySelector,
} from 'reducers/settings'
import type { Currency } from '@ledgerhq/live-common/lib/types'
import type { T } from 'types/common'
import { EXPERIMENTAL_MARKET_INDICATOR_SETTINGS } from 'config/constants'
@ -17,6 +21,7 @@ import CounterValueSelect from '../CounterValueSelect'
import CounterValueExchangeSelect from '../CounterValueExchangeSelect'
import RegionSelect from '../RegionSelect'
import PasswordButton from '../PasswordButton'
import PasswordAutoLockSelect from '../PasswordAutoLockSelect'
import DevModeButton from '../DevModeButton'
import SentryLogsButton from '../SentryLogsButton'
import ShareAnalyticsButton from '../ShareAnalyticsButton'
@ -32,11 +37,12 @@ type Props = {
t: T,
counterValueCurrency: Currency,
useSystem: boolean,
hasPassword: boolean,
}
class TabGeneral extends PureComponent<Props> {
render() {
const { t, useSystem, counterValueCurrency } = this.props
const { t, useSystem, counterValueCurrency, hasPassword } = this.props
return (
<Section>
@ -83,6 +89,14 @@ class TabGeneral extends PureComponent<Props> {
<Row title={t('settings.profile.password')} desc={t('settings.profile.passwordDesc')}>
<PasswordButton />
</Row>
{hasPassword ? (
<Row
title={t('app:settings.profile.passwordAutoLock')}
desc={t('app:settings.profile.passwordAutoLockDesc')}
>
<PasswordAutoLockSelect />
</Row>
) : null}
<Row
title={t('settings.profile.reportErrors')}
desc={t('settings.profile.reportErrorsDesc')}
@ -109,10 +123,13 @@ export default translate()(
createSelector(
langAndRegionSelector,
counterValueCurrencySelector,
({ useSystem }, counterValueCurrency) => ({
hasPasswordSelector,
({ useSystem }, counterValueCurrency, hasPassword) => ({
useSystem,
counterValueCurrency,
hasPassword,
}),
),
null,
)(TabGeneral),
)

2
src/components/layout/Default.js

@ -14,6 +14,7 @@ import * as modals from 'components/modals'
import Box from 'components/base/Box'
import GrowScroll from 'components/base/GrowScroll'
import Track from 'analytics/Track'
import Idler from 'components/Idler'
import AccountPage from 'components/AccountPage'
import DashboardPage from 'components/DashboardPage'
@ -88,6 +89,7 @@ class Default extends Component<Props> {
{process.platform === 'darwin' && <AppRegionDrag />}
<ExportLogsBtn hookToShortcut />
<Track mandatory onMount event="App Starts" />
<Idler />
<IsUnlocked>
<OnboardingOrElse>

3
src/reducers/settings.js

@ -38,6 +38,7 @@ export type SettingsState = {
region: ?string,
orderAccounts: string,
hasPassword: boolean,
autoLockTimeout: number,
selectedTimeRange: TimeRange,
marketIndicator: 'eastern' | 'western',
currenciesSettings: {
@ -66,6 +67,7 @@ const INITIAL_STATE: SettingsState = {
region: null,
orderAccounts: 'balance|asc',
hasPassword: false,
autoLockTimeout: 10,
selectedTimeRange: 'month',
marketIndicator: 'western',
currenciesSettings: {},
@ -229,6 +231,7 @@ export const exchangeSettingsForAccountSelector: ESFAS = createSelector(
export const marketIndicatorSelector = (state: State) => state.settings.marketIndicator
export const sentryLogsSelector = (state: State) => state.settings.sentryLogs
export const autoLockTimeoutSelector = (state: State) => state.settings.autoLockTimeout
export const shareAnalyticsSelector = (state: State) => state.settings.shareAnalytics
export const selectedTimeRangeSelector = (state: State) => state.settings.selectedTimeRange
export const hasCompletedOnboardingSelector = (state: State) =>

8
static/i18n/en/app.json

@ -2,6 +2,7 @@
"common": {
"labelYes": "Yes",
"labelNo": "No",
"never": "Never",
"apply": "Apply",
"confirm": "Confirm",
"cancel": "Cancel",
@ -67,6 +68,9 @@
"week": "Week",
"month": "Month",
"year": "Year",
"minute": "Minute",
"second": "Second",
"hour": "Hour",
"since": {
"day": "past day",
"week": "past week",
@ -383,7 +387,9 @@
},
"profile": {
"password": "Password lock",
"passwordDesc": "Set a password to prevent unauthorized access to Ledger Live data stored on your computer, including account names, transactions and public addresses.",
"passwordDesc": "Set a password to prevent unauthorized access to Ledger Live data stored on your computer, including account names, balances, transactions and public addresses.",
"passwordAutoLock": "Auto-lock",
"passwordAutoLockDesc": "Optional, how long should the app be idle before it locks itself.",
"changePassword": "Change password",
"softResetTitle": "Clear cache",
"softResetDesc": "Clear the Ledger Live cache to force resynchronization with the blockchain.",

Loading…
Cancel
Save