capacitor-biometric-authentication
Version:
Framework-agnostic biometric authentication library. Works with React, Vue, Angular, or vanilla JS. No providers required!
262 lines • 9.34 kB
JavaScript
import { BiometricErrorCode } from './types';
import { PlatformDetector } from './platform-detector';
export class BiometricAuthCore {
constructor() {
this.config = {
adapter: 'auto',
debug: false,
sessionDuration: 300000, // 5 minutes
};
this.adapters = new Map();
this.currentAdapter = null;
this.state = {
isAuthenticated: false
};
this.platformDetector = PlatformDetector.getInstance();
this.subscribers = new Set();
this.initialize();
}
static getInstance() {
if (!BiometricAuthCore.instance) {
BiometricAuthCore.instance = new BiometricAuthCore();
}
return BiometricAuthCore.instance;
}
async initialize() {
// Detect platform and load appropriate adapter
const platformInfo = this.platformDetector.detect();
if (this.config.debug) {
console.warn('[BiometricAuth] Platform detected:', platformInfo);
}
// Load adapter based on platform
await this.loadAdapter(platformInfo.name);
}
async loadAdapter(platform) {
var _a;
try {
// Try custom adapters first
if ((_a = this.config.customAdapters) === null || _a === void 0 ? void 0 : _a[platform]) {
this.currentAdapter = this.config.customAdapters[platform];
return;
}
// Try to load from registered adapters
if (this.adapters.has(platform)) {
this.currentAdapter = this.adapters.get(platform);
return;
}
// Dynamic import based on platform
switch (platform) {
case 'web':
const { WebAdapter } = await import('../adapters/WebAdapter');
this.currentAdapter = new WebAdapter();
break;
case 'ios':
case 'android':
// Check if Capacitor is available
if (this.platformDetector.detect().isCapacitor) {
const { CapacitorAdapter } = await import('../adapters/CapacitorAdapter');
this.currentAdapter = new CapacitorAdapter();
}
else if (this.platformDetector.detect().isReactNative) {
// Dynamic import for React Native
try {
const { ReactNativeAdapter } = await import('../adapters/ReactNativeAdapter');
this.currentAdapter = new ReactNativeAdapter();
}
catch (_b) {
throw new Error('React Native biometric module not installed. Please install react-native-biometrics');
}
}
break;
case 'electron':
const { ElectronAdapter } = await import('../adapters/ElectronAdapter');
this.currentAdapter = new ElectronAdapter();
break;
default:
throw new Error(`Platform ${platform} not supported`);
}
}
catch (error) {
if (this.config.debug) {
console.warn('[BiometricAuth] Failed to load adapter:', error);
}
// Fallback to web adapter if available
if (platform !== 'web' && this.platformDetector.detect().isWeb) {
const { WebAdapter } = await import('../adapters/WebAdapter');
this.currentAdapter = new WebAdapter();
}
}
}
configure(config) {
this.config = Object.assign(Object.assign({}, this.config), config);
// Re-initialize if adapter changed
if (config.adapter && config.adapter !== 'auto') {
this.loadAdapter(config.adapter);
}
}
registerAdapter(name, adapter) {
this.adapters.set(name, adapter);
}
async isAvailable() {
if (!this.currentAdapter) {
return false;
}
try {
return await this.currentAdapter.isAvailable();
}
catch (error) {
if (this.config.debug) {
console.warn('[BiometricAuth] isAvailable error:', error);
}
return false;
}
}
async getSupportedBiometrics() {
if (!this.currentAdapter) {
return [];
}
try {
return await this.currentAdapter.getSupportedBiometrics();
}
catch (error) {
if (this.config.debug) {
console.warn('[BiometricAuth] getSupportedBiometrics error:', error);
}
return [];
}
}
async authenticate(options) {
if (!this.currentAdapter) {
return {
success: false,
error: {
code: BiometricErrorCode.PLATFORM_NOT_SUPPORTED,
message: 'No biometric adapter available for this platform'
}
};
}
try {
const result = await this.currentAdapter.authenticate(options);
if (result.success) {
this.updateState({
isAuthenticated: true,
sessionId: result.sessionId,
lastAuthTime: Date.now(),
biometryType: result.biometryType,
error: undefined
});
// Set up session timeout
if (this.config.sessionDuration && this.config.sessionDuration > 0) {
setTimeout(() => {
this.logout();
}, this.config.sessionDuration);
}
}
else {
this.updateState({
isAuthenticated: false,
error: result.error
});
}
return result;
}
catch (error) {
const errorResult = {
success: false,
error: {
code: BiometricErrorCode.UNKNOWN_ERROR,
message: error instanceof Error ? error.message : 'Unknown error occurred',
details: error
}
};
this.updateState({
isAuthenticated: false,
error: errorResult.error
});
return errorResult;
}
}
async deleteCredentials() {
if (!this.currentAdapter) {
throw new Error('No biometric adapter available');
}
await this.currentAdapter.deleteCredentials();
this.logout();
}
async hasCredentials() {
if (!this.currentAdapter) {
return false;
}
try {
return await this.currentAdapter.hasCredentials();
}
catch (error) {
if (this.config.debug) {
console.warn('[BiometricAuth] hasCredentials error:', error);
}
return false;
}
}
logout() {
this.updateState({
isAuthenticated: false,
sessionId: undefined,
lastAuthTime: undefined,
biometryType: undefined,
error: undefined
});
}
getState() {
return Object.assign({}, this.state);
}
isAuthenticated() {
if (!this.state.isAuthenticated || !this.state.lastAuthTime) {
return false;
}
// Check if session is still valid
if (this.config.sessionDuration && this.config.sessionDuration > 0) {
const elapsed = Date.now() - this.state.lastAuthTime;
if (this.config.sessionDuration && elapsed > this.config.sessionDuration) {
this.logout();
return false;
}
}
return true;
}
subscribe(callback) {
this.subscribers.add(callback);
// Return unsubscribe function
return () => {
this.subscribers.delete(callback);
};
}
updateState(newState) {
this.state = Object.assign(Object.assign({}, this.state), newState);
// Notify subscribers
this.subscribers.forEach(callback => {
callback(this.getState());
});
}
// Utility methods for common use cases
async requireAuthentication(callback, options) {
var _a;
if (!this.isAuthenticated()) {
const result = await this.authenticate(options);
if (!result.success) {
throw new Error(((_a = result.error) === null || _a === void 0 ? void 0 : _a.message) || 'Authentication failed');
}
}
return callback();
}
async withAuthentication(callback, options) {
var _a;
if (!this.isAuthenticated()) {
const result = await this.authenticate(options);
if (!result.success) {
throw new Error(((_a = result.error) === null || _a === void 0 ? void 0 : _a.message) || 'Authentication failed');
}
}
return callback();
}
}
//# sourceMappingURL=BiometricAuthCore.js.map