UNPKG

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

Version:

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

533 lines (498 loc) 19.5 kB
/** * Copyright © 2023-2024 Nevis Security AG. All rights reserved. */ import { PlatformOperation } from './PlatformOperation'; import { Aaid } from '../../localData/Aaid'; import { Authenticator } from '../../localData/Authenticator'; import NevisMobileAuthenticationSdkReact from '../../MobileAuthenticationSdk'; import { PasswordValidatedMessage } from '../../model/messages/out/PasswordValidatedMessage'; import { PinValidatedMessage } from '../../model/messages/out/PinValidatedMessage'; import type { PasswordChangeContext } from '../../operations/password/PasswordChangeContext'; import { PasswordChangeHandler, PasswordChangeHandlerImpl, } from '../../operations/password/PasswordChangeHandler'; import type { PasswordChanger } from '../../operations/password/PasswordChanger'; import type { PasswordEnroller } from '../../operations/password/PasswordEnroller'; import type { PasswordEnrollmentContext } from '../../operations/password/PasswordEnrollmentContext'; import { PasswordEnrollmentHandler, PasswordEnrollmentHandlerImpl, } from '../../operations/password/PasswordEnrollmentHandler'; import { PinChangeContext } from '../../operations/pin/PinChangeContext'; import { PinChangeHandler, PinChangeHandlerImpl } from '../../operations/pin/PinChangeHandler'; import { PinChanger } from '../../operations/pin/PinChanger'; import { PinEnroller } from '../../operations/pin/PinEnroller'; import type { PinEnrollmentContext } from '../../operations/pin/PinEnrollmentContext'; import { PinEnrollmentHandler, PinEnrollmentHandlerImpl, } from '../../operations/pin/PinEnrollmentHandler'; import type { AccountSelectionContext } from '../../operations/selection/AccountSelectionContext'; import { AccountSelectionHandler, AccountSelectionHandlerImpl, } from '../../operations/selection/AccountSelectionHandler'; import { AccountSelector } from '../../operations/selection/AccountSelector'; import type { AuthenticatorSelectionContext } from '../../operations/selection/AuthenticatorSelectionContext'; import { AuthenticatorSelectionHandler, AuthenticatorSelectionHandlerImpl, } from '../../operations/selection/AuthenticatorSelectionHandler'; import { AuthenticatorSelector } from '../../operations/selection/AuthenticatorSelector'; import type { BiometricUserVerificationHandler } from '../../operations/userverification/BiometricUserVerificationHandler'; import { BiometricUserVerifier } from '../../operations/userverification/BiometricUserVerifier'; import type { DevicePasscodeUserVerificationHandler } from '../../operations/userverification/DevicePasscodeUserVerificationHandler'; import { DevicePasscodeUserVerifier } from '../../operations/userverification/DevicePasscodeUserVerifier'; import type { FingerprintUserVerificationHandler } from '../../operations/userverification/FingerprintUserVerificationHandler'; import { FingerprintUserVerifier } from '../../operations/userverification/FingerprintUserVerifier'; import type { PasswordUserVerificationContext } from '../../operations/userverification/PasswordUserVerificationContext'; import type { PasswordUserVerificationHandler } from '../../operations/userverification/PasswordUserVerificationHandler'; import type { PasswordUserVerifier } from '../../operations/userverification/PasswordUserVerifier'; import type { PinUserVerificationContext } from '../../operations/userverification/PinUserVerificationContext'; import type { PinUserVerificationHandler } from '../../operations/userverification/PinUserVerificationHandler'; import { PinUserVerifier } from '../../operations/userverification/PinUserVerifier'; import type { UserVerificationContext } from '../../operations/userverification/UserVerificationContext'; import type { UserVerificationHandler } from '../../operations/userverification/UserVerificationHandler'; /** * Helps in following the states of user interaction operations during method * channel calls. */ export abstract class UserInteractionPlatformOperation extends PlatformOperation { /** * The {@link AccountSelector} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract accountSelector?: AccountSelector; /** * The {@link AuthenticatorSelector} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract authenticatorSelector?: AuthenticatorSelector; /** * The {@link PinEnroller} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract pinEnroller?: PinEnroller; /** * The {@link PasswordEnroller} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract passwordEnroller?: PasswordEnroller; /** * The {@link PinChanger} given when an operation is started. */ abstract pinChanger?: PinChanger; /** * The {@link PasswordChanger} given when an operation is started. */ abstract passwordChanger?: PasswordChanger; /** * The {@link PinUserVerifier} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract pinUserVerifier?: PinUserVerifier; /** * The {@link PasswordUserVerifier} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract passwordUserVerifier?: PasswordUserVerifier; /** * The {@link BiometricUserVerifier} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract biometricUserVerifier?: BiometricUserVerifier; /** * The {@link DevicePasscodeUserVerifier} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract devicePasscodeUserVerifier?: DevicePasscodeUserVerifier; /** * The {@link FingerprintUserVerifier} given when an operation is started. * * E.g.: During an out-of-band process. */ abstract fingerprintUserVerifier?: FingerprintUserVerifier; /** * The {@link AccountSelectionHandler} given when an operation is started. * * E.g.: During an out-of-band process. * This is generated automatically based on the {@link operationId}. */ abstract accountSelectionHandler?: AccountSelectionHandler; /** * The {@link AuthenticatorSelectionHandler} given when an operation is started. * * E.g.: During an out-of-band process. * This is generated automatically based on the {@link operationId}. */ abstract authenticatorSelectionHandler?: AuthenticatorSelectionHandler; /** * The {@link PinEnrollmentHandler} given when an operation is started. * * E.g.: During an out-of-band process. * This is generated automatically based on the {@link operationId}. */ abstract pinEnrollmentHandler?: PinEnrollmentHandler; /** * The {@link PasswordEnrollmentHandler} given when an operation is started. * * E.g.: During an out-of-band process. * This is generated automatically based on the {@link operationId}. */ abstract passwordEnrollmentHandler?: PasswordEnrollmentHandler; /** * The {@link PinChangeHandler} given when an operation is started. * * E.g.: During a pin change. * This is generated automatically based on the {@link operationId}. */ abstract pinChangeHandler?: PinChangeHandler; /** * The {@link PasswordChangeHandler} given when an operation is started. * * E.g.: During a password change. * This is generated automatically based on the {@link operationId}. */ abstract passwordChangeHandler?: PasswordChangeHandler; /** * The {@link UserVerificationHandler} given when an operation is in the state of user verification. */ abstract userVerificationHandler?: UserVerificationHandler; /** * The account selection interaction. * * The implementing class must ask the user to choose one of the accounts * exposed by the {@link AccountSelectionContext} and provide the choice to the * {@link AccountSelectionHandler}. * * @param context the object containing the list of existing accounts and authenticators. */ selectAccount(context: AccountSelectionContext): void { this.accountSelector?.selectAccount(context, this.accountSelectionHandler!); } /** * The authenticator selection interaction. * * The implementing class must ask the user to choose one of the authenticators * exposed by the {@link AuthenticatorSelectionContext} and provide the choice to the * {@link AuthenticatorSelectionHandler}. * * Note, that in the case of transaction confirmation (which can be considered * a special case of authentication) the implementing classes must present * the contents of the transaction (if any) to the user for verification * @see {@link AuthenticatorSelectionContext.transactionConfirmationData} * * @param context the object containing the list of existing authenticators. */ selectAuthenticator(context: AuthenticatorSelectionContext): void { this.authenticatorSelector?.selectAuthenticator( context, this.authenticatorSelectionHandler! ); } /** * The method that will be invoked till either the user provides a PIN that * conforms with the format specified by the {@link PinPolicy} or till the * operation is cancelled (through the {@link PinEnrollmentHandler.cancel}). * * @param context the context. */ enrollPin(context: PinEnrollmentContext): void { this.pinEnroller?.enrollPin(context, this.pinEnrollmentHandler!); } /** * The method that will be invoked till either the user provides a password that * conforms with the format specified by the {@link PasswordPolicy} or till the * operation is cancelled (through the {@link PasswordEnrollmentHandler.cancel}). * * @param context the context. */ enrollPassword(context: PasswordEnrollmentContext): void { this.passwordEnroller?.enrollPassword(context, this.passwordEnrollmentHandler!); } /** * The method that will be invoked till either the user provides the old PIN * and a new PIN that conforms with the format specified by the {@link PinPolicy}, * or till the operation is cancelled (through the {@link PinChangeHandler.cancel}), * or till the PIN authenticator is permanently locked because the user provided * too many times an invalid PIN. * * @param context the context. */ changePin(context: PinChangeContext) { this.pinChanger?.changePin(context, this.pinChangeHandler!); } /** * The method that will be invoked till either the user provides the old password * and a new password that conforms with the format specified by the {@link PasswordPolicy}, * or till the operation is cancelled (through the {@link PasswordChangeHandler.cancel}), * or till the password authenticator is permanently locked because the user provided * too many times an invalid password. * * @param context the context. */ changePassword(context: PasswordChangeContext) { this.passwordChanger?.changePassword(context, this.passwordChangeHandler!); } /** * The user verification interaction. * * In the case of the registration the user must provide credentials again as * required by the FIDO UAF protocol. * In the case of the authentication, this is invoked for the user to provide * credentials. * * If the user provided invalid credentials, and it results in a non-recoverable * error, then `onSuccess` method will be invoked. * * @param context the object providing the information required for the verification * process. * @param handler the object that must be notified with the result of the interaction. */ verifyUser(context: UserVerificationContext, handler: UserVerificationHandler): Promise<void> { switch (context.authenticator.aaid) { case Aaid.PIN.rawValue(): return this.pinUserVerifier!.verifyPin( context as PinUserVerificationContext, handler as PinUserVerificationHandler ); case Aaid.PASSWORD.rawValue(): return this.passwordUserVerifier!.verifyPassword( context as PasswordUserVerificationContext, handler as PasswordUserVerificationHandler ); case Aaid.BIOMETRIC.rawValue(): return this.biometricUserVerifier!.verifyBiometric( context, handler as BiometricUserVerificationHandler ); case Aaid.DEVICE_PASSCODE.rawValue(): return this.devicePasscodeUserVerifier!.verifyDevicePasscode( context, handler as DevicePasscodeUserVerificationHandler ); case Aaid.FINGERPRINT.rawValue(): return this.fingerprintUserVerifier!.verifyFingerprint( context, handler as FingerprintUserVerificationHandler ); } return Promise.reject( new Error( `No verifier found for Authenticator aaid ${context.authenticator.aaid} when verifying the user.` ) ); } /** * This method is invoked when either valid local system credentials (biometric, * fingerprint) or valid SDK-managed credentials (PIN, password) were provided * and verified locally. * * This method can be used for instance to display some progress message * indicating that the operation is ongoing. * * Note that invoking this method does not mean that the UAF operation completed * successfully (this is notified through `onSuccess` methods once the FIDO UAF * server validates the request generated with the credentials). * * @param authenticator the object describing the authenticator where credentials * were validated. */ onValidCredentialsProvided(authenticator: Authenticator): void { switch (authenticator.aaid) { case Aaid.PIN.rawValue(): return this.pinUserVerifier?.onValidCredentialsProvided(); case Aaid.PASSWORD.rawValue(): return this.passwordUserVerifier?.onValidCredentialsProvided(); case Aaid.BIOMETRIC.rawValue(): return this.biometricUserVerifier?.onValidCredentialsProvided(); case Aaid.DEVICE_PASSCODE.rawValue(): return this.devicePasscodeUserVerifier?.onValidCredentialsProvided(); case Aaid.FINGERPRINT.rawValue(): return this.fingerprintUserVerifier?.onValidCredentialsProvided(); } throw new Error( `No verifier found for Authenticator aaid ${authenticator.aaid} when valid credentials provided.` ); } /** * Performs validation other than the minimum and maximum PIN length during PIN enrollment. * * @param pin the PIN to be validated. */ validatePinForEnrollment(pin: string) { this.pinEnroller?.pinPolicy.validatePinForEnrollment( pin, () => { (async () => { const message = new PinValidatedMessage(this.operationId, undefined, undefined); await NevisMobileAuthenticationSdkReact.pinValidatedForEnrollment(message); })(); }, (error) => { (async () => { const message = new PinValidatedMessage( this.operationId, error.description, error.cause ); await NevisMobileAuthenticationSdkReact.pinValidatedForEnrollment(message); })(); } ); } /** * Performs validation during password enrollment. * * @param password the password to be validated. */ validatePasswordForEnrollment(password: string) { this.passwordEnroller?.passwordPolicy.validatePasswordForEnrollment( password, () => { (async () => { const message = new PasswordValidatedMessage( this.operationId, undefined, undefined ); await NevisMobileAuthenticationSdkReact.passwordValidatedForEnrollment(message); })(); }, (error) => { (async () => { const message = new PasswordValidatedMessage( this.operationId, error.description, error.cause ); await NevisMobileAuthenticationSdkReact.passwordValidatedForEnrollment(message); })(); } ); } /** * Performs validation other than the minimum and maximum PIN length during PIN change. * * @param pin the PIN to be validated. */ validatePinForPinChange(pin: string) { this.pinChanger?.pinPolicy.validatePinForPinChange( pin, () => { (async () => { const message = new PinValidatedMessage(this.operationId, undefined, undefined); await NevisMobileAuthenticationSdkReact.pinValidatedForPinChange(message); })(); }, (error) => { (async () => { const message = new PinValidatedMessage( this.operationId, error.description, error.cause ); await NevisMobileAuthenticationSdkReact.pinValidatedForPinChange(message); })(); } ); } /** * Performs validation during password enrollment. * * @param password the password to be validated. */ validatePasswordForPasswordChange(password: string) { this.passwordChanger?.passwordPolicy.validatePasswordForPasswordChange( password, () => { (async () => { const message = new PasswordValidatedMessage( this.operationId, undefined, undefined ); await NevisMobileAuthenticationSdkReact.passwordValidatedForPasswordChange( message ); })(); }, (error) => { (async () => { const message = new PasswordValidatedMessage( this.operationId, error.description, error.cause ); await NevisMobileAuthenticationSdkReact.passwordValidatedForPasswordChange( message ); })(); } ); } } export class UserInteractionPlatformOperationImpl extends UserInteractionPlatformOperation { operationId: string; accountSelector?: AccountSelector; accountSelectionHandler?: AccountSelectionHandler; authenticatorSelector?: AuthenticatorSelector; authenticatorSelectionHandler?: AuthenticatorSelectionHandler; pinEnroller?: PinEnroller; pinEnrollmentHandler?: PinEnrollmentHandler; passwordEnroller?: PasswordEnroller; passwordEnrollmentHandler?: PasswordEnrollmentHandler; pinChanger?: PinChanger; pinChangeHandler?: PinChangeHandler; passwordChanger?: PasswordChanger; passwordChangeHandler?: PasswordChangeHandler; pinUserVerifier?: PinUserVerifier; passwordUserVerifier?: PasswordUserVerifier; biometricUserVerifier?: BiometricUserVerifier; devicePasscodeUserVerifier?: DevicePasscodeUserVerifier; fingerprintUserVerifier?: FingerprintUserVerifier; userVerificationHandler?: UserVerificationHandler; constructor( operationId: string, accountSelector?: AccountSelector, authenticatorSelector?: AuthenticatorSelector, pinEnroller?: PinEnroller, passwordEnroller?: PasswordEnroller, pinChanger?: PinChanger, passwordChanger?: PasswordChanger, pinUserVerifier?: PinUserVerifier, passwordUserVerifier?: PasswordUserVerifier, biometricUserVerifier?: BiometricUserVerifier, devicePasscodeUserVerifier?: DevicePasscodeUserVerifier, fingerprintUserVerifier?: FingerprintUserVerifier ) { super(); this.operationId = operationId; this.accountSelector = accountSelector; this.authenticatorSelector = authenticatorSelector; this.pinEnroller = pinEnroller; this.passwordEnroller = passwordEnroller; this.pinChanger = pinChanger; this.passwordChanger = passwordChanger; this.pinUserVerifier = pinUserVerifier; this.passwordUserVerifier = passwordUserVerifier; this.biometricUserVerifier = biometricUserVerifier; this.devicePasscodeUserVerifier = devicePasscodeUserVerifier; this.fingerprintUserVerifier = fingerprintUserVerifier; this.accountSelectionHandler = new AccountSelectionHandlerImpl(operationId); this.authenticatorSelectionHandler = new AuthenticatorSelectionHandlerImpl(operationId); this.pinEnrollmentHandler = new PinEnrollmentHandlerImpl(operationId); this.passwordEnrollmentHandler = new PasswordEnrollmentHandlerImpl(operationId); this.pinChangeHandler = new PinChangeHandlerImpl(operationId); this.passwordChangeHandler = new PasswordChangeHandlerImpl(operationId); } }