@nevis-security/nevis-mobile-authentication-sdk-react
Version:
React Native plugin for Nevis Mobile Authentication SDK. Supports only mobile.
355 lines (328 loc) • 13 kB
text/typescript
/**
* Copyright © 2023-2024 Nevis Security AG. All rights reserved.
*/
import type { AuthorizationProvider } from '../../authorization/AuthorizationProvider';
import { UserInteractionPlatformOperationImpl } from '../../cache/operation/UserInteractionPlatformOperation';
import { PlatformOperationCache } from '../../cache/PlatformOperationCache';
import { OperationError } from '../../error/operation/OperationError';
import { OperationErrorConverter } from '../../error/operation/OperationErrorConverter';
import { NativeEventListener } from '../../event/NativeEventListener';
import NevisMobileAuthenticationSdkReact from '../../MobileAuthenticationSdk';
import { OnSuccessMessage } from '../../model/messages/in/OnSuccessMessage';
import { OutOfBandAuthenticationMessage } from '../../model/messages/out/OutOfBandAuthenticationMessage';
import { HttpOperation, HttpOperationImpl } from '../HttpOperation';
import { AccountSelector } from '../selection/AccountSelector';
import { AuthenticatorSelector } from '../selection/AuthenticatorSelector';
import { BiometricUserVerifier } from '../userverification/BiometricUserVerifier';
import { DevicePasscodeUserVerifier } from '../userverification/DevicePasscodeUserVerifier';
import { FingerprintUserVerifier } from '../userverification/FingerprintUserVerifier';
import type { PasswordUserVerifier } from '../userverification/PasswordUserVerifier';
import { PinUserVerifier } from '../userverification/PinUserVerifier';
/**
* The operation handling an out-of-band authentication.
*
* This is the object returned by the SDK, when an {@link OutOfBandPayload} was processed and the
* {@link OutOfBandPayload} corresponds to an authentication operation.
*
* Usage example:
* ```ts
* class AccountSelectorImpl extends AccountSelector {
* async selectAccount(
* context: AccountSelectionContext,
* handler: AccountSelectionHandler
* ): Promise<void> {
* await handler.username(username).catch(console.error);
* }
* }
*
* class AuthenticatorSelectorImpl extends AuthenticatorSelector {
* async selectAuthenticator(
* context: AuthenticatorSelectionContext,
* handler: AuthenticatorSelectionHandler
* ): Promise<void> {
* await handler.aaid(aaid).catch(console.error);
* }
* }
*
* class PinUserVerifierImpl extends PinUserVerifier {
* async verifyPin(
* context: PinVerificationContext,
* handler: PinVerificationHandler
* ): Promise<void> {
* await handler.verifyPin(pin).catch(console.error);
* }
* }
*
* class BiometricUserVerifierImpl extends BiometricUserVerifier {
* async verifyBiometric(
* context: BiometricUserVerificationContext,
* handler: BiometricUserVerificationHandler
* ): Promise<void> {
* await handler
* .listenForOsCredentials(
* BiometricPromptOptions.create(
* 'Biometric authentication required',
* 'Cancel',
* 'Please identify yourself.'
* )
* )
* .catch(console.error);
* }
* }
*
* async authenticateWithOutOfBand(
* client: MobileAuthenticationClient,
* payload: OutOfBandPayload
* ): Promise<void> {
* await client.operations.outOfBandOperation
* .payload(payload)
* .onRegistration((registration) => {
* // handle registration
* })
* .onAuthentication((authentication) => {
* authentication
* .accountSelector(new AccountSelectorImpl())
* .authenticatorSelector(new AuthenticatorSelectorImpl())
* .pinUserVerifier(new PinUserVerifierImpl())
* .biometricUserVerifier(new BiometricUserVerifierImpl())
* .onSuccess((authorizationProvider) => {
* // handle success
* })
* .onError((error) => {
* // handle error
* })
* .execute();
* })
* .onError((_error) => {
* // handle out-of-band error
* })
* .execute();
* }
* ```
*
* @see {@link OutOfBandOperation.onAuthentication}
*/
export abstract class OutOfBandAuthentication extends HttpOperation<OutOfBandAuthentication> {
/**
* Specifies the object that will take care of the account selection.
*
* @param accountSelector the {@link AccountSelector}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract accountSelector(accountSelector: AccountSelector): OutOfBandAuthentication;
/**
* Specifies the object that will take care of the selection of the authenticator to be used.
*
* **IMPORTANT** \
* Providing the authenticator selector is required.
*
* @param authenticatorSelector the {@link AuthenticatorSelector}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract authenticatorSelector(
authenticatorSelector: AuthenticatorSelector
): OutOfBandAuthentication;
/**
* Specifies the object that will take care of the PIN user verification.
*
* **IMPORTANT** \
*
* Providing at least one of the {@link PinUserVerifier}, {@link PasswordUserVerifier},
* {@link BiometricUserVerifier} or {@link DevicePasscodeUserVerifier} or {@link FingerprintUserVerifier}
* is required.
*
* @param pinUserVerifier the {@link PinUserVerifier}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract pinUserVerifier(pinUserVerifier: PinUserVerifier): OutOfBandAuthentication;
/**
* Specifies the object that will take care of the password user verification.
*
* **IMPORTANT** \
* Providing at least one of the {@link PinUserVerifier}, {@link PasswordUserVerifier},
* {@link BiometricUserVerifier} or {@link DevicePasscodeUserVerifier} or {@link FingerprintUserVerifier}
* is required.
*
* @param passwordUserVerifier the {@link PasswordUserVerifier}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract passwordUserVerifier(
passwordUserVerifier: PasswordUserVerifier
): OutOfBandAuthentication;
/**
* Specifies the object that will take care of the biometric user verification.
* It must be provided only if a biometric authenticator must be registered.
*
* **IMPORTANT** \
* Providing at least one of the {@link PinUserVerifier}, {@link PasswordUserVerifier},
* {@link BiometricUserVerifier} or {@link DevicePasscodeUserVerifier} or {@link FingerprintUserVerifier}
* is required.
*
* @param biometricUserVerifier the {@link BiometricUserVerifier}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract biometricUserVerifier(
biometricUserVerifier: BiometricUserVerifier
): OutOfBandAuthentication;
/**
* Specifies the object that will take care of the device passcode user verification.
* It must be provided only if a device passcode authenticator must be registered.
*
* **IMPORTANT** \
* Providing at least one of the {@link PinUserVerifier}, {@link PasswordUserVerifier},
* {@link BiometricUserVerifier} or {@link DevicePasscodeUserVerifier} or {@link FingerprintUserVerifier}
* is required.
*
* @param devicePasscodeUserVerifier the {@link DevicePasscodeUserVerifier}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract devicePasscodeUserVerifier(
devicePasscodeUserVerifier: DevicePasscodeUserVerifier
): OutOfBandAuthentication;
/**
* Specifies the object that will take care of the fingerprint user verification.
* It must be provided only if a fingerprint authenticator must be registered.
*
* **IMPORTANT** \
* Providing at least one of the {@link PinUserVerifier}, {@link PasswordUserVerifier},
* {@link BiometricUserVerifier} or {@link DevicePasscodeUserVerifier} or {@link FingerprintUserVerifier}
* is required.
*
* @param fingerprintUserVerifier the {@link FingerprintUserVerifier}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract fingerprintUserVerifier(
fingerprintUserVerifier: FingerprintUserVerifier
): OutOfBandAuthentication;
/**
* Specifies the object that will be invoked if the authentication was successful.
*
* **IMPORTANT** \
* Providing the {@link onSuccess} is required.
*
* @param onSuccess the callback which receives an optional {@link AuthorizationProvider}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract onSuccess(
onSuccess: (authorizationProvider?: AuthorizationProvider) => void
): OutOfBandAuthentication;
/**
* Specifies the object that will be invoked if the authentication failed.
*
* **IMPORTANT** \
* Providing the {@link onError} is required.
*
* @param onError the callback which receives an {@link OperationError}.
* @returns an {@link OutOfBandAuthentication} object.
*/
abstract onError(onError: (error: OperationError) => void): OutOfBandAuthentication;
}
export class OutOfBandAuthenticationImpl
extends HttpOperationImpl<OutOfBandAuthentication>
implements OutOfBandAuthentication
{
operationId: string;
private _accountSelector?: AccountSelector;
private _authenticatorSelector?: AuthenticatorSelector;
private _pinUserVerifier?: PinUserVerifier;
private _passwordUserVerifier?: PasswordUserVerifier;
private _biometricUserVerifier?: BiometricUserVerifier;
private _devicePasscodeUserVerifier?: DevicePasscodeUserVerifier;
private _fingerprintUserVerifier?: FingerprintUserVerifier;
private _onSuccess?: (authorizationProvider?: AuthorizationProvider) => void;
private _onError?: (error: OperationError) => void;
constructor(operationId: string) {
super();
this.operationId = operationId;
}
accountSelector(accountSelector: AccountSelector): OutOfBandAuthentication {
this._accountSelector = accountSelector;
return this;
}
authenticatorSelector(authenticatorSelector: AuthenticatorSelector): OutOfBandAuthentication {
this._authenticatorSelector = authenticatorSelector;
return this;
}
pinUserVerifier(pinUserVerifier: PinUserVerifier): OutOfBandAuthentication {
this._pinUserVerifier = pinUserVerifier;
return this;
}
passwordUserVerifier(passwordUserVerifier: PasswordUserVerifier): OutOfBandAuthentication {
this._passwordUserVerifier = passwordUserVerifier;
return this;
}
biometricUserVerifier(biometricUserVerifier: BiometricUserVerifier): OutOfBandAuthentication {
this._biometricUserVerifier = biometricUserVerifier;
return this;
}
devicePasscodeUserVerifier(
devicePasscodeUserVerifier: DevicePasscodeUserVerifier
): OutOfBandAuthentication {
this._devicePasscodeUserVerifier = devicePasscodeUserVerifier;
return this;
}
fingerprintUserVerifier(
fingerprintUserVerifier: FingerprintUserVerifier
): OutOfBandAuthentication {
this._fingerprintUserVerifier = fingerprintUserVerifier;
return this;
}
onSuccess(
onSuccess: (authorizationProvider?: AuthorizationProvider) => void
): OutOfBandAuthentication {
this._onSuccess = onSuccess;
return this;
}
onError(onError: (error: OperationError) => void): OutOfBandAuthentication {
this._onError = onError;
return this;
}
async execute(): Promise<void> {
const operation = new UserInteractionPlatformOperationImpl(
this.operationId,
this._accountSelector,
this._authenticatorSelector,
undefined,
undefined,
undefined,
undefined,
this._pinUserVerifier,
this._passwordUserVerifier,
this._biometricUserVerifier,
this._devicePasscodeUserVerifier,
this._fingerprintUserVerifier
);
PlatformOperationCache.getInstance().put(operation);
NativeEventListener.getInstance().start(this.operationId);
const message = new OutOfBandAuthenticationMessage(
this.operationId,
this._accountSelector !== undefined,
this._authenticatorSelector !== undefined,
false,
false,
this._pinUserVerifier !== undefined,
this._passwordUserVerifier !== undefined,
this._biometricUserVerifier !== undefined,
this._devicePasscodeUserVerifier !== undefined,
this._fingerprintUserVerifier !== undefined,
this._onSuccess !== undefined,
this._onError !== undefined,
this.httpRequestHeaders
);
const finish = () => {
NativeEventListener.getInstance().stop(this.operationId);
PlatformOperationCache.getInstance().delete(this.operationId);
};
return NevisMobileAuthenticationSdkReact.oobAuthenticate(message)
.then((data: OnSuccessMessage) => {
finish();
const successMessage = OnSuccessMessage.fromJson(data);
this._onSuccess?.(successMessage.authorizationProvider);
})
.catch((error: Error) => {
finish();
const operationError = new OperationErrorConverter(error).convert();
this._onError?.(operationError);
});
}
}