feat: recovery codes UI (recovery sign in + get recovery codes) (#2139)

* feat(web): show recovery codes

* feat(web): add recovery sign in

* fix: copy

* fix: styles

* feat: add "copy to clipboard" button

* style: copy

* fix: copy button bg

* style: singularize recovery codes

* style: singularize recovery codes

* feat: password validation

Co-authored-by: Aman Harwara <amanharwara@protonmail.com>
Co-authored-by: Mo <mo@standardnotes.com>
This commit is contained in:
Karol Sójko
2023-01-10 21:33:44 +01:00
committed by GitHub
parent de3fa476c7
commit 5e6c901c21
16 changed files with 234 additions and 32 deletions

View File

@@ -27,7 +27,11 @@ const Security: FunctionComponent<SecurityProps> = (props) => {
<ErroredItems viewControllerManager={props.viewControllerManager} />
)}
<Protections application={props.application} />
<TwoFactorAuthWrapper mfaProvider={props.mfaProvider} userProvider={props.userProvider} />
<TwoFactorAuthWrapper
mfaProvider={props.mfaProvider}
userProvider={props.userProvider}
application={props.application}
/>
{isNativeMobileWeb && <MultitaskingPrivacy application={props.application} />}
<PasscodeLock viewControllerManager={props.viewControllerManager} application={props.application} />
{isNativeMobileWeb && <BiometricsLock application={props.application} />}

View File

@@ -1,6 +1,8 @@
import { WebApplication } from '@/Application/Application'
import { MfaProvider, UserProvider } from '@/Components/Preferences/Providers'
export interface MfaProps {
userProvider: UserProvider
mfaProvider: MfaProvider
application: WebApplication
}

View File

@@ -1,19 +1,22 @@
import { FunctionComponent } from 'react'
import { Text } from '@/Components/Preferences/PreferencesComponents/Content'
import { observer } from 'mobx-react-lite'
import { is2FAActivation, TwoFactorAuth } from '../TwoFactorAuth'
import { is2FAActivation, is2FAEnabled, TwoFactorAuth } from '../TwoFactorAuth'
import TwoFactorActivationView from '../TwoFactorActivationView'
import TwoFactorTitle from './TwoFactorTitle'
import TwoFactorDescription from './TwoFactorDescription'
import TwoFactorSwitch from './TwoFactorSwitch'
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
import { WebApplication } from '@/Application/Application'
import RecoveryCodeBanner from '@/Components/RecoveryCodeBanner/RecoveryCodeBanner'
type Props = {
auth: TwoFactorAuth
application: WebApplication
}
const TwoFactorAuthView: FunctionComponent<Props> = ({ auth }) => {
const TwoFactorAuthView: FunctionComponent<Props> = ({ auth, application }) => {
return (
<>
<PreferencesGroup>
@@ -34,6 +37,13 @@ const TwoFactorAuthView: FunctionComponent<Props> = ({ auth }) => {
<Text className="text-danger">{auth.errorMessage}</Text>
</PreferencesSegment>
)}
{auth.status !== 'fetching' && is2FAEnabled(auth.status) && (
<PreferencesSegment>
<div className="mt-3">
<RecoveryCodeBanner application={application} />
</div>
</PreferencesSegment>
)}
</PreferencesGroup>
{auth.status !== 'fetching' && is2FAActivation(auth.status) && (
<TwoFactorActivationView activation={auth.status} />

View File

@@ -6,7 +6,7 @@ import TwoFactorAuthView from './TwoFactorAuthView/TwoFactorAuthView'
const TwoFactorAuthWrapper: FunctionComponent<MfaProps> = (props) => {
const [auth] = useState(() => new TwoFactorAuth(props.mfaProvider, props.userProvider))
auth.fetchStatus()
return <TwoFactorAuthView auth={auth} />
return <TwoFactorAuthView auth={auth} application={props.application} />
}
export default TwoFactorAuthWrapper