import EventEmitter from "eventemitter3" ; import TouchID from "react-native-touch-id" ; import { Platform } from "react-native" ; import SecureStorage , { ACCESSIBLE , AUTHENTICATION_TYPE } from "react-native-secure-storage" ; import { VaultSourceID } from "buttercup" ; import { BIOMETRICS_ERROR_NOT_ENROLLED } from "../symbols" ; interface KeychainCredentials { [ sourceID ] : string ; } let __ee = null ; const STORAGE_SERVICE = Platform . select ( { ios : "pw.buttercup.mobile" , android : "com.buttercup" } ) ; const SECURE_STORAGE_CONFIG = { accessible : ACCESSIBLE . WHEN_UNLOCKED_THIS_DEVICE_ONLY , authenticationPrompt : "Authenticate to unlock vaults using biometrics" , service : STORAGE_SERVICE , authenticateType : AUTHENTICATION_TYPE . DEVICE_PASSCODE_OR_BIOMETRICS , accessGroup : "group.pw.buttercup.mobile" } ; const TOUCH_UNLOCK_CRED_KEY = "@@touchunlock" ; export async function authenticateBiometrics ( ) { try { await TouchID . authenticate ( "To unlock the selected vault" , { passcodeFallback : false , unifiedErrors : true } ) ; return true ; } catch ( err ) { if ( err . code === BIOMETRICS_ERROR_NOT_ENROLLED ) { return false ; } throw err ; } } export async function biometricsAvailable ( ) { try { const supportCode = await TouchID . isSupported ( ) ; return supportCode === "FaceID" || supportCode === "TouchID" || supportCode === true ; } catch ( err ) { return false ; } } export async function biometicsEnabledForSource ( sourceID ) { const keychainCreds = await getBiometricCredentials ( ) ; return keychainCreds . hasOwnProperty ( sourceID ) ; } export async function disableBiometicsForSource ( sourceID ) { const creds = await getBiometricCredentials ( ) ; delete creds [ sourceID ] ; await setBiometricCredentials ( creds ) ; getBiometricEvents ( ) . emit ( `biometrics-changed:${ sourceID }` , { state : "disabled" } ) ; } export async function enableBiometricsForSource ( sourceID , password ) { await setSourcePassword ( sourceID , password ) ; getBiometricEvents ( ) . emit ( `biometrics-changed:${ sourceID }` , { state : "enabled" } ) ; } async function getBiometricCredentials ( ) { const keychainCreds = await SecureStorage . getItem ( TOUCH_UNLOCK_CRED_KEY , SECURE_STORAGE_CONFIG ) ; return typeof keychainCreds === "string" && keychainCreds . length > 0 ? JSON . parse ( keychainCreds ) : { } ; } export async function getBiometricCredentialsForSource ( sourceID ) { const creds = await getBiometricCredentials ( ) ; return creds [ sourceID ] || null ; } export function getBiometricEvents ( ) { if ( ! __ee ) { __ee = new EventEmitter ( ) ; } return __ee ; } async function setBiometricCredentials ( credentials ) { await SecureStorage . setItem ( TOUCH_UNLOCK_CRED_KEY , JSON . stringify ( credentials ) , SECURE_STORAGE_CONFIG ) ; } async function setSourcePassword ( sourceID , password ) { const creds = await getBiometricCredentials ( ) ; await setBiometricCredentials ( { ... creds , [ sourceID ] : password } ) ; }