diff --git a/src/screen/LockScreen.tsx b/src/screen/LockScreen.tsx new file mode 100644 index 0000000..3be0454 --- /dev/null +++ b/src/screen/LockScreen.tsx @@ -0,0 +1,70 @@ +import React, { useState } from 'react'; +import { + View, + Text, + TouchableOpacity, + TextInput, + Alert, +} from 'react-native'; +import { verifyPin } from '../auth/AppPinService'; +import { unlockWithDevice, unlockApp } from '../auth/AuthManager'; + +const LockScreen = ({ onUnlock }: any) => { + const [pin, setPin] = useState(''); + + const handlePinUnlock = async () => { + const valid = await verifyPin(pin); + if (valid) { + await unlockApp(); + onUnlock(); + } else { + Alert.alert('Wrong PIN'); + } + }; + + const handleDeviceUnlock = async () => { + const res = await unlockWithDevice(); + if (res.success) { + await unlockApp(); + onUnlock(); + } else { + Alert.alert('Authentication Failed'); + } + }; + + return ( + + + Enter App PIN + + + + + + + Unlock with PIN + + + + + + Unlock with Device Lock + + + + ); +}; + +export default LockScreen; diff --git a/src/screen/SetPinScreen.tsx b/src/screen/SetPinScreen.tsx new file mode 100644 index 0000000..18946ad --- /dev/null +++ b/src/screen/SetPinScreen.tsx @@ -0,0 +1,31 @@ +import React, { useState } from 'react'; +import { View, TextInput, Text, TouchableOpacity } from 'react-native'; +import { savePin } from '../auth/AppPinService'; + +const SetPinScreen = ({ onDone }: any) => { + const [pin, setPin] = useState(''); + + const save = async () => { + await savePin(pin); + onDone(); + }; + + return ( + + Create App PIN + + + Save PIN + + + ); +}; + +export default SetPinScreen; diff --git a/src/screen/authorised/AppPinService.ts b/src/screen/authorised/AppPinService.ts new file mode 100644 index 0000000..4b2f2f9 --- /dev/null +++ b/src/screen/authorised/AppPinService.ts @@ -0,0 +1,20 @@ +import * as Keychain from 'react-native-keychain'; + +const PIN_KEY = 'APP_PIN'; + +export const savePin = async (pin: string) => { + await Keychain.setGenericPassword(PIN_KEY, pin, { + accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED, + }); +}; + +export const verifyPin = async (inputPin: string) => { + const creds = await Keychain.getGenericPassword(); + if (!creds) return false; + return creds.password === inputPin; +}; + +export const isPinSet = async () => { + const creds = await Keychain.getGenericPassword(); + return !!creds; +}; diff --git a/src/screen/authorised/AuthManager.ts b/src/screen/authorised/AuthManager.ts new file mode 100644 index 0000000..d8adade --- /dev/null +++ b/src/screen/authorised/AuthManager.ts @@ -0,0 +1,21 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { deviceAuthenticate } from './DeviceAuth'; + +const LOCK_KEY = 'APP_LOCKED'; + +export const lockApp = async () => { + await AsyncStorage.setItem(LOCK_KEY, 'true'); +}; + +export const unlockApp = async () => { + await AsyncStorage.removeItem(LOCK_KEY); +}; + +export const isAppLocked = async () => { + const v = await AsyncStorage.getItem(LOCK_KEY); + return v === 'true'; +}; + +export const unlockWithDevice = async () => { + return await deviceAuthenticate(); +};