capacitor-biometric-authentication
Version:
Framework-agnostic biometric authentication library. Works with React, Vue, Angular, or vanilla JS. No providers required!
208 lines • 8.5 kB
JavaScript
import { BiometricErrorCode, BiometryType } from '../core/types';
export class CapacitorAdapter {
constructor() {
this.platform = 'capacitor';
// Plugin will be loaded dynamically
}
async getPlugin() {
if (this.capacitorPlugin) {
return this.capacitorPlugin;
}
try {
// Try to get the registered Capacitor plugin
const capacitorCore = await import('@capacitor/core');
// Try using registerPlugin if available
if (capacitorCore.registerPlugin) {
try {
this.capacitorPlugin = capacitorCore.registerPlugin('BiometricAuth');
if (this.capacitorPlugin) {
return this.capacitorPlugin;
}
}
catch (_a) {
// Continue to fallback
}
}
// Legacy support for older Capacitor versions
const legacyPlugins = capacitorCore.Plugins;
if (legacyPlugins === null || legacyPlugins === void 0 ? void 0 : legacyPlugins.BiometricAuth) {
this.capacitorPlugin = legacyPlugins.BiometricAuth;
return this.capacitorPlugin;
}
// If not found in Plugins, try direct import
// This allows the plugin to work even if not properly registered
const BiometricAuthPlugin = window.BiometricAuthPlugin;
if (BiometricAuthPlugin) {
this.capacitorPlugin = BiometricAuthPlugin;
return this.capacitorPlugin;
}
throw new Error('BiometricAuth Capacitor plugin not found');
}
catch (error) {
throw new Error('Failed to load Capacitor plugin: ' + error.message);
}
}
async isAvailable() {
try {
const plugin = await this.getPlugin();
const result = await plugin.isAvailable();
return result.isAvailable || false;
}
catch (_a) {
return false;
}
}
async getSupportedBiometrics() {
try {
const plugin = await this.getPlugin();
const result = await plugin.getSupportedBiometrics();
// Map Capacitor biometry types to our types
return (result.biometryTypes || []).map((type) => {
switch (type.toLowerCase()) {
case 'fingerprint':
return BiometryType.FINGERPRINT;
case 'faceid':
case 'face_id':
return BiometryType.FACE_ID;
case 'touchid':
case 'touch_id':
return BiometryType.TOUCH_ID;
case 'iris':
return BiometryType.IRIS;
default:
return BiometryType.UNKNOWN;
}
}).filter((type) => type !== BiometryType.UNKNOWN);
}
catch (_a) {
return [];
}
}
async authenticate(options) {
var _a, _b;
try {
const plugin = await this.getPlugin();
// Map our options to Capacitor plugin options
const capacitorOptions = Object.assign(Object.assign({ reason: (options === null || options === void 0 ? void 0 : options.reason) || 'Authenticate to continue', cancelTitle: options === null || options === void 0 ? void 0 : options.cancelTitle, fallbackTitle: options === null || options === void 0 ? void 0 : options.fallbackTitle, disableDeviceCredential: options === null || options === void 0 ? void 0 : options.disableDeviceCredential, maxAttempts: options === null || options === void 0 ? void 0 : options.maxAttempts, requireConfirmation: options === null || options === void 0 ? void 0 : options.requireConfirmation }, (((_a = options === null || options === void 0 ? void 0 : options.platform) === null || _a === void 0 ? void 0 : _a.android) || {})), (((_b = options === null || options === void 0 ? void 0 : options.platform) === null || _b === void 0 ? void 0 : _b.ios) || {}));
const result = await plugin.authenticate(capacitorOptions);
if (result.success) {
const biometryType = this.mapBiometryType(result.biometryType);
return {
success: true,
biometryType,
sessionId: this.generateSessionId(),
platform: 'capacitor'
};
}
else {
return {
success: false,
error: this.mapError(result.error)
};
}
}
catch (error) {
return {
success: false,
error: this.mapError(error)
};
}
}
async deleteCredentials() {
try {
const plugin = await this.getPlugin();
await plugin.deleteCredentials();
}
catch (_a) {
// Ignore errors when deleting credentials
}
}
async hasCredentials() {
try {
const plugin = await this.getPlugin();
// Check if the plugin has a hasCredentials method
if (typeof plugin.hasCredentials === 'function') {
const result = await plugin.hasCredentials();
return result.hasCredentials || false;
}
// Fallback: assume credentials exist if biometrics are available
return await this.isAvailable();
}
catch (_a) {
return false;
}
}
mapBiometryType(type) {
if (!type) {
return BiometryType.UNKNOWN;
}
switch (type.toLowerCase()) {
case 'fingerprint':
return BiometryType.FINGERPRINT;
case 'faceid':
case 'face_id':
return BiometryType.FACE_ID;
case 'touchid':
case 'touch_id':
return BiometryType.TOUCH_ID;
case 'iris':
return BiometryType.IRIS;
default:
return BiometryType.UNKNOWN;
}
}
mapError(error) {
let code = BiometricErrorCode.UNKNOWN_ERROR;
let message = 'An unknown error occurred';
const errorObj = error;
if (errorObj === null || errorObj === void 0 ? void 0 : errorObj.code) {
switch (errorObj.code) {
case 'BIOMETRIC_UNAVAILABLE':
case 'UNAVAILABLE':
code = BiometricErrorCode.BIOMETRIC_UNAVAILABLE;
message = errorObj.message || 'Biometric authentication is not available';
break;
case 'USER_CANCELLED':
case 'CANCELLED':
case 'USER_CANCEL':
code = BiometricErrorCode.USER_CANCELLED;
message = errorObj.message || 'User cancelled authentication';
break;
case 'AUTHENTICATION_FAILED':
case 'FAILED':
code = BiometricErrorCode.AUTHENTICATION_FAILED;
message = errorObj.message || 'Authentication failed';
break;
case 'TIMEOUT':
code = BiometricErrorCode.TIMEOUT;
message = errorObj.message || 'Authentication timed out';
break;
case 'LOCKOUT':
code = BiometricErrorCode.LOCKOUT;
message = errorObj.message || 'Too many failed attempts';
break;
case 'NOT_ENROLLED':
code = BiometricErrorCode.NOT_ENROLLED;
message = errorObj.message || 'No biometric credentials enrolled';
break;
default:
message = errorObj.message || message;
}
}
else if (error instanceof Error) {
message = error.message;
}
else if (typeof error === 'string') {
message = error;
}
return {
code,
message,
details: error
};
}
generateSessionId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
}
//# sourceMappingURL=CapacitorAdapter.js.map