import React, { MouseEventHandler, useCallback, useState } from 'react'; import { Badge, Box, Button, Chip, config, Icon, Icons, Spinner, Text, Overlay, 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'; import { VerificationStatus } from '../../../hooks/useDeviceVerificationStatus'; import { InfoCard } from '../../../components/info-card'; import { ManualVerificationTile } from '../../../components/ManualVerification'; import { SecretStorageKeyContent } from '../../../../types/matrix/accountData'; import { AsyncState, AsyncStatus, useAsync } from '../../../hooks/useAsyncCallback'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { DeviceVerification } from '../../../components/DeviceVerification'; import { DeviceVerificationReset, DeviceVerificationSetup, } from '../../../components/DeviceVerificationSetup'; import { stopPropagation } from '../../../utils/keyboard'; import { useAuthMetadata } from '../../../hooks/useAuthMetadata'; import { withSearchParam } from '../../../pages/pathUtils'; import { useAccountManagementActions } from '../../../hooks/useAccountManagement'; type VerificationStatusBadgeProps = { verificationStatus: VerificationStatus; otherUnverifiedCount?: number; }; export function VerificationStatusBadge({ verificationStatus, otherUnverifiedCount, }: VerificationStatusBadgeProps) { if ( verificationStatus === VerificationStatus.Unknown || typeof otherUnverifiedCount !== 'number' ) { return ; } if (verificationStatus === VerificationStatus.Unverified) { return ( Unverified ); } if (otherUnverifiedCount > 0) { return ( {otherUnverifiedCount} Unverified ); } return ( Verified ); } function LearnStartVerificationFromOtherDevice() { return ( Steps to verify from other device.
  • Open your other verified device.
  • Open Settings.
  • Find this device in Devices/Sessions section.
  • Initiate verification.
If you do not have any verified device press the "Verify Manually" button.
); } type VerifyCurrentDeviceTileProps = { secretStorageKeyId: string; secretStorageKeyContent: SecretStorageKeyContent; }; export function VerifyCurrentDeviceTile({ secretStorageKeyId, secretStorageKeyContent, }: VerifyCurrentDeviceTileProps) { const [learnMore, setLearnMore] = useState(false); const [manualVerification, setManualVerification] = useState(false); const handleCancelVerification = () => setManualVerification(false); return ( <> Start verification from other device or verify manually.{' '} setLearnMore(!learnMore)}> {learnMore ? 'View Less' : 'Learn More'} } after={ !manualVerification && ( ) } > {learnMore && } {manualVerification && ( } /> )} ); } type VerifyOtherDeviceTileProps = { crypto: CryptoApi; deviceId: string; }; export function VerifyOtherDeviceTile({ crypto, deviceId }: VerifyOtherDeviceTileProps) { const mx = useMatrixClient(); const [requestState, setRequestState] = useState>({ status: AsyncStatus.Idle, }); const requestVerification = useAsync( useCallback(() => { const requestPromise = crypto.requestDeviceVerification(mx.getSafeUserId(), deviceId); return requestPromise; }, [mx, crypto, deviceId]), setRequestState ); const handleExit = useCallback(() => { setRequestState({ status: AsyncStatus.Idle, }); }, []); const requesting = requestState.status === AsyncStatus.Loading; return ( } disabled={requesting} > Verify } > {requestState.status === AsyncStatus.Error && ( {requestState.error.message} )} {requestState.status === AsyncStatus.Success && ( )} ); } type EnableVerificationProps = { visible: boolean; }; export function EnableVerification({ visible }: EnableVerificationProps) { const [open, setOpen] = useState(false); const handleCancel = useCallback(() => setOpen(false), []); return ( <> {visible && ( )} {open && ( }> )} ); } export function DeviceVerificationOptions() { const [menuCords, setMenuCords] = useState(); const authMetadata = useAuthMetadata(); const accountManagementActions = useAccountManagementActions(); const [reset, setReset] = useState(false); const handleCancelReset = useCallback(() => { setReset(false); }, []); const handleMenu: MouseEventHandler = (event) => { setMenuCords(event.currentTarget.getBoundingClientRect()); }; const handleReset = () => { setMenuCords(undefined); if (authMetadata) { const authUrl = authMetadata.account_management_uri ?? authMetadata.issuer; window.open( withSearchParam(authUrl, { action: accountManagementActions.crossSigningReset, }), '_blank' ); return; } setReset(true); }; return ( <> setMenuCords(undefined), clickOutsideDeactivates: true, isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown' || evt.key === 'ArrowRight', isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp' || evt.key === 'ArrowLeft', escapeDeactivates: stopPropagation, }} > Reset } /> {reset && ( }> )} ); }