Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Seedless Onboarding]: Adjust password form #2692

Merged
merged 3 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions public/images/common/bar-chart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/common/PageHeader/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
flex-direction: column;
justify-content: space-between;
background-color: var(--color-background-main);
z-index: 1;
z-index: 2;
width: 100%;
position: sticky !important;
top: calc(var(--header-height) - 76px);
Expand Down
1 change: 1 addition & 0 deletions src/components/new-safe/create/steps/SetNameStep/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ function SetNameStep({
}

const onCancel = () => {
trackEvent(CREATE_SAFE_EVENTS.CANCEL_CREATE_SAFE_FORM)
router.push(AppRoutes.welcome)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,14 @@ const ExportMPCAccountModal = ({ onClose, open }: { onClose: () => void; open: b
)}
{error && <ErrorMessage className={css.modalError}>{error}</ErrorMessage>}

<Box display="flex" flexDirection="row" justifyContent="space-between" alignItems="center" width="100%">
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
width="100%"
mt={2}
>
<Button variant="outlined" onClick={handleClose}>
Close
</Button>
Expand Down
27 changes: 4 additions & 23 deletions src/components/settings/SecurityLogin/SocialSignerMFA/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { logError } from '@/services/exceptions'
import ErrorCodes from '@/services/exceptions/ErrorCodes'
import { asError } from '@/services/exceptions/utils'
import { type Web3AuthMPCCoreKit } from '@web3auth/mpc-core-kit'
import { showNotification } from '@/store/notificationsSlice'
import { type AppDispatch } from '@/store'

export const isMFAEnabled = (mpcCoreKit: Web3AuthMPCCoreKit) => {
if (!mpcCoreKit) {
Expand All @@ -17,14 +15,13 @@ export const isMFAEnabled = (mpcCoreKit: Web3AuthMPCCoreKit) => {
}

export const enableMFA = async (
dispatch: AppDispatch,
mpcCoreKit: Web3AuthMPCCoreKit,
{
newPassword,
oldPassword,
currentPassword,
}: {
newPassword: string
oldPassword: string | undefined
currentPassword: string | undefined
},
) => {
if (!mpcCoreKit) {
Expand All @@ -33,7 +30,7 @@ export const enableMFA = async (
const securityQuestions = new SecurityQuestionRecovery(mpcCoreKit)
try {
// 1. setup device factor with password recovery
await securityQuestions.upsertPassword(newPassword, oldPassword)
await securityQuestions.upsertPassword(newPassword, currentPassword)
const securityQuestionFactor = await securityQuestions.recoverWithPassword(newPassword)
if (!securityQuestionFactor) {
throw Error('Could not recover using the new password recovery')
Expand All @@ -46,25 +43,9 @@ export const enableMFA = async (
}

await mpcCoreKit.commitChanges()

dispatch(
showNotification({
variant: 'success',
groupKey: 'global-upsert-password',
message: 'Successfully created or updated password',
}),
)
} catch (e) {
const error = asError(e)
logError(ErrorCodes._304, error.message)

// TODO: Check if we should use a notification or show an error inside the form
dispatch(
showNotification({
variant: 'error',
groupKey: 'global-upsert-password',
message: 'Failed to create or update password',
}),
)
throw error
}
}
98 changes: 64 additions & 34 deletions src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
FormControl,
SvgIcon,
Divider,
Alert,
} from '@mui/material'
import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet'
import { useState, useMemo, type ChangeEvent } from 'react'
Expand All @@ -24,17 +25,16 @@
import ShieldIcon from '@/public/images/common/shield.svg'
import ShieldOffIcon from '@/public/images/common/shield-off.svg'
import useMPC from '@/hooks/wallets/mpc/useMPC'
import { useAppDispatch } from '@/store'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'

enum PasswordFieldNames {
oldPassword = 'oldPassword',
currentPassword = 'currentPassword',
newPassword = 'newPassword',
confirmPassword = 'confirmPassword',
}

type PasswordFormData = {
[PasswordFieldNames.oldPassword]: string | undefined
[PasswordFieldNames.currentPassword]: string | undefined
[PasswordFieldNames.newPassword]: string
[PasswordFieldNames.confirmPassword]: string
}
Expand All @@ -50,7 +50,9 @@
// At least 9 characters, one lowercase, one uppercase, one number, one symbol
const mediumPassword = new RegExp('((?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9])(?=.{9,}))')

export const _getPasswordStrength = (value: string): PasswordStrength => {
export const _getPasswordStrength = (value: string): PasswordStrength | undefined => {
if (value === '') return undefined

if (strongPassword.test(value)) {
return PasswordStrength.strong
}
Expand Down Expand Up @@ -78,15 +80,16 @@
} as const

const SocialSignerMFA = () => {
const dispatch = useAppDispatch()
const mpcCoreKit = useMPC()
const [passwordStrength, setPasswordStrength] = useState<PasswordStrength>(PasswordStrength.weak)
const [passwordStrength, setPasswordStrength] = useState<PasswordStrength>()
const [submitError, setSubmitError] = useState<string>()
const [open, setOpen] = useState<boolean>(false)

Check warning on line 86 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

const formMethods = useForm<PasswordFormData>({
mode: 'all',
defaultValues: {
[PasswordFieldNames.confirmPassword]: '',
[PasswordFieldNames.oldPassword]: undefined,
[PasswordFieldNames.currentPassword]: undefined,
[PasswordFieldNames.newPassword]: '',
},
})
Expand All @@ -100,19 +103,32 @@
return securityQuestions.isEnabled()
}, [mpcCoreKit])

const onSubmit = async (data: PasswordFormData) => {
if (!mpcCoreKit) return

await enableMFA(dispatch, mpcCoreKit, data)
try {
await enableMFA(mpcCoreKit, data)
onReset()

Check warning on line 111 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
setOpen(false)

Check warning on line 112 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
} catch (e) {
setSubmitError('The password you entered is incorrect. Please try again.')
}

Check warning on line 115 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
}

Check warning on line 116 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

const onReset = () => {
reset()
setPasswordStrength(PasswordStrength.weak)
setPasswordStrength(undefined)
setSubmitError(undefined)
}

const toggleAccordion = () => {

Check warning on line 124 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
setOpen((prev) => !prev)

Check warning on line 125 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 125 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 125 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
}

Check warning on line 126 in src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

const confirmPassword = watch(PasswordFieldNames.confirmPassword)
const passwordsMatch = watch(PasswordFieldNames.newPassword) === confirmPassword && confirmPassword !== ''
const newPassword = watch(PasswordFieldNames.newPassword)
const passwordsEmpty = confirmPassword === '' && newPassword === ''
const passwordsMatch = newPassword === confirmPassword

const isSubmitDisabled =
!passwordsMatch ||
Expand All @@ -128,7 +144,7 @@
Protect your social login signer with a password. It will be used to restore access in another browser or on
another device.
</Typography>
<Accordion>
<Accordion expanded={open} defaultExpanded={false} onChange={toggleAccordion}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Box display="flex" alignItems="center" gap={1}>
<SvgIcon component={CheckIcon} sx={{ color: isPasswordSet ? 'success.main' : 'border.light' }} />
Expand All @@ -140,13 +156,12 @@
<Grid item container xs={12} md={7} gap={3} p={3}>
{isPasswordSet && (
<>
<Typography>You already have a password setup.</Typography>
<FormControl fullWidth>
<PasswordInput
name={PasswordFieldNames.oldPassword}
placeholder="Old password"
label="Old password"
helperText={formState.errors[PasswordFieldNames.oldPassword]?.message}
name={PasswordFieldNames.currentPassword}
placeholder="Current password"
label="Current password"
helperText={formState.errors[PasswordFieldNames.currentPassword]?.message}
required
/>
</FormControl>
Expand Down Expand Up @@ -174,10 +189,16 @@
alignItems="center"
gap={1}
mt={1}
className={css[passwordStrengthMap[passwordStrength].className]}
className={
passwordStrength !== undefined
? css[passwordStrengthMap[passwordStrength].className]
: css.defaultPassword
}
>
<BarChartIcon />
{passwordStrengthMap[passwordStrength].label} password
{passwordStrength !== undefined
? `${passwordStrengthMap[passwordStrength].label} password`
: 'Password strength'}
</Typography>
<Typography variant="body2" color="text.secondary" mt={1}>
Include at least 9 or more characters, a number, an uppercase letter and a symbol
Expand All @@ -187,8 +208,8 @@
<FormControl fullWidth>
<PasswordInput
name={PasswordFieldNames.confirmPassword}
placeholder="Confirm new password"
label="Confirm new password"
placeholder="Confirm password"
label="Confirm password"
helperText={formState.errors[PasswordFieldNames.confirmPassword]?.message}
required
/>
Expand All @@ -198,9 +219,19 @@
alignItems="center"
gap={1}
mt={1}
className={passwordsMatch ? css.passwordsMatch : css.passwordsNoMatch}
className={
passwordsEmpty
? css.passwordsShouldMatch
: passwordsMatch
? css.passwordsMatch
: css.passwordsNoMatch
}
>
{passwordsMatch ? (
{passwordsEmpty ? (
<>
<ShieldOffIcon /> Passwords should match
</>
) : passwordsMatch ? (
<>
<ShieldIcon /> Passwords match
</>
Expand All @@ -212,19 +243,18 @@
</Typography>
</FormControl>

<Button variant="text" onClick={onReset} disabled={!formState.isDirty}>
Cancel
</Button>
<Track {...MPC_WALLET_EVENTS.UPSERT_PASSWORD}>
<Button
sx={{ justifySelf: 'flex-end', marginLeft: 'auto', fontSize: '14px' }}
disabled={isSubmitDisabled}
type="submit"
variant="contained"
>
{isPasswordSet ? 'Change' : 'Create'} Password
{submitError && <Alert severity="error">{submitError}</Alert>}

<Box display="flex" justifyContent="space-between" width={1}>
<Button sx={{ fontSize: '14px' }} variant="text" onClick={onReset} disabled={!formState.isDirty}>
Cancel
</Button>
</Track>
<Track {...MPC_WALLET_EVENTS.UPSERT_PASSWORD}>
<Button sx={{ fontSize: '14px' }} disabled={isSubmitDisabled} type="submit" variant="contained">
{isPasswordSet ? 'Change' : 'Create'} Password
</Button>
</Track>
</Box>
</Grid>
<Grid item xs={12} md={5} p={3} sx={{ borderLeft: '1px solid #DCDEE0' }}>
<Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@
margin-bottom: 0;
}

.defaultPassword,
.passwordsShouldMatch {
color: var(--color-border-main);
}

.passwordsShouldMatch svg path {
stroke: var(--color-border-main);
}

.defaultPassword svg path {
stroke: var(--color-border-main);
}

.weakPassword {
color: var(--color-error-main);
}
Expand Down
4 changes: 4 additions & 0 deletions src/services/analytics/events/createLoadSafe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export const CREATE_SAFE_EVENTS = {
action: 'Retry Safe creation',
category: CREATE_SAFE_CATEGORY,
},
CANCEL_CREATE_SAFE_FORM: {
action: 'Cancel safe creation form',
category: CREATE_SAFE_CATEGORY,
},
CANCEL_CREATE_SAFE: {
event: EventType.META,
action: 'Cancel Safe creation',
Expand Down
4 changes: 4 additions & 0 deletions src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ input[type='number'] {
stroke: var(--color-border-main);
}

.illustration-very-light-stroke {
stroke: var(--color-border-light);
}

.illustration-background-stroke {
stroke: var(--color-logo-background);
}
Expand Down
Loading