diff --git a/KeychainExample/app.js b/KeychainExample/app.js index 87b50f9..5fa2607 100644 --- a/KeychainExample/app.js +++ b/KeychainExample/app.js @@ -16,8 +16,15 @@ export default class KeychainExample extends Component { username: '', password: '', status: '', + biometryType: null, }; + componentDidMount() { + Keychain.getSupportedBiometryType().then(biometryType => { + this.setState({ biometryType }); + }); + } + save() { Keychain.setGenericPassword(this.state.username, this.state.password) .then(() => { @@ -91,6 +98,11 @@ export default class KeychainExample extends Component { {!!this.state.status && ( {this.state.status} )} + {!!this.state.biometryType && ( + + Supported biometry: {this.state.biometryType} + + )} this.save()} @@ -160,6 +172,11 @@ const styles = StyleSheet.create({ fontSize: 12, marginTop: 15, }, + biometryType: { + color: '#333', + fontSize: 12, + marginTop: 15, + }, buttons: { flexDirection: 'row', justifyContent: 'space-between', diff --git a/RNKeychainManager/RNKeychainManager.m b/RNKeychainManager/RNKeychainManager.m index 4fa50c0..39031e6 100644 --- a/RNKeychainManager/RNKeychainManager.m +++ b/RNKeychainManager/RNKeychainManager.m @@ -178,6 +178,23 @@ RCT_EXPORT_METHOD(canCheckAuthentication:(NSDictionary *)options resolver:(RCTPr } } +RCT_EXPORT_METHOD(getSupportedBiometryType:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +{ + NSError *aerr = nil; + LAContext *context = [LAContext new]; + BOOL canBeProtected = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&aerr]; + + if (!aerr && canBeProtected) { + if (@available(iOS 11, *)) { + if (context.biometryType == LABiometryTypeFaceID) { + return resolve(@"FaceID"); + } + } + return resolve(@"TouchID"); + } + return resolve([NSNull null]); +} + - (BOOL) canCheckAuthentication:(LAPolicy)policyToEvaluate error:(NSError **)err { return [[[ LAContext alloc] init ] canEvaluatePolicy:policyToEvaluate error:err ]; } diff --git a/index.js b/index.js index f6093d0..d4f5a31 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,11 @@ import { NativeModules, Platform } from 'react-native'; const { RNKeychainManager } = NativeModules; +export const BIOMETRY_TYPE = { + TOUCH_ID: 'TouchID', + FACE_ID: 'FaceID', +}; + type SecAccessible = | 'AccessibleWhenUnlocked' | 'AccessibleAfterFirstUnlock' @@ -49,6 +54,22 @@ export function canImplyAuthentication(options?: SecureOptions): Promise { return RNKeychainManager.canCheckAuthentication(options); } +/** + * Get what type of local authentication policy (LAPolicy) is supported + * on this device with the device settings the user chose. + * @return {Promise} Resolves to a `BIOMETRY_TYPE` when supported, otherwise `null` + */ +export function getSupportedBiometryType(): Promise { + if (Platform.OS !== 'ios') { + return Promise.reject( + new Error( + `getSupportedBiometryType() is not supported on ${Platform.OS} yet` + ) + ); + } + return RNKeychainManager.getSupportedBiometryType(); +} + /** * Saves the `username` and `password` combination for `service` securely - needs authentication to retrieve it. * @param {string} service Associated service.