Skip to content

Commit

Permalink
add device verification reset dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
ajbura committed Feb 9, 2025
1 parent 90f63c1 commit 982c738
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 8 deletions.
67 changes: 66 additions & 1 deletion src/app/components/DeviceVerificationSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { clearSecretStorageKeys } from '../../client/state/secretStorageKeys';
import { ActionUIA, ActionUIAFlowsLoader } from './ActionUIA';
import { useMatrixClient } from '../hooks/useMatrixClient';
import { useAlive } from '../hooks/useAlive';
import { UseStateProvider } from './UseStateProvider';

type UIACallback<T> = (
authDict: AuthDict | null
Expand Down Expand Up @@ -300,7 +301,14 @@ export const DeviceVerificationSetup = forwardRef<HTMLDivElement, DeviceVerifica
<Box grow="Yes">
<Text size="H4">Setup Device Verification</Text>
</Box>
<IconButton size="300" radii="300" onClick={onCancel}>
<IconButton
size="300"
radii="300"
onClick={() => {
console.log('cancel click');
onCancel();
}}
>
<Icon src={Icons.Cross} />
</IconButton>
</Header>
Expand All @@ -315,3 +323,60 @@ export const DeviceVerificationSetup = forwardRef<HTMLDivElement, DeviceVerifica
);
}
);
type DeviceVerificationResetProps = {
onCancel: () => void;
};
export const DeviceVerificationReset = forwardRef<HTMLDivElement, DeviceVerificationResetProps>(
({ onCancel }, ref) => {
const [reset, setReset] = useState(false);

return (
<Dialog ref={ref}>
<Header
style={{
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
borderBottomWidth: config.borderWidth.B300,
}}
variant="Surface"
size="500"
>
<Box grow="Yes">
<Text size="H4">Reset Device Verification</Text>
</Box>
<IconButton size="300" radii="300" onClick={onCancel}>
<Icon src={Icons.Cross} />
</IconButton>
</Header>
{reset ? (
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
<UseStateProvider initial={undefined}>
{(recoveryKey: string | undefined, setRecoveryKey) =>
recoveryKey ? (
<RecoveryKeyDisplay recoveryKey={recoveryKey} />
) : (
<SetupVerification onComplete={setRecoveryKey} />
)
}
</UseStateProvider>
</Box>
) : (
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
<Box direction="Column" gap="200">
<Text size="H1">✋🧑‍🚒🤚</Text>
<Text size="T300">Resetting device verification is permanent.</Text>
<Text size="T300">
Anyone you have verified with will see security alerts and your encryption backup
will be lost. You almost certainly do not want to do this, unless you have lost{' '}
<b>Recovery Key</b> or <b>Recovery Passphrase</b> and every device you can verify
from.
</Text>
</Box>
<Button variant="Critical" onClick={() => setReset(true)}>
<Text size="B400">Reset</Text>
</Button>
</Box>
)}
</Dialog>
);
}
);
78 changes: 71 additions & 7 deletions src/app/features/settings/devices/Verification.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react';
import React, { MouseEventHandler, useCallback, useState } from 'react';
import {
Badge,
Box,
Expand All @@ -13,6 +13,10 @@ import {
OverlayBackdrop,
OverlayCenter,
IconButton,
RectCords,
PopOut,
Menu,
MenuItem,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { CryptoApi, VerificationRequest } from 'matrix-js-sdk/lib/crypto-api';
Expand All @@ -23,7 +27,11 @@ import { SecretStorageKeyContent } from '../../../../types/matrix/accountData';
import { AsyncState, AsyncStatus, useAsync } from '../../../hooks/useAsyncCallback';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { DeviceVerification } from '../../../components/DeviceVerification';
import { DeviceVerificationSetup } from '../../../components/DeviceVerificationSetup';
import {
DeviceVerificationReset,
DeviceVerificationSetup,
} from '../../../components/DeviceVerificationSetup';
import { stopPropagation } from '../../../utils/keyboard';

type VerificationStatusBadgeProps = {
verificationStatus: VerificationStatus;
Expand Down Expand Up @@ -238,15 +246,71 @@ export function EnableVerification() {
}

export function DeviceVerificationOptions() {
const [open, setOpen] = useState(false);
const [menuCords, setMenuCords] = useState<RectCords>();

const [reset, setReset] = useState(false);

const handleCancelReset = useCallback(() => {
setReset(false);
}, []);

const handleMenu: MouseEventHandler<HTMLButtonElement> = (event) => {
setMenuCords(event.currentTarget.getBoundingClientRect());
};

const handleReset = () => {
setMenuCords(undefined);
setReset(true);
};

const handleCancel = useCallback(() => setOpen(false), []);
return (
<>
<IconButton variant="SurfaceVariant" size="300" radii="300" onClick={() => setOpen(true)}>
<IconButton
aria-pressed={!!menuCords}
variant="SurfaceVariant"
size="300"
radii="300"
onClick={handleMenu}
>
<Icon size="100" src={Icons.VerticalDots} />
</IconButton>
{open && (
<PopOut
anchor={menuCords}
offset={5}
position="Bottom"
align="Center"
content={
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onDeactivate: () => setMenuCords(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) =>
evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
isKeyBackward: (evt: KeyboardEvent) =>
evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
escapeDeactivates: stopPropagation,
}}
>
<Menu>
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
<MenuItem
variant="Critical"
onClick={handleReset}
size="300"
radii="300"
fill="None"
>
<Text as="span" size="T300" truncate>
Reset
</Text>
</MenuItem>
</Box>
</Menu>
</FocusTrap>
}
/>
{reset && (
<Overlay open backdrop={<OverlayBackdrop />}>
<OverlayCenter>
<FocusTrap
Expand All @@ -256,7 +320,7 @@ export function DeviceVerificationOptions() {
escapeDeactivates: false,
}}
>
<DeviceVerificationSetup onCancel={handleCancel} />
<DeviceVerificationReset onCancel={handleCancelReset} />
</FocusTrap>
</OverlayCenter>
</Overlay>
Expand Down

0 comments on commit 982c738

Please sign in to comment.