import React, { useEffect, useRef, useState } from 'react'; import { useAsyncStorage } from '@react-native-community/async-storage'; import { gestureHandlerRootHOC } from 'react-native-gesture-handler'; import * as Haptics from 'expo-haptics'; import { sha256 } from 'js-sha256'; import Base from './Base'; import Locked from './Base/Locked'; import { TYPE } from './constants'; import { ATTEMPTS_KEY, LOCKED_OUT_TIMER_KEY, MAX_ATTEMPTS, PASSCODE_KEY } from '../../constants/localAuthentication'; import { biometryAuth, resetAttempts } from '../../utils/localAuthentication'; import { getDiff, getLockedUntil } from './utils'; import UserPreferences from '../../lib/userPreferences'; import I18n from '../../i18n'; interface IPasscodePasscodeEnter { theme: string; hasBiometry: boolean; finishProcess: Function; } const PasscodeEnter = ({ theme, hasBiometry, finishProcess }: IPasscodePasscodeEnter) => { const ref = useRef(null); let attempts: any = 0; let lockedUntil: any = false; const [passcode, setPasscode] = useState(null); const [status, setStatus] = useState(null); const { getItem: getAttempts, setItem: setAttempts } = useAsyncStorage(ATTEMPTS_KEY); const { setItem: setLockedUntil } = useAsyncStorage(LOCKED_OUT_TIMER_KEY); const fetchPasscode = async () => { const p: any = await UserPreferences.getStringAsync(PASSCODE_KEY); setPasscode(p); }; const biometry = async () => { if (hasBiometry && status === TYPE.ENTER) { const result = await biometryAuth(); if (result?.success) { finishProcess(); } } }; const readStorage = async () => { lockedUntil = await getLockedUntil(); if (lockedUntil) { const diff = getDiff(lockedUntil); if (diff <= 1) { await resetAttempts(); setStatus(TYPE.ENTER); } else { attempts = await getAttempts(); setStatus(TYPE.LOCKED); } } else { setStatus(TYPE.ENTER); } await fetchPasscode(); biometry(); }; useEffect(() => { readStorage(); }, [status]); const onEndProcess = (p: any) => { setTimeout(() => { if (sha256(p) === passcode) { finishProcess(); } else { attempts += 1; if (attempts >= MAX_ATTEMPTS) { setStatus(TYPE.LOCKED); setLockedUntil(new Date().toISOString()); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); } else { // @ts-ignore ref.current.wrongPasscode(); setAttempts(attempts?.toString()); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning); } } }, 200); }; if (status === TYPE.LOCKED) { return ; } return ( ); }; export default gestureHandlerRootHOC(PasscodeEnter);