import type { FC } from '../../lib/teact/teact'; import React, { memo, useCallback, useEffect, useState, } from '../../lib/teact/teact'; import { getActions, withGlobal } from '../../global'; import type { GlobalState } from '../../global/types'; import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets'; import useLang from '../../hooks/useLang'; import { decryptSession } from '../../util/passcode'; import useShowTransition from '../../hooks/useShowTransition'; import useTimeout from '../../hooks/useTimeout'; import useFlag from '../../hooks/useFlag'; import AnimatedIconWithPreview from '../common/AnimatedIconWithPreview'; import PasswordForm from '../common/PasswordForm'; import ConfirmDialog from '../ui/ConfirmDialog'; import Button from '../ui/Button'; import Link from '../ui/Link'; import styles from './LockScreen.module.scss'; import lockPreviewUrl from '../../assets/lock.png'; export type OwnProps = { isLocked?: boolean; }; type StateProps = { passcodeSettings: GlobalState['passcode']; }; const MAX_INVALID_ATTEMPTS = 5; const TIMEOUT_RESET_INVALID_ATTEMPTS_MS = 180000; // 3 minutes const ICON_SIZE = 160; const LockScreen: FC = ({ isLocked, passcodeSettings, }) => { const { unlockScreen, signOut, logInvalidUnlockAttempt, resetInvalidUnlockAttempts, } = getActions(); const { invalidAttemptsCount, isLoading, } = passcodeSettings; const lang = useLang(); const [validationError, setValidationError] = useState(''); const [shouldShowPasscode, setShouldShowPasscode] = useState(false); const [isSignOutDialogOpen, openSignOutConfirmation, closeSignOutConfirmation] = useFlag(false); const { shouldRender } = useShowTransition(isLocked); useTimeout( resetInvalidUnlockAttempts, invalidAttemptsCount && invalidAttemptsCount >= MAX_INVALID_ATTEMPTS ? TIMEOUT_RESET_INVALID_ATTEMPTS_MS : undefined, ); const handleClearError = useCallback(() => { setValidationError(''); }, []); const handleSubmit = useCallback((passcode: string) => { if (invalidAttemptsCount && invalidAttemptsCount >= MAX_INVALID_ATTEMPTS) { setValidationError(lang('FloodWait')); return; } setValidationError(''); decryptSession(passcode).then(unlockScreen, () => { logInvalidUnlockAttempt(); setValidationError(lang('lng_passcode_wrong')); }); }, [invalidAttemptsCount, lang, logInvalidUnlockAttempt, unlockScreen]); useEffect(() => { if (invalidAttemptsCount && invalidAttemptsCount >= MAX_INVALID_ATTEMPTS) { setValidationError(lang('FloodWait')); } else if (invalidAttemptsCount === 0) { setValidationError(''); } }, [invalidAttemptsCount, lang]); const handleSignOutMessage = useCallback(() => { closeSignOutConfirmation(); signOut(); }, [closeSignOutConfirmation, signOut]); if (!shouldRender) { return undefined; } function renderLogoutPrompt() { return (

Log out{' '} if you don't remember your passcode.

); } return (
{renderLogoutPrompt()}
); }; export default memo(withGlobal( (global): StateProps => { return { passcodeSettings: global.passcode, }; }, )(LockScreen));