UNPKG

capacitor-biometric-authentication

Version:

Framework-agnostic biometric authentication library. Works with React, Vue, Angular, or vanilla JS. No providers required!

176 lines 7.5 kB
import { BiometricErrorCode, BiometryType } from '../core/types'; import { generateSessionId } from '../utils/encoding'; import { createErrorResult } from '../utils/error-handler'; /** * Electron Adapter for biometric authentication * Supports: * - macOS: Touch ID via Electron's systemPreferences API * - Windows: Windows Hello via WebAuthn API */ export class ElectronAdapter { constructor() { this.platform = 'electron'; this.windowsHelloAvailable = null; // Electron-specific initialization } /** * Check if Windows Hello is available */ async checkWindowsHello() { // Cache the result since this check can be expensive if (this.windowsHelloAvailable !== null) { return this.windowsHelloAvailable; } try { // Check if PublicKeyCredential API is available (WebAuthn) if (typeof PublicKeyCredential !== 'undefined' && typeof PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable === 'function') { this.windowsHelloAvailable = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); return this.windowsHelloAvailable; } } catch (_a) { // Windows Hello not available } this.windowsHelloAvailable = false; return false; } async isAvailable() { try { // Check if we're in Electron main or renderer process if (typeof process !== 'undefined' && process.versions && process.versions.electron) { // In Electron, we can use TouchID on macOS if (process.platform === 'darwin') { // eslint-disable-next-line @typescript-eslint/no-require-imports const electronModule = require('electron'); const { systemPreferences } = electronModule.remote || electronModule; return systemPreferences.canPromptTouchID(); } // On Windows, check for Windows Hello via WebAuthn if (process.platform === 'win32') { return await this.checkWindowsHello(); } return false; } return false; } catch (_a) { return false; } } async getSupportedBiometrics() { if (!(await this.isAvailable())) { return []; } // On macOS, we support Touch ID if (process.platform === 'darwin') { return [BiometryType.TOUCH_ID]; } // On Windows, Windows Hello supports multiple biometric types if (process.platform === 'win32') { // Windows Hello can use fingerprint, face, or PIN // We report FINGERPRINT as the primary type, but it could also be face recognition return [BiometryType.FINGERPRINT, BiometryType.FACE_ID]; } return []; } /** * Authenticate using Windows Hello via WebAuthn API */ async authenticateWithWindowsHello(options) { var _a, _b; try { // Generate a random challenge const challenge = new Uint8Array(32); crypto.getRandomValues(challenge); // Get WebAuthn options from the options object const webAuthnGet = (_a = options === null || options === void 0 ? void 0 : options.webAuthnOptions) === null || _a === void 0 ? void 0 : _a.get; const platformWeb = (_b = options === null || options === void 0 ? void 0 : options.platform) === null || _b === void 0 ? void 0 : _b.web; // Create a credential request for platform authenticator (Windows Hello) const publicKeyCredentialRequestOptions = { challenge: challenge.buffer, timeout: (webAuthnGet === null || webAuthnGet === void 0 ? void 0 : webAuthnGet.timeout) || (platformWeb === null || platformWeb === void 0 ? void 0 : platformWeb.timeout) || (options === null || options === void 0 ? void 0 : options.sessionTimeout) || 60000, userVerification: 'required', rpId: (webAuthnGet === null || webAuthnGet === void 0 ? void 0 : webAuthnGet.rpId) || (platformWeb === null || platformWeb === void 0 ? void 0 : platformWeb.rpId) || (typeof window !== 'undefined' ? window.location.hostname : 'localhost'), }; // Request authentication const credential = await navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions, }); if (!credential) { return { success: false, error: { code: BiometricErrorCode.AUTHENTICATION_FAILED, message: 'Windows Hello authentication failed - no credential returned' } }; } // Authentication successful return { success: true, biometryType: BiometryType.FINGERPRINT, // Windows Hello primary type sessionId: generateSessionId(), platform: 'electron', }; } catch (error) { return createErrorResult(error, 'windows'); } } async authenticate(options) { try { if (!(await this.isAvailable())) { return { success: false, error: { code: BiometricErrorCode.BIOMETRIC_UNAVAILABLE, message: 'Biometric authentication is not available' } }; } // macOS Touch ID if (process.platform === 'darwin') { // eslint-disable-next-line @typescript-eslint/no-require-imports const electronModule = require('electron'); const { systemPreferences } = electronModule.remote || electronModule; try { await systemPreferences.promptTouchID((options === null || options === void 0 ? void 0 : options.reason) || 'authenticate with Touch ID'); return { success: true, biometryType: BiometryType.TOUCH_ID, sessionId: generateSessionId(), platform: 'electron' }; } catch (touchIdError) { return createErrorResult(touchIdError, 'electron'); } } // Windows Hello if (process.platform === 'win32') { return await this.authenticateWithWindowsHello(options); } return { success: false, error: { code: BiometricErrorCode.PLATFORM_NOT_SUPPORTED, message: 'Platform not supported' } }; } catch (error) { return createErrorResult(error, 'electron'); } } async deleteCredentials() { // Electron doesn't store biometric credentials // This is a no-op } async hasCredentials() { // In Electron, we don't store credentials // Return true if biometrics are available return await this.isAvailable(); } } //# sourceMappingURL=ElectronAdapter.js.map