react-native-biometrics-authentication
Version:
React Native biometric functionality for signing and encryption with optional fallback passcode option in IOS.
308 lines (270 loc) • 10.5 kB
text/typescript
import { NativeModules } from "react-native";
const { ReactNativeBiometrics: bridge } = NativeModules;
/**
* Type alias for possible biometry types
*/
export type BiometryType = "TouchID" | "FaceID" | "Biometrics";
interface RNBiometricsOptions {
allowDeviceCredentials?: boolean;
}
interface IsSensorAvailableResult {
available: boolean;
biometryType?: BiometryType;
error?: string;
}
interface CreateKeysResult {
publicKey: string;
}
interface BiometricKeysExistResult {
keysExist: boolean;
}
interface DeleteKeysResult {
keysDeleted: boolean;
}
interface CreateSignatureOptions {
promptMessage: string;
payload: string;
cancelButtonText?: string;
}
interface CreateSignatureResult {
success: boolean;
signature?: string;
error?: string;
}
interface SimplePromptOptions {
promptMessage: string;
fallbackPromptMessage?: string;
cancelButtonText?: string;
}
interface AuthenticationOptions {
promptMessage: string;
fallbackPromptMessage?: string;
cancelButtonText?: string;
errorCallback: Function;
successCallback: Function;
encryption: boolean;
}
interface SimplePromptResult {
success: boolean;
error?: string;
}
interface AuthenticationResult {
publicKey?: string;
error?: string;
}
interface ERROR_TYPE {}
/**
* Enum for touch id sensor type
*/
export const TouchID = "TouchID";
/**
* Enum for face id sensor type
*/
export const FaceID = "FaceID";
/**
* Enum for generic biometrics (this is the only value available on android)
*/
export const Biometrics = "Biometrics";
/**
* List of Biometrices Error Comes.
*/
export const BIOMETRY_ERROR_TYPE: ERROR_TYPE = {
limitExceed: "Too many attempts. Try again later.",
sensorDisable: "Too many attempts. Fingerprint sensor disabled.",
signatureInvalidate: "Error generating signature",
fingerPrintDisabled: "Your Finger Print is Locked.",
};
/**
* List of Biometrices Error Comes during enrollement.
*/
export const BIOMETRY_ENROLLED_ERROR_TYPE: ERROR_TYPE = {
biometricNotEnroll: "BIOMETRIC_ERROR_NONE_ENROLLED",
biometricNotSupport: "BIOMETRIC_ERROR_NO_HARDWARE",
biometricHWUnavailable: "BIOMETRIC_ERROR_HW_UNAVAILABLE",
biometricPasscodeNotEnrolled:
'Error Domain=com.apple.LocalAuthentication Code=-5 "Passcode not set." UserInfo={NSDebugDescription=Passcode not set., NSLocalizedDescription=Passcode is not set.}',
biometricNotEnrollIOS:
'Error Domain=com.apple.LocalAuthentication Code=-7 "No identities are enrolled." UserInfo={NSDebugDescription=No identities are enrolled., NSLocalizedDescription=Biometry is not enrolled.}',
biometricDeviceLockOut:
'Error Domain=com.apple.LocalAuthentication Code=-8 "Biometry is locked out." UserInfo={NSDebugDescription=Biometry is locked out., NSLocalizedDescription=Biometry is locked out.}',
};
export const BiometryTypes = {
TouchID,
FaceID,
Biometrics,
};
export module ReactNativeBiometricsLegacy {
/**
* Returns promise that resolves to an object with object.biometryType = Biometrics | TouchID | FaceID
* @returns {Promise<Object>} Promise that resolves to an object with details about biometrics available
*/
export function isSensorAvailable(): Promise<IsSensorAvailableResult> {
return new ReactNativeBiometrics().isSensorAvailable();
}
/**
* Creates a public private key pair,returns promise that resolves to
* an object with object.publicKey, which is the public key of the newly generated key pair
* @returns {Promise<Object>} Promise that resolves to object with details about the newly generated public key
*/
export function createKeys(): Promise<CreateKeysResult> {
return new ReactNativeBiometrics().createKeys();
}
/**
* Returns promise that resolves to an object with object.keysExists = true | false
* indicating if the keys were found to exist or not
* @returns {Promise<Object>} Promise that resolves to object with details about the existence of keys
*/
export function biometricKeysExist(): Promise<BiometricKeysExistResult> {
return new ReactNativeBiometrics().biometricKeysExist();
}
/**
* Returns promise that resolves to an object with true | false
* indicating if the keys were properly deleted
* @returns {Promise<Object>} Promise that resolves to an object with details about the deletion
*/
export function deleteKeys(): Promise<DeleteKeysResult> {
return new ReactNativeBiometrics().deleteKeys();
}
/**
* Prompts user with biometrics dialog using the passed in prompt message and
* returns promise that resolves to an object with object.signature,
* which is cryptographic signature of the payload
* @param {Object} createSignatureOptions
* @param {string} createSignatureOptions.promptMessage
* @param {string} createSignatureOptions.payload
* @returns {Promise<Object>} Promise that resolves to an object cryptographic signature details
*/
export function createSignature(
createSignatureOptions: CreateSignatureOptions
): Promise<CreateSignatureResult> {
return new ReactNativeBiometrics().createSignature(createSignatureOptions);
}
/**
* Prompts user with biometrics dialog using the passed in prompt message and
* returns promise that resolves to an object with object.success = true if the user passes,
* object.success = false if the user cancels, and rejects if anything fails
* @param {Object} simplePromptOptions
* @param {string} simplePromptOptions.promptMessage
* @param {string} simplePromptOptions.fallbackPromptMessage
* @returns {Promise<Object>} Promise that resolves an object with details about the biometrics result
*/
export function simplePrompt(
simplePromptOptions: SimplePromptOptions
): Promise<SimplePromptResult> {
return new ReactNativeBiometrics().simplePrompt(simplePromptOptions);
}
}
export default class ReactNativeBiometrics {
allowDeviceCredentials = false;
/**
* @param {Object} rnBiometricsOptions
* @param {boolean} rnBiometricsOptions.allowDeviceCredentials
*/
constructor(rnBiometricsOptions?: RNBiometricsOptions) {
const allowDeviceCredentials =
rnBiometricsOptions?.allowDeviceCredentials ?? false;
this.allowDeviceCredentials = allowDeviceCredentials;
}
/**
* Returns promise that resolves to an object with object.biometryType = Biometrics | TouchID | FaceID
* @returns {Promise<Object>} Promise that resolves to an object with details about biometrics available
*/
isSensorAvailable(): Promise<IsSensorAvailableResult> {
return bridge.isSensorAvailable({
allowDeviceCredentials: this.allowDeviceCredentials,
});
}
/**
* Creates a public private key pair,returns promise that resolves to
* an object with object.publicKey, which is the public key of the newly generated key pair
* @returns {Promise<Object>} Promise that resolves to object with details about the newly generated public key
*/
createKeys(): Promise<CreateKeysResult> {
return bridge.createKeys({
allowDeviceCredentials: this.allowDeviceCredentials,
});
}
/**
* Returns promise that resolves to an object with object.keysExists = true | false
* indicating if the keys were found to exist or not
* @returns {Promise<Object>} Promise that resolves to object with details aobut the existence of keys
*/
biometricKeysExist(): Promise<BiometricKeysExistResult> {
return bridge.biometricKeysExist();
}
/**
* Returns promise that resolves to an object with true | false
* indicating if the keys were properly deleted
* @returns {Promise<Object>} Promise that resolves to an object with details about the deletion
*/
deleteKeys(): Promise<DeleteKeysResult> {
return bridge.deleteKeys();
}
/**
* Prompts user with biometrics dialog using the passed in prompt message and
* returns promise that resolves to an object with object.signature,
* which is cryptographic signature of the payload
* @param {Object} createSignatureOptions
* @param {string} createSignatureOptions.promptMessage
* @param {string} createSignatureOptions.payload
* @returns {Promise<Object>} Promise that resolves to an object cryptographic signature details
*/
createSignature(
createSignatureOptions: CreateSignatureOptions
): Promise<CreateSignatureResult> {
createSignatureOptions.cancelButtonText =
createSignatureOptions.cancelButtonText ?? "Cancel";
return bridge.createSignature({
allowDeviceCredentials: this.allowDeviceCredentials,
...createSignatureOptions,
});
}
/**
* Prompts user with biometrics dialog using the passed in prompt message and
* returns promise that resolves to an object with object.success = true if the user passes,
* object.success = false if the user cancels, and rejects if anything fails
* @param {Object} simplePromptOptions
* @param {string} simplePromptOptions.promptMessage
* @param {string} simplePromptOptions.fallbackPromptMessage
* @returns {Promise<Object>} Promise that resolves an object with details about the biometrics result
*/
simplePrompt(
simplePromptOptions: SimplePromptOptions
): Promise<SimplePromptResult> {
simplePromptOptions.cancelButtonText =
simplePromptOptions.cancelButtonText ?? "Cancel";
simplePromptOptions.fallbackPromptMessage =
simplePromptOptions.fallbackPromptMessage ?? "Use Passcode";
return bridge.simplePrompt({
allowDeviceCredentials: this.allowDeviceCredentials,
...simplePromptOptions,
});
}
async generateKey() {
const response = await this.createKeys();
return response.publicKey;
}
async _addDeviceAuthenticationUtil(
authenticationOptions: AuthenticationOptions
) {
const response = await this.simplePrompt({
promptMessage: authenticationOptions.promptMessage,
fallbackPromptMessage: authenticationOptions.fallbackPromptMessage,
cancelButtonText: authenticationOptions.cancelButtonText,
});
if (response.success) {
return authenticationOptions.successCallback({
publicKey: authenticationOptions.encryption ? this.generateKey() : "",
});
} else if (response.error) {
return authenticationOptions.errorCallback({
error: response.error,
});
}
}
addDeviceAuthentication(
authenticationOptions: AuthenticationOptions
): Promise<AuthenticationResult> {
return this._addDeviceAuthenticationUtil(authenticationOptions);
}
}