UNPKG

@aparajita/capacitor-biometric-auth

Version:

Provides access to the native biometric auth & device security APIs for Capacitor 7+ apps

129 lines (128 loc) 5.38 kB
import { BiometricAuthBase } from './base.js'; import { BiometryError, BiometryErrorType, BiometryType, } from './definitions.js'; import { getBiometryName } from './web-utils.js'; /* eslint-disable @typescript-eslint/require-await */ export class BiometricAuthWeb extends BiometricAuthBase { constructor() { super(...arguments); this.biometryType = BiometryType.none; this.biometryTypes = []; this.biometryIsEnrolled = false; this.deviceIsSecure = false; } // On the web, return the fake biometry set by setBiometryType(). async checkBiometry() { const hasBiometry = this.biometryType !== BiometryType.none; const available = hasBiometry && this.biometryIsEnrolled; let reason = ''; let code = BiometryErrorType.none; if (!hasBiometry) { reason = 'No biometry is available'; code = BiometryErrorType.biometryNotAvailable; } else if (!this.biometryIsEnrolled) { reason = 'Biometry is not enrolled'; code = BiometryErrorType.biometryNotEnrolled; } return { isAvailable: available, strongBiometryIsAvailable: this.biometryIsEnrolled && this.hasStrongBiometry(), biometryType: this.biometryType, biometryTypes: this.biometryTypes, deviceIsSecure: this.deviceIsSecure, reason, code, }; } hasStrongBiometry() { return this.biometryTypes.some((type) => type === BiometryType.faceId || type === BiometryType.touchId || type === BiometryType.fingerprintAuthentication); } // On the web, fake authentication with a confirm dialog. async internalAuthenticate(options) { const result = await this.checkBiometry(); // First try biometry if available. if (result.isAvailable && // oxlint-disable-next-line no-alert confirm( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to use the default value if options?.reason is an empty string (options === null || options === void 0 ? void 0 : options.reason) || `Authenticate with ${result.biometryTypes .map((type) => getBiometryName(type)) .join(' or ')}?`)) { return; } if (options === null || options === void 0 ? void 0 : options.allowDeviceCredential) { // Either biometry is not available, or the user declined to use it // and device security is allowed. if (result.deviceIsSecure) { // oxlint-disable-next-line no-alert if (confirm('Authenticate with device security?')) { return; } throw new BiometryError('User cancelled', BiometryErrorType.userCancel); } else if (result.isAvailable) { throw new BiometryError('Device is not secure', BiometryErrorType.noDeviceCredential); } } else if (!result.isAvailable) { // Biometry is not available and device security is not allowed. throw result.biometryType === BiometryType.none ? new BiometryError('Biometry is not available', BiometryErrorType.biometryNotAvailable) : new BiometryError('Biometry is not enrolled', BiometryErrorType.biometryNotEnrolled); } // The user declined to use biometry and device credentials not allowed. throw new BiometryError('User cancelled', BiometryErrorType.userCancel); } // Web only, used for simulating biometric authentication. async setBiometryType(type) { if (type === undefined) { return; } const types = Array.isArray(type) ? type : [type]; this.biometryTypes = []; this.biometryType = BiometryType.none; if (types.length === 0) { return; } if (isBiometryTypes(types)) { this.biometryType = types[0]; if (this.biometryType !== BiometryType.none) { this.biometryTypes = types; } } else { for (const [i, theType] of types.entries()) { if (isBiometryType(theType)) { if (this.biometryType === BiometryType.none) { this.biometryTypes = []; } else { this.biometryTypes.push(theType); } if (i === 0) { this.biometryType = theType; } } } } } // Web only, used for simulating device unlock security. async setBiometryIsEnrolled(enrolled) { this.biometryIsEnrolled = enrolled; } // Web only, used for simulating device unlock security. async setDeviceIsSecure(isSecure) { this.deviceIsSecure = isSecure; } } function isBiometryType(value) { // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion return Object.values(BiometryType).includes(value); } function isBiometryTypes(value) { return value.every((type) => isBiometryType(type)); } /* eslint-enable @typescript-eslint/require-await */