Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

feat(app): basic password authentication #2860

Closed
wants to merge 12 commits into from
5 changes: 5 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ module.exports = {
interval: 60 * 60 * 1000,
},

password: {
active: false,
value: null,
},

// Supported chains.
chains: ['bitcoin', 'litecoin'],

Expand Down
10 changes: 9 additions & 1 deletion renderer/components/Form/Field.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Flex } from 'rebass/styled-components'
import { Box, Flex } from 'rebass/styled-components'
import { Message, Text } from 'components/UI'
import Label from './Label'

Expand All @@ -10,6 +10,7 @@ const Field = ({
error,
field,
hasFocus,
hasMessageSpacer,
isDisabled,
isReadOnly,
isRequired,
Expand Down Expand Up @@ -40,6 +41,12 @@ const Field = ({
{error}
</Message>
)}

{hasMessageSpacer && !error && (
<Box fontSize="s" fontWeight="normal" height="16px" mt={1}>
&nbsp;
</Box>
)}
</Flex>
)

Expand All @@ -49,6 +56,7 @@ Field.propTypes = {
error: PropTypes.node,
field: PropTypes.string.isRequired,
hasFocus: PropTypes.bool,
hasMessageSpacer: PropTypes.bool,
isDisabled: PropTypes.bool,
isReadOnly: PropTypes.bool,
isRequired: PropTypes.bool,
Expand Down
3 changes: 3 additions & 0 deletions renderer/components/Form/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const Input = props => {
fieldState,
forwardedRef,
hasMessage,
hasMessageSpacer,
initialValue,
isDisabled,
isReadOnly,
Expand Down Expand Up @@ -67,6 +68,7 @@ const Input = props => {
error={fieldError}
field={field}
hasFocus={hasFocus}
hasMessageSpacer={hasMessageSpacer}
isDisabled={isDisabled}
isReadOnly={isReadOnly}
isRequired={isRequired}
Expand Down Expand Up @@ -132,6 +134,7 @@ Input.propTypes = {
fieldState: PropTypes.object.isRequired,
forwardedRef: PropTypes.object,
hasMessage: PropTypes.bool,
hasMessageSpacer: PropTypes.bool,
highlightOnValid: PropTypes.bool,
initialValue: PropTypes.string,
isDisabled: PropTypes.bool,
Expand Down
71 changes: 71 additions & 0 deletions renderer/components/Login/Login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useEffect, useRef } from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage } from 'react-intl'
import { Flex } from 'rebass/styled-components'
import { Button, CenteredContent, Message, Text } from 'components/UI'
import { Form, PasswordInput } from 'components/Form'
import ArrowRight from 'components/Icon/ArrowRight'
import ZapLogo from 'components/Icon/ZapLogo'
import messages from './messages'

const Login = ({ login, loginError, clearLoginError, ...rest }) => {
const formApiRef = useRef(null)

useEffect(() => {
const { current: formApi } = formApiRef
if (loginError) {
formApi.setFormError(loginError)
clearLoginError()
}
}, [loginError, formApiRef, clearLoginError])

const handleSubmit = ({ password }) => login(password)

return (
<Form getApi={api => (formApiRef.current = api)} onSubmit={handleSubmit} width={1}>
{({ formState: { submits, error } }) => {
const willValidateInline = submits > 0
return (
<CenteredContent {...rest} mx="auto" width={11 / 16}>
<Flex alignItems="center" flexDirection="column" px={0} width={5 / 8} {...rest}>
<Flex justifyContent="center" mb={4}>
<ZapLogo height={34} width={34} />
</Flex>
<Text mb={4} textAlign="center">
<FormattedMessage {...messages.intro} />
</Text>
{error && (
<Message mb={3} variant="error">
{error}
</Message>
)}
<Flex alignItems="flex-start" width={1}>
<PasswordInput
field="password"
hasMessageSpacer
isRequired
ml={5}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
width={1}
willAutoFocus
/>
<Button ml={2} px={3} type="submit">
<ArrowRight />
</Button>
</Flex>
</Flex>
</CenteredContent>
)
}}
</Form>
)
}

Login.propTypes = {
clearLoginError: PropTypes.func.isRequired,
login: PropTypes.func.isRequired,
loginError: PropTypes.string,
}

export default Login
3 changes: 3 additions & 0 deletions renderer/components/Login/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Login from './Login'

export default Login
6 changes: 6 additions & 0 deletions renderer/components/Login/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineMessages } from 'react-intl'

/* eslint-disable max-len */
export default defineMessages({
intro: 'Enter your password to continue.',
})
10 changes: 5 additions & 5 deletions renderer/components/Onboarding/Steps/ConnectionDetailsManual.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class ConnectionDetailsManual extends React.Component {
onSubmitFailure={onSubmitFailure}
>
{({ formState }) => {
const shouldValidateInline =
const willValidateInline =
formState.submits > 0 ||
connectionHost ||
connectionCert ||
Expand Down Expand Up @@ -199,8 +199,8 @@ class ConnectionDetailsManual extends React.Component {
mb={3}
name="connectionCert"
onBlur={this.validateCert}
validateOnBlur={shouldValidateInline}
validateOnChange={shouldValidateInline}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
width={1}
/>

Expand All @@ -212,8 +212,8 @@ class ConnectionDetailsManual extends React.Component {
label="Macaroon"
name="connectionMacaroon"
onBlur={this.validateMacaroon}
validateOnBlur={shouldValidateInline}
validateOnChange={shouldValidateInline}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
width={1}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class ConnectionDetailsString extends React.Component {
onSubmitFailure={onSubmitFailure}
>
{({ formState }) => {
const shouldValidateInline =
const willValidateInline =
formState.submits > 0 ||
connectionString ||
startLndHostError ||
Expand Down Expand Up @@ -157,8 +157,8 @@ class ConnectionDetailsString extends React.Component {
initialValue={connectionString}
isRequired
rows="12"
validateOnBlur={shouldValidateInline}
validateOnChange={shouldValidateInline}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
willAutoFocus
/>
</>
Expand Down
6 changes: 3 additions & 3 deletions renderer/components/Onboarding/Steps/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class Login extends React.Component {
onSubmitFailure={onSubmitFailure}
>
{({ formState }) => {
const shouldValidateInline = formState.submits > 0
const willValidateInline = formState.submits > 0
return (
<>
<Header
Expand All @@ -96,8 +96,8 @@ class Login extends React.Component {
label={<FormattedMessage {...messages.password_label} />}
minLength={8}
placeholder={intl.formatMessage({ ...messages.password_placeholder })}
validateOnBlur={shouldValidateInline}
validateOnChange={shouldValidateInline}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
willAutoFocus
/>
</Box>
Expand Down
6 changes: 3 additions & 3 deletions renderer/components/Onboarding/Steps/Name.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class Name extends React.Component {
onSubmitFailure={onSubmitFailure}
>
{({ formState }) => {
const shouldValidateInline = formState.submits > 0
const willValidateInline = formState.submits > 0
return (
<>
<Header
Expand All @@ -70,8 +70,8 @@ class Name extends React.Component {
label={<FormattedMessage {...messages.wallet_name_label} />}
maxLength={30}
name="name"
validateOnBlur={shouldValidateInline}
validateOnChange={shouldValidateInline}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
willAutoFocus
/>
</Box>
Expand Down
6 changes: 3 additions & 3 deletions renderer/components/Onboarding/Steps/Password.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Password extends React.Component {
onSubmitFailure={onSubmitFailure}
>
{({ formState }) => {
const shouldValidateInline = formState.submits > 0
const willValidateInline = formState.submits > 0
return (
<>
<Header
Expand All @@ -71,8 +71,8 @@ class Password extends React.Component {
label={<FormattedMessage {...messages.password_label} />}
minLength={8}
placeholder={intl.formatMessage({ ...messages.password_placeholder })}
validateOnBlur={shouldValidateInline}
validateOnChange={shouldValidateInline}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
willAutoFocus
/>
</Box>
Expand Down
6 changes: 3 additions & 3 deletions renderer/components/Onboarding/Steps/WalletRecover.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class WalletRecover extends React.Component {
onSubmitFailure={onSubmitFailure}
>
{({ formState }) => {
const shouldValidateInline = formState.submits > 0
const willValidateInline = formState.submits > 0
return (
<>
<Header
Expand All @@ -126,8 +126,8 @@ class WalletRecover extends React.Component {
isRequired
label={<FormattedMessage {...messages.passphrase_label} />}
placeholder={intl.formatMessage({ ...messages.passphrase_placeholder })}
validateOnBlur={shouldValidateInline}
validateOnChange={shouldValidateInline}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
willAutoFocus
/>
) : (
Expand Down
2 changes: 1 addition & 1 deletion renderer/components/Settings/SettingsFieldHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { IntegerInput, Label } from 'components/Form'
import messages from './messages'

export const FieldLabel = ({ itemKey, ...rest }) => {
const messageKey = itemKey.replace('.', '_')
const messageKey = itemKey.replace(/\./g, '_')
return (
<Box {...rest}>
<Label htmlFor={itemKey} mb={2}>
Expand Down
48 changes: 48 additions & 0 deletions renderer/components/Settings/SettingsFieldsSecurity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react'
import PropTypes from 'prop-types'
import { useFieldState, useFormState } from 'informed'
import { useIntl } from 'react-intl'
import { DataRow } from 'components/UI'
import { PasswordInput, Toggle } from 'components/Form'
import { FieldLabel } from './SettingsFieldHelpers'
import messages from './messages'

const SettingsFieldsSecurity = ({ currentConfig }) => {
const { value: isPasswordActive } = useFieldState('password.active')
const { submits } = useFormState()
const willValidateInline = submits > 0
const intl = useIntl()

return (
<>
<DataRow
left={<FieldLabel itemKey="password.active" />}
pb={0}
right={<Toggle field="password.active" initialValue={currentConfig.password.active} />}
/>
{isPasswordActive && (
<DataRow
pt={0}
right={
<PasswordInput
description={intl.formatMessage({ ...messages.password_value_description })}
field="password.value"
initialValue={currentConfig.password.value}
isRequired
minLength={6}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
width={200}
/>
}
/>
)}
</>
)
}

SettingsFieldsSecurity.propTypes = {
currentConfig: PropTypes.object.isRequired,
}

export default SettingsFieldsSecurity
6 changes: 6 additions & 0 deletions renderer/components/Settings/SettingsForm.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import get from 'lodash/get'
import { injectIntl } from 'react-intl'
import { intlShape } from '@zap/i18n'
import { Form } from 'components/Form'
Expand All @@ -18,6 +19,11 @@ const SettingsForm = ({
}) => {
const handleSubmit = async values => {
try {
// If password feature has been disabled, reset the password to null.
if (!get(values, 'password.value')) {
values.password.value = null
mrfelton marked this conversation as resolved.
Show resolved Hide resolved
}

// Save the updated settings.
await saveConfigOverrides(values)

Expand Down
Loading