Cleanup NativeVaultManager bridge (#1340)

This commit is contained in:
Leendert de Borst
2025-11-13 06:38:22 +01:00
committed by Leendert de Borst
parent 95a5391589
commit 52b60e07d2
8 changed files with 18 additions and 154 deletions

View File

@@ -63,7 +63,7 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
const val PIN_SETUP_REQUEST_CODE = 1002
/**
* Static holder for the pending promise from showPinUnlockUI.
* Static holder for the pending promise from showPinUnlock.
* This allows MainActivity to resolve/reject the promise directly without
* depending on React context availability.
*/
@@ -71,7 +71,7 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
var pendingActivityResultPromise: Promise? = null
/**
* Static holder for the pending promise from showNativePinSetup.
* Static holder for the pending promise from showPinSetup.
* This allows MainActivity to resolve/reject the promise directly without
* depending on React context availability.
*/
@@ -1287,47 +1287,6 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
}
}
/**
* Get the configured PIN length.
* @param promise The promise to resolve.
*/
@ReactMethod
override fun getPinLength(promise: Promise) {
try {
val length = vaultStore.getPinLength()
promise.resolve(length)
} catch (e: Exception) {
Log.e(TAG, "Error getting PIN length", e)
promise.reject("ERR_GET_PIN_LENGTH", "Failed to get PIN length: ${e.message}", e)
}
}
/**
* Setup PIN unlock.
* Gets the vault encryption key from memory (vault must be unlocked).
* @param pin The PIN to set.
* @param promise The promise to resolve.
*/
@ReactMethod
override fun setupPin(pin: String, promise: Promise) {
vaultStore.getEncryptionKey(object : net.aliasvault.app.vaultstore.interfaces.CryptoOperationCallback {
override fun onSuccess(result: String) {
try {
vaultStore.setupPin(pin, result)
promise.resolve(null)
} catch (e: Exception) {
Log.e(TAG, "Error setting up PIN", e)
promise.reject("ERR_SETUP_PIN", "Failed to setup PIN: ${e.message}", e)
}
}
override fun onError(error: Exception) {
Log.e(TAG, "Error getting encryption key for PIN setup", error)
promise.reject("ERR_SETUP_PIN", "Failed to get encryption key: ${error.message}", error)
}
})
}
/**
* Show native PIN setup UI.
* Launches the native PinUnlockActivity in setup mode.
@@ -1368,38 +1327,6 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
})
}
/**
* Unlock with PIN.
* @param pin The PIN to unlock with.
* @param promise The promise to resolve.
*/
@ReactMethod
override fun unlockWithPin(pin: String, promise: Promise) {
try {
val vaultEncryptionKey = vaultStore.unlockWithPin(pin)
promise.resolve(vaultEncryptionKey)
} catch (e: net.aliasvault.app.vaultstore.PinUnlockException) {
// Handle PinUnlockException with proper error codes and English messages for React Native
Log.e(TAG, "PIN unlock error: ${e.errorCode}", e)
when (e) {
is net.aliasvault.app.vaultstore.PinUnlockException.NotConfigured -> {
promise.reject("PIN_NOT_CONFIGURED", "PIN unlock is not configured", null)
}
is net.aliasvault.app.vaultstore.PinUnlockException.Locked -> {
promise.reject("PIN_LOCKED", "PIN locked after too many failed attempts", null)
}
is net.aliasvault.app.vaultstore.PinUnlockException.IncorrectPin -> {
val message = "Incorrect PIN. ${e.attemptsRemaining} attempts remaining"
promise.reject("INCORRECT_PIN", message, null)
}
}
} catch (e: Exception) {
// Fallback for any other errors
Log.e(TAG, "Error unlocking with PIN", e)
promise.reject("PIN_UNLOCK_ERROR", "Failed to unlock with PIN: ${e.message}", e)
}
}
/**
* Disable PIN unlock and remove all stored data.
* @param promise The promise to resolve.
@@ -1416,7 +1343,7 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
}
/**
* Show native PIN unlock UI.
* Show PIN unlock UI.
* This presents a native PIN unlock screen modally and handles the unlock flow.
* On success, the vault is unlocked and the encryption key is stored in memory.
* On cancel or error, the promise is rejected.
@@ -1424,7 +1351,7 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
* @param promise The promise to resolve on success or reject on error/cancel.
*/
@ReactMethod
override fun showPinUnlockUI(promise: Promise) {
override fun showPinUnlock(promise: Promise) {
val activity = currentActivity
if (activity == null) {
promise.reject("NO_ACTIVITY", "No activity available", null)

View File

@@ -162,7 +162,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
const handleEnablePin = useCallback(async () : Promise<void> => {
try {
// Launch native PIN setup UI
await NativeVaultManager.showNativePinSetup();
await NativeVaultManager.showPinSetup();
// PIN setup successful - now disable biometrics if it was enabled
if (isBiometricsEnabled) {
@@ -308,8 +308,7 @@ export default function VaultUnlockSettingsScreen() : React.ReactNode {
</View>
<ThemedText style={styles.helpText}>
{t('settings.vaultUnlockSettings.biometricHelp', {
keystore: Platform.OS === 'ios' ? t('settings.vaultUnlockSettings.keystoreIOS') : t('settings.vaultUnlockSettings.keystoreAndroid'),
biometric: biometricDisplayName
keystore: Platform.OS === 'ios' ? t('settings.vaultUnlockSettings.keystoreIOS') : t('settings.vaultUnlockSettings.keystoreAndroid')
})}
</ThemedText>
{!hasBiometrics && (

View File

@@ -66,7 +66,7 @@ export default function UnlockScreen() : React.ReactNode {
* Show native PIN unlock UI
* This will handle the unlock internally and store the encryption key
*/
await NativeVaultManager.showPinUnlockUI();
await NativeVaultManager.showPinUnlock();
/*
* Check if the vault is ready

View File

@@ -292,11 +292,10 @@
"biometricEnabled": "{{biometric}} is now successfully enabled",
"biometricNotAvailable": "{{biometric}} Not Available",
"biometricDisabledMessage": "{{biometric}} is disabled for AliasVault. In order to use it, please enable it in your device settings first.",
"biometricHelp": "Your vault decryption key will be securely stored on your local device in the {{keystore}} and can be accessed securely with {{biometric}}.",
"biometricHelp": "Use biometrics to unlock your vault, which is secured by the {{keystore}}.",
"biometricUnavailableHelp": "{{biometric}} is not available. Tap to open settings and/or go to your device settings to enable and configure it.",
"pin": "PIN Code",
"pinDescription": "Use a custom PIN code to unlock your vault quickly",
"pinHelp": "Your vault decryption key will be encrypted with your PIN and stored securely on your device.",
"pinDescription": "Use a custom PIN code to unlock your vault more quickly.",
"pinEnabled": "PIN unlock enabled successfully",
"pinDisabled": "PIN unlock has been disabled",
"setupPin": "Setup PIN",

View File

@@ -261,28 +261,16 @@
[vaultManager isPinEnabled:resolve rejecter:reject];
}
- (void)getPinLength:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager getPinLength:resolve rejecter:reject];
}
- (void)setupPin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager setupPin:pin resolver:resolve rejecter:reject];
}
- (void)unlockWithPin:(NSString *)pin resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager unlockWithPin:pin resolver:resolve rejecter:reject];
}
- (void)removeAndDisablePin:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager removeAndDisablePin:resolve rejecter:reject];
}
- (void)showPinUnlockUI:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager showPinUnlockUI:resolve rejecter:reject];
- (void)showPinUnlock:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager showPinUnlock:resolve rejecter:reject];
}
- (void)showNativePinSetup:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager showNativePinSetup:resolve rejecter:reject];
- (void)showPinSetup:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager showPinSetup:resolve rejecter:reject];
}
@end

View File

@@ -756,58 +756,12 @@ public class VaultManager: NSObject {
resolve(vaultStore.isPinEnabled())
}
@objc
func getPinLength(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
if let length = vaultStore.getPinLength() {
resolve(length)
} else {
resolve(nil)
}
}
@objc
func getPinFailedAttempts(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
resolve(vaultStore.getPinFailedAttempts())
}
@objc
func setupPin(_ pin: String,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
do {
try vaultStore.setupPin(pin)
resolve(nil)
} catch {
reject("SETUP_PIN_ERROR", "Failed to setup PIN: \(error.localizedDescription)", error)
}
}
@objc
func unlockWithPin(_ pin: String,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
do {
let vaultEncryptionKey = try vaultStore.unlockWithPin(pin)
resolve(vaultEncryptionKey)
} catch let error as PinUnlockError {
// Handle PinUnlockError with proper error codes and localized messages
switch error {
case .notConfigured:
reject("PIN_NOT_CONFIGURED", "PIN unlock is not configured", nil)
case .locked:
reject("PIN_LOCKED", "PIN locked after too many failed attempts", nil)
case .incorrectPin(let attemptsRemaining):
let message = "Incorrect PIN. \(attemptsRemaining) attempts remaining"
reject("INCORRECT_PIN", message, nil)
}
} catch {
// Fallback for any other errors
reject("PIN_UNLOCK_ERROR", error.localizedDescription, error)
}
}
@objc
func resetPinFailedAttempts(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
@@ -827,7 +781,7 @@ public class VaultManager: NSObject {
}
@objc
func showPinUnlockUI(_ resolve: @escaping RCTPromiseResolveBlock,
func showPinUnlock(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
DispatchQueue.main.async { [weak self] in
guard let self = self else {
@@ -885,7 +839,7 @@ public class VaultManager: NSObject {
}
@objc
func showNativePinSetup(_ resolve: @escaping RCTPromiseResolveBlock,
func showPinSetup(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
DispatchQueue.main.async { [weak self] in
guard let self = self else {

View File

@@ -104,7 +104,7 @@ public struct PinSetupView: View {
await viewModel.submitPin()
}
}) {
Text(String(localized: "common_next", bundle: locBundle))
Text(String(localized: "next", bundle: locBundle))
.font(.system(size: 16, weight: .semibold))
.foregroundColor(.white)
.frame(maxWidth: .infinity)

View File

@@ -92,12 +92,9 @@ export interface Spec extends TurboModule {
// PIN unlock methods
isPinEnabled(): Promise<boolean>;
getPinLength(): Promise<number | null>;
unlockWithPin(pin: string): Promise<string>;
setupPin(pin: string): Promise<void>;
removeAndDisablePin(): Promise<void>;
showPinUnlockUI(): Promise<void>;
showNativePinSetup(): Promise<void>;
showPinUnlock(): Promise<void>;
showPinSetup(): Promise<void>;
}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeVaultManager');