UNPKG

@nevis-security/nevis-mobile-authentication-sdk-react

Version:

React Native plugin for Nevis Mobile Authentication SDK. Supports only mobile.

166 lines (154 loc) 6.65 kB
/** * Copyright © 2023 Nevis Security AG. All rights reserved. */ import { UserInteractionPlatformOperation } from '../../cache/operation/UserInteractionPlatformOperation'; import { PlatformOperationCache } from '../../cache/PlatformOperationCache'; import NevisMobileAuthenticationSdkReact from '../../MobileAuthenticationSdk'; import { OperationIdMessage } from '../../model/messages/out/OperationIdMessage'; /** * An object that can be used to pause or resume listening for OS credentials (i.e. fingerprint, face * recognition) and to cancel the whole operation while listening for credentials. * * **IMPORTANT** \ * The {@link OsAuthenticationListenHandler} class is Android specific. * * This is used with {@link Aaid.BIOMETRIC}, {@link Aaid.DEVICE_PASSCODE} and {@link Aaid.FINGERPRINT} * authenticator attestation identifiers. * * @see * - {@link BiometricUserVerificationHandler.listenForOsCredentials} * - {@link DevicePasscodeUserVerificationHandler.listenForOsCredentials} * - {@link FingerprintUserVerificationHandler.listenForOsCredentials} */ export abstract class OsAuthenticationListenHandler { /** * Cancels the authentication operation. * * This will result in the operation being canceled and an {@link OperationError} or * an {@link OperationFidoError} with a {@link FidoErrorCodeType.UserCanceled} will be returned. */ abstract cancelAuthentication(): Promise<void>; /** * Pauses listening for OS credentials. * * If the application is listening for OS credentials, and it is brought to the background, then * the operating system will cancel automatically listening for credentials and will send an error. * This method must be invoked when the application is brought to the background before the OS * cancels the authentication and the SDK sends an error. * * Invoking this method will have effect only if {@link cancelAuthentication} was not previously * invoked. * * The method can be invoked from the [AppState](https://reactnative.dev/docs/appstate) event listener * when the new state is `inactive` or `background` and the current state is `active`. * Note that this approach does not work in some devices (in these devices the event listener is * invoked after the OS cancels the authentication). * * For example: * ```ts * const appState = useRef(AppState.currentState); * const [listenHandler, setListenHandler] = useState<OsAuthenticationListenHandler>(); * * useCallback(() => { * const onStateChange = async (nextAppState: AppStateStatus) => { * if (appState.current === 'active' && nextAppState.match(/inactive|background/)) { * if (listenHandler !== undefined) { * await listenHandler.pauseListening() * .then((newListenHandler) => { * setListenHandler(newListenHandler); * }) * .catch(ErrorHandler.handle.bind(null, OperationType.unknown)); * } * } * * appState.current = nextAppState; * }; * * const subscription = AppState.addEventListener('change', onStateChange); * return () => subscription.remove(); * }, [appState, listenHandler]); * ``` * * @returns the {@link OsAuthenticationListenHandler} to handle the new listening. */ abstract pauseListening(): Promise<OsAuthenticationListenHandler>; /** * Resumes listening for OS credentials. * * If the application is listening for OS credentials and it is brought to the background, then * the operating system will cancel automatically listening for credentials. * This method must be invoked when the application is brought to the foreground again to resume * listening for credentials. * * Invoking this method will have effect only if {@link cancelAuthentication} was not previously * invoked. * * The method is typically invoked from the [AppState](https://reactnative.dev/docs/appstate) event * listener when the new state is `active` and the current state is `inactive` or `background`. * * For example: * ```ts * const appState = useRef(AppState.currentState); * const [listenHandler, setListenHandler] = useState<OsAuthenticationListenHandler>(); * * useCallback(() => { * const onStateChange = async (nextAppState: AppStateStatus) => { * if (appState.current.match(/inactive|background/) && nextAppState === 'active') { * if (listenHandler !== undefined) { * await listenHandler.resumeListening() * .then((newListenHandler) => { * setListenHandler(newListenHandler); * }) * .catch(ErrorHandler.handle.bind(null, OperationType.unknown)); * } * } * * appState.current = nextAppState; * }; * * const subscription = AppState.addEventListener('change', onStateChange); * return () => subscription.remove(); * }, [appState, listenHandler]); * ``` * * @returns the {@link OsAuthenticationListenHandler} to handle the new listening. */ abstract resumeListening(): Promise<OsAuthenticationListenHandler>; } export class OsAuthenticationListenHandlerImpl extends OsAuthenticationListenHandler { private readonly _operationId: string; constructor(operationId: string) { super(); this._operationId = operationId; } async cancelAuthentication(): Promise<void> { const message = new OperationIdMessage(this._operationId); return NevisMobileAuthenticationSdkReact.cancelAuthentication(message); } async pauseListening(): Promise<OsAuthenticationListenHandler> { const operation = PlatformOperationCache.getInstance().read(this._operationId); if ( !(operation instanceof UserInteractionPlatformOperation) || operation.userVerificationHandler === undefined ) { return this; } const message = new OperationIdMessage(this._operationId); return NevisMobileAuthenticationSdkReact.pauseListening(message).then(() => { return this; }); } async resumeListening(): Promise<OsAuthenticationListenHandler> { const operation = PlatformOperationCache.getInstance().read(this._operationId); if ( !(operation instanceof UserInteractionPlatformOperation) || operation.userVerificationHandler === undefined ) { return this; } const message = new OperationIdMessage(this._operationId); return NevisMobileAuthenticationSdkReact.resumeListening(message).then(() => { return this; }); } }