mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-20 15:41:40 -04:00
Fix keychain accessibility issue (#771)
This commit is contained in:
@@ -4,10 +4,11 @@ import { ThemedSafeAreaView } from '@/components/ThemedSafeAreaView';
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
import * as LocalAuthentication from 'expo-local-authentication';
|
||||
import { useState, useEffect, useMemo, useCallback } from 'react';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { AuthMethod, useAuth } from '@/context/AuthContext';
|
||||
|
||||
export default function VaultUnlockSettingsScreen() {
|
||||
const colors = useColors();
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const { setAuthMethods, enabledAuthMethods } = useAuth();
|
||||
const [hasFaceID, setHasFaceID] = useState(false);
|
||||
const [isFaceIDEnabled, setIsFaceIDEnabled] = useState(false);
|
||||
@@ -23,15 +24,25 @@ export default function VaultUnlockSettingsScreen() {
|
||||
if (enabledAuthMethods.includes('faceid')) {
|
||||
setIsFaceIDEnabled(true);
|
||||
}
|
||||
|
||||
setInitialized(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFaceIDEnabled) {
|
||||
setAuthMethods(['faceid', 'password']);
|
||||
} else {
|
||||
setAuthMethods(['password']);
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
}, [isFaceIDEnabled, setAuthMethods]);
|
||||
|
||||
// Check if there are actually differences between the current and the new auth methods
|
||||
const currentAuthMethods = enabledAuthMethods;
|
||||
const newAuthMethods = isFaceIDEnabled ? ['faceid', 'password'] : ['password'];
|
||||
if (currentAuthMethods.length === newAuthMethods.length && currentAuthMethods.every(method => newAuthMethods.includes(method))) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Updating auth methods to', newAuthMethods);
|
||||
setAuthMethods(newAuthMethods as AuthMethod[]);
|
||||
}, [isFaceIDEnabled, setAuthMethods, enabledAuthMethods, initialized]);
|
||||
|
||||
const handleFaceIDToggle = useCallback(async (value: boolean) => {
|
||||
if (value && !hasFaceID) {
|
||||
@@ -117,7 +128,7 @@ export default function VaultUnlockSettingsScreen() {
|
||||
>
|
||||
<View style={styles.header}>
|
||||
<ThemedText style={styles.headerText}>
|
||||
Choose how you want to unlock your vault
|
||||
Choose how you want to unlock your vault.
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
@@ -134,7 +145,7 @@ export default function VaultUnlockSettingsScreen() {
|
||||
/>
|
||||
</View>
|
||||
<ThemedText style={styles.helpText}>
|
||||
Your vault decryption key will be securely stored on your local device in the iOS Keychain and can only be accessed with your face or fingerprint.
|
||||
Your vault decryption key will be securely stored on your local device in the iOS Keychain and can be accessed with your face or fingerprint.
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ struct AuthMethods: OptionSet {
|
||||
class SharedCredentialStore {
|
||||
static let shared = SharedCredentialStore()
|
||||
private let keychain = Keychain(service: "net.aliasvault.autofill", accessGroup: "group.net.aliasvault.autofill")
|
||||
.accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: .biometryAny)
|
||||
|
||||
private let encryptionKeyKey = "aliasvault_encryption_key"
|
||||
private let encryptedDbFileName = "encrypted_db.sqlite"
|
||||
private let authMethodsKey = "aliasvault_auth_methods"
|
||||
@@ -36,6 +38,24 @@ class SharedCredentialStore {
|
||||
enabledAuthMethods = methods
|
||||
UserDefaults.standard.set(methods.rawValue, forKey: authMethodsKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
|
||||
if !enabledAuthMethods.contains(.faceID) {
|
||||
// If Face ID is now disabled, remove the persisted key from keychain if it exists
|
||||
print("Face ID is now disabled, removing key from keychain")
|
||||
try? keychain.remove(encryptionKeyKey)
|
||||
}
|
||||
else {
|
||||
// If Face ID is now enabled, persist the current key from memory into keychain
|
||||
print("Face ID is now enabled, persisting key to keychain")
|
||||
do {
|
||||
if let key = encryptionKey {
|
||||
try storeEncryptionKey(base64Key: key.base64EncodedString())
|
||||
}
|
||||
} catch {
|
||||
print("Failed to save existing key from memory to keychain: \(error)")
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Vault Status
|
||||
@@ -88,18 +108,24 @@ class SharedCredentialStore {
|
||||
|
||||
// Store the key in memory
|
||||
encryptionKey = keyData
|
||||
print("Stored key in memory")
|
||||
|
||||
// Store the key in the keychain if Face ID is enabled
|
||||
if enabledAuthMethods.contains(.faceID) {
|
||||
print("Face ID is enabled, storing key in keychain")
|
||||
do {
|
||||
try keychain
|
||||
.authenticationPrompt("Authenticate to unlock your vault")
|
||||
.authenticationPrompt("Authenticate to save your vault decryption key in the iOS keychain")
|
||||
.set(keyData, key: encryptionKeyKey)
|
||||
print("Key saved to keychain")
|
||||
} catch {
|
||||
print("Failed to save key to keychain: \(error)")
|
||||
throw error
|
||||
}
|
||||
}
|
||||
else {
|
||||
print("Face ID is disabled, not storing key in keychain")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Database Management
|
||||
|
||||
Reference in New Issue
Block a user