-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Mobile: Add support for locking the app using biometrics
- Loading branch information
Showing
12 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
packages/app-mobile/components/biometrics/BiometricPopup.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
const React = require('react'); | ||
import Setting from '@joplin/lib/models/Setting'; | ||
import { useEffect, useMemo, useState } from 'react'; | ||
import { View, Dimensions, Alert, Button } from 'react-native'; | ||
import FingerprintScanner from 'react-native-fingerprint-scanner'; | ||
import { SensorInfo } from './sensorInfo'; | ||
import { _ } from '@joplin/lib/locale'; | ||
|
||
interface Props { | ||
themeId: number; | ||
sensorInfo: SensorInfo; | ||
} | ||
|
||
export default (props: Props) => { | ||
const [initialPromptDone, setInitialPromptDone] = useState(false); // Setting.value('security.biometricsInitialPromptDone')); | ||
const [display, setDisplay] = useState(!!props.sensorInfo.supportedSensors && (props.sensorInfo.enabled || !initialPromptDone)); | ||
const [tryBiometricsCheck, setTryBiometricsCheck] = useState(initialPromptDone); | ||
|
||
useEffect(() => { | ||
if (!display || !tryBiometricsCheck) return; | ||
|
||
const biometricsCheck = async () => { | ||
try { | ||
await FingerprintScanner.authenticate({ description: _('Verify your identity') }); | ||
setTryBiometricsCheck(false); | ||
setDisplay(false); | ||
} catch (error) { | ||
Alert.alert(_('Could not verify your identify'), error.message); | ||
setTryBiometricsCheck(false); | ||
} finally { | ||
FingerprintScanner.release(); | ||
} | ||
}; | ||
|
||
void biometricsCheck(); | ||
}, [display, tryBiometricsCheck]); | ||
|
||
useEffect(() => { | ||
if (initialPromptDone) return; | ||
if (!display) return; | ||
|
||
const complete = (enableBiometrics: boolean) => { | ||
setInitialPromptDone(true); | ||
Setting.setValue('security.biometricsInitialPromptDone', true); | ||
Setting.setValue('security.biometricsEnabled', enableBiometrics); | ||
if (!enableBiometrics) { | ||
setDisplay(false); | ||
setTryBiometricsCheck(false); | ||
} else { | ||
setTryBiometricsCheck(true); | ||
} | ||
}; | ||
|
||
Alert.alert( | ||
_('Enable biometrics authentication?'), | ||
_('Use your biometrics to secure access to your application. You can always set it up later in Settings.'), | ||
[ | ||
{ | ||
text: _('Enable'), | ||
onPress: () => complete(true), | ||
style: 'default', | ||
}, | ||
{ | ||
text: _('Not now'), | ||
onPress: () => complete(false), | ||
style: 'cancel', | ||
}, | ||
] | ||
); | ||
}, [initialPromptDone, props.sensorInfo.supportedSensors, display]); | ||
|
||
const windowSize = useMemo(() => { | ||
return { | ||
width: Dimensions.get('window').width, | ||
height: Dimensions.get('window').height, | ||
}; | ||
}, []); | ||
|
||
const renderTryAgainButton = () => { | ||
if (!display || tryBiometricsCheck || !initialPromptDone) return null; | ||
return <Button title={_('Try again')} onPress={() => setTryBiometricsCheck(true)} />; | ||
}; | ||
|
||
return ( | ||
<View style={{ display: display ? 'flex' : 'none', position: 'absolute', zIndex: 99999, backgroundColor: '#000000', width: windowSize.width, height: windowSize.height }}> | ||
{renderTryAgainButton()} | ||
</View> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import Setting from '@joplin/lib/models/Setting'; | ||
import FingerprintScanner from 'react-native-fingerprint-scanner'; | ||
|
||
export interface SensorInfo { | ||
enabled: boolean; | ||
sensorsHaveChanged: boolean; | ||
supportedSensors: string; | ||
} | ||
|
||
export default async (): Promise<SensorInfo> => { | ||
const enabled = Setting.value('security.biometricsEnabled'); | ||
let hasChanged = false; | ||
let supportedSensors = ''; | ||
|
||
if (enabled) { | ||
try { | ||
const result = await FingerprintScanner.isSensorAvailable(); | ||
supportedSensors = result; | ||
|
||
if (result) { | ||
if (result !== Setting.value('security.biometricsSupportedSensors')) { | ||
hasChanged = true; | ||
Setting.setValue('security.biometricsSupportedSensors', result); | ||
} | ||
} | ||
} catch (error) { | ||
console.warn('Could not check for biometrics sensor:', error); | ||
Setting.setValue('security.biometricsSupportedSensors', ''); | ||
} | ||
} | ||
|
||
return { | ||
enabled, | ||
sensorsHaveChanged: hasChanged, | ||
supportedSensors, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters