From 6a0e8909a8810016b733a03cf6eb68cbb2c12c8b Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Thu, 29 May 2025 18:40:10 +0200 Subject: [PATCH] Refactor default auth method setting to be part of login flow (#846) --- apps/mobile-app/app/login.tsx | 82 +++++++++++++++---- .../ios/VaultStoreKit/VaultStore+Cache.swift | 2 +- .../ios/VaultStoreKit/VaultStore.swift | 2 +- 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/apps/mobile-app/app/login.tsx b/apps/mobile-app/app/login.tsx index d845954be..f4d137b89 100644 --- a/apps/mobile-app/app/login.tsx +++ b/apps/mobile-app/app/login.tsx @@ -1,21 +1,7 @@ import { Buffer } from 'buffer'; import React, { useState, useEffect } from 'react'; -import { - StyleSheet, - View, - Text, - SafeAreaView, - TextInput, - TouchableOpacity, - ActivityIndicator, - Animated, - ScrollView, - KeyboardAvoidingView, - Platform, - Dimensions, - Alert -} from 'react-native'; +import { StyleSheet, View, Text, SafeAreaView, TextInput, TouchableOpacity, ActivityIndicator, Animated, ScrollView, KeyboardAvoidingView, Platform, Dimensions, Alert } from 'react-native'; import { router } from 'expo-router'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useFocusEffect } from '@react-navigation/native'; @@ -108,6 +94,7 @@ export default function LoginScreen() : React.ReactNode { * @param refreshToken - The refresh token to use for the vault * @param vaultResponseJson - The vault response * @param passwordHashBase64 - The password hash base64 + * @param initiateLoginResponse - The initiate login response */ const processVaultResponse = async ( token: string, @@ -115,6 +102,68 @@ export default function LoginScreen() : React.ReactNode { vaultResponseJson: VaultResponse, passwordHashBase64: string, initiateLoginResponse: LoginResponse + ) : Promise => { + // Get biometric display name + const biometricDisplayName = await authContext.getBiometricDisplayName(); + + // Show biometric prompt + Alert.alert( + `Enable ${biometricDisplayName}?`, + `Would you like to use ${biometricDisplayName} to unlock your vault?`, + [ + { + text: 'No', + style: 'destructive', + /** + * Handle disabling biometric authentication + */ + onPress: async () : Promise => { + await authContext.setAuthMethods(['password']); + await continueProcessVaultResponse( + token, + refreshToken, + vaultResponseJson, + passwordHashBase64, + initiateLoginResponse + ); + } + }, + { + text: 'Yes', + isPreferred: true, + /** + * Handle enabling biometric authentication + */ + onPress: async () : Promise => { + await authContext.setAuthMethods(['faceid', 'password']); + await continueProcessVaultResponse( + token, + refreshToken, + vaultResponseJson, + passwordHashBase64, + initiateLoginResponse + ); + } + } + ] + ); + }; + + /** + * Continue processing the vault response after biometric choice + * @param token - The token to use for the vault + * @param refreshToken - The refresh token to use for the vault + * @param vaultResponseJson - The vault response + * @param passwordHashBase64 - The password hash base64 + * @param initiateLoginResponse - The initiate login response + * @param encryptionKeyDerivationParams - The encryption key derivation parameters + */ + const continueProcessVaultResponse = async ( + token: string, + refreshToken: string, + vaultResponseJson: VaultResponse, + passwordHashBase64: string, + initiateLoginResponse: LoginResponse ) : Promise => { const encryptionKeyDerivationParams : EncryptionKeyDerivationParams = { encryptionType: initiateLoginResponse.encryptionType, @@ -122,6 +171,7 @@ export default function LoginScreen() : React.ReactNode { salt: initiateLoginResponse.salt, }; + // Set auth tokens, store encryption key and key derivation params, and initialize database await authContext.setAuthTokens(credentials.username, token, refreshToken); await dbContext.storeEncryptionKey(passwordHashBase64); await dbContext.storeEncryptionKeyDerivationParams(encryptionKeyDerivationParams); @@ -240,7 +290,7 @@ export default function LoginScreen() : React.ReactNode { setError(err.message); } else { console.error('Login error:', err); - setError('Could not reach AliasVault server. Please try again later or contact support if the problem persists.'); + setError('An error occurred while logging in. Please try again later or contact support if the problem persists.'); } setIsLoading(false); setLoginStatus(null); diff --git a/apps/mobile-app/ios/VaultStoreKit/VaultStore+Cache.swift b/apps/mobile-app/ios/VaultStoreKit/VaultStore+Cache.swift index eb2e02383..d73c0fd32 100644 --- a/apps/mobile-app/ios/VaultStoreKit/VaultStore+Cache.swift +++ b/apps/mobile-app/ios/VaultStoreKit/VaultStore+Cache.swift @@ -40,7 +40,7 @@ extension VaultStore { // Clear the cache to remove all in-memory data self.encryptionKey = nil self.dbConnection = nil - self.enabledAuthMethods = VaultConstants.defaultAuthMethods + self.enabledAuthMethods = [] self.autoLockTimeout = VaultConstants.defaultAutoLockTimeout self.keyDerivationParams = nil } diff --git a/apps/mobile-app/ios/VaultStoreKit/VaultStore.swift b/apps/mobile-app/ios/VaultStoreKit/VaultStore.swift index 39cf4088a..b1c812e4d 100644 --- a/apps/mobile-app/ios/VaultStoreKit/VaultStore.swift +++ b/apps/mobile-app/ios/VaultStoreKit/VaultStore.swift @@ -21,7 +21,7 @@ public class VaultStore { internal let userDefaults = UserDefaults(suiteName: VaultConstants.userDefaultsSuite)! /// The enabled authentication methods for the vault. - internal var enabledAuthMethods: AuthMethods = VaultConstants.defaultAuthMethods + internal var enabledAuthMethods: AuthMethods = [] /// The auto-lock timeout for the vault. internal var autoLockTimeout: Int = VaultConstants.defaultAutoLockTimeout