Cleanup unused NativeVaultManager methods and refactor (#1404)

This commit is contained in:
Leendert de Borst
2026-01-01 20:04:37 +01:00
parent 3ff6cd7f32
commit 282d69eeb6
7 changed files with 46 additions and 172 deletions

View File

@@ -183,22 +183,6 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
}
}
/**
* Store the encrypted database.
* @param base64EncryptedDb The encrypted database as a base64 encoded string
* @param promise The promise to resolve
*/
@ReactMethod
override fun storeDatabase(base64EncryptedDb: String, promise: Promise) {
try {
vaultStore.storeEncryptedDatabase(base64EncryptedDb)
promise.resolve(null)
} catch (e: Exception) {
Log.e(TAG, "Error storing database", e)
promise.reject("ERR_STORE_DB", "Failed to store database: ${e.message}", e)
}
}
/**
* Store the metadata.
* @param metadata The metadata as a string
@@ -340,37 +324,6 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
}
}
/**
* Get the current vault revision number.
* @param promise The promise to resolve
*/
@ReactMethod
override fun getCurrentVaultRevisionNumber(promise: Promise) {
try {
val revision = vaultStore.getVaultRevisionNumber()
promise.resolve(revision)
} catch (e: Exception) {
Log.e(TAG, "Error getting vault revision", e)
promise.reject("ERR_GET_REVISION", "Failed to get vault revision: ${e.message}", e)
}
}
/**
* Set the current vault revision number.
* @param revisionNumber The revision number
* @param promise The promise to resolve
*/
@ReactMethod
override fun setCurrentVaultRevisionNumber(revisionNumber: Double, promise: Promise?) {
try {
vaultStore.setVaultRevisionNumber(revisionNumber.toInt())
promise?.resolve(null)
} catch (e: Exception) {
Log.e(TAG, "Error setting vault revision", e)
promise?.reject("ERR_SET_REVISION", "Failed to set vault revision: ${e.message}", e)
}
}
/**
* Execute a query on the vault.
* @param query The query

View File

@@ -95,8 +95,15 @@ export const DbProvider: React.FC<{ children: React.ReactNode }> = ({ children }
vaultRevisionNumber: vaultResponse.vault.currentRevisionNumber,
};
// Store the encrypted database and metadata (metadata is stored in plain text in UserDefaults)
await sqliteClient.storeEncryptedDatabase(vaultResponse.vault.blob);
// Store vault blob atomically with sync state (fresh from server, not dirty)
await NativeVaultManager.storeEncryptedVaultWithSyncState(
vaultResponse.vault.blob,
false, // markDirty = false (fresh from server)
vaultResponse.vault.currentRevisionNumber, // serverRevision
null // expectedMutationSeq (not checking race on initial login)
);
// Store metadata separately (email domains - not critical for race conditions)
await sqliteClient.storeMetadata(JSON.stringify(metadata));
// Unlock the vault to make it available for queries

View File

@@ -49,7 +49,8 @@ export function useVaultMutate() : {
* Prepare vault for password change operation.
*/
const prepareVaultForPasswordChange = useCallback(async (): Promise<Vault> => {
const currentRevision = await NativeVaultManager.getCurrentVaultRevisionNumber();
const syncState = await NativeVaultManager.getSyncState();
const currentRevision = syncState.serverRevision;
const encryptedDb = await NativeVaultManager.getEncryptedDatabase();
if (!encryptedDb) {
throw new Error(t('vault.errors.failedToGetEncryptedDatabase'));
@@ -261,6 +262,9 @@ export function useVaultMutate() : {
};
try {
// Capture mutation sequence before upload for atomic state update
const syncState = await NativeVaultManager.getSyncState();
// Upload to server
const response = await webApi.post<typeof passwordChangeVault, VaultPostResponse>('Vault/change-password', passwordChangeVault);
@@ -273,7 +277,8 @@ export function useVaultMutate() : {
// If we get here, it means we have a valid connection to the server.
await NativeVaultManager.setOfflineMode(false);
await NativeVaultManager.setCurrentVaultRevisionNumber(newRevisionNumber);
// Update revision atomically with sync state (clears dirty flag if no mutations during upload)
await NativeVaultManager.markVaultClean(syncState.mutationSequence, newRevisionNumber);
options.onSuccess?.();
} catch (error) {
console.error('Error during password change operation:', error);

View File

@@ -93,10 +93,6 @@
[vaultManager clearClipboardAfterDelay:delayInSeconds resolver:resolve rejecter:reject];
}
- (void)storeDatabase:(NSString *)base64EncryptedDb resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager storeDatabase:base64EncryptedDb resolver:resolve rejecter:reject];
}
- (void)storeMetadata:(NSString *)metadata resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager storeMetadata:metadata resolver:resolve rejecter:reject];
}
@@ -125,14 +121,6 @@
[vaultManager getEncryptedDatabase:resolve rejecter:reject];
}
- (void)getCurrentVaultRevisionNumber:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager getCurrentVaultRevisionNumber:resolve rejecter:reject];
}
- (void)setCurrentVaultRevisionNumber:(double)revisionNumber resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager setCurrentVaultRevisionNumber:revisionNumber resolver:resolve rejecter:reject];
}
- (void)deriveKeyFromPassword:(NSString *)password salt:(NSString *)salt encryptionType:(NSString *)encryptionType encryptionSettings:(NSString *)encryptionSettings resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[vaultManager deriveKeyFromPassword:password salt:salt encryptionType:encryptionType encryptionSettings:encryptionSettings resolver:resolve rejecter:reject];
}

View File

@@ -23,18 +23,6 @@ public class VaultManager: NSObject {
super.init()
}
@objc
func storeDatabase(_ base64EncryptedDb: String,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
do {
try vaultStore.storeEncryptedDatabase(base64EncryptedDb)
resolve(nil)
} catch {
reject("DB_ERROR", "Failed to store database: \(error.localizedDescription)", error)
}
}
@objc
func storeMetadata(_ metadata: String,
resolver resolve: @escaping RCTPromiseResolveBlock,
@@ -201,21 +189,6 @@ public class VaultManager: NSObject {
}
}
@objc
func getCurrentVaultRevisionNumber(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
let revisionNumber = vaultStore.getCurrentVaultRevisionNumber()
resolve(revisionNumber)
}
@objc
func setCurrentVaultRevisionNumber(_ revisionNumber: Int,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
vaultStore.setCurrentVaultRevisionNumber(revisionNumber)
resolve(nil)
}
@objc
func hasEncryptedDatabase(_ resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {

View File

@@ -4,19 +4,45 @@ import type { TurboModule } from 'react-native';
// eslint-disable-next-line @typescript-eslint/naming-convention
export interface Spec extends TurboModule {
// Basic credential operations
clearVault(): Promise<void>;
// WebAPI configuration and token management
setApiUrl(url: string): Promise<void>;
getApiUrl(): Promise<string>;
setAuthTokens(accessToken: string, refreshToken: string): Promise<void>;
getAccessToken(): Promise<string | null>;
clearAuthTokens(): Promise<void>;
revokeTokens(): Promise<void>;
// WebAPI request execution
executeWebApiRequest(method: string, endpoint: string, body: string | null, headers: string, requiresAuth: boolean): Promise<string>;
// Vault state management
isVaultUnlocked(): Promise<boolean>;
getVaultMetadata(): Promise<string>;
unlockVault(): Promise<boolean>;
clearVault(): Promise<void>;
// Vault sync - single method handles all sync logic including merge
// Returns detailed result about what action was taken
syncVaultWithServer(): Promise<{ success: boolean; action: 'uploaded' | 'downloaded' | 'merged' | 'already_in_sync' | 'error'; newRevision: number; wasOffline: boolean; error: string | null }>;
// Sync state management (kept for local mutation tracking)
getSyncState(): Promise<{isDirty: boolean; mutationSequence: number; serverRevision: number; isSyncing: boolean}>;
storeEncryptedVaultWithSyncState(encryptedVault: string, markDirty: boolean, serverRevision: number | null, expectedMutationSeq: number | null): Promise<{ success: boolean; mutationSequence: number }>;
markVaultClean(mutationSeqAtStart: number, newServerRevision: number): Promise<boolean>;
uploadVault(): Promise<{ success: boolean; status: number; newRevisionNumber: number; mutationSeqAtStart: number; error: string | null }>;
// Vault SQL operations
executeQuery(query: string, params: (string | number | null)[]): Promise<string[]>;
executeUpdate(query: string, params:(string | number | null)[]): Promise<number>;
executeRaw(query: string): Promise<void>;
beginTransaction(): Promise<void>;
commitTransaction(): Promise<void>;
rollbackTransaction(): Promise<void>;
// Cryptography operations
deriveKeyFromPassword(password: string, salt: string, encryptionType: string, encryptionSettings: string): Promise<string>;
// Database operations
storeDatabase(base64EncryptedDb: string): Promise<void>;
// Database/encryption key operations
storeMetadata(metadata: string): Promise<void>;
setAuthMethods(authMethods: string[]): Promise<void>;
storeEncryptionKey(base64EncryptionKey: string): Promise<void>;
@@ -24,16 +50,6 @@ export interface Spec extends TurboModule {
getEncryptionKeyDerivationParams(): Promise<string | null>;
hasEncryptedDatabase(): Promise<boolean>;
getEncryptedDatabase(): Promise<string | null>;
getCurrentVaultRevisionNumber(): Promise<number>;
setCurrentVaultRevisionNumber(revisionNumber: number): Promise<void>;
// SQL operations
executeQuery(query: string, params: (string | number | null)[]): Promise<string[]>;
executeUpdate(query: string, params:(string | number | null)[]): Promise<number>;
executeRaw(query: string): Promise<void>;
beginTransaction(): Promise<void>;
commitTransaction(): Promise<void>;
rollbackTransaction(): Promise<void>;
// Auto-lock settings
setAutoLockTimeout(timeout: number): Promise<void>;
@@ -59,23 +75,6 @@ export interface Spec extends TurboModule {
registerCredentialIdentities(): Promise<void>;
removeCredentialIdentities(): Promise<void>;
// WebAPI configuration and token management
setApiUrl(url: string): Promise<void>;
getApiUrl(): Promise<string>;
setAuthTokens(accessToken: string, refreshToken: string): Promise<void>;
getAccessToken(): Promise<string | null>;
clearAuthTokens(): Promise<void>;
revokeTokens(): Promise<void>;
// WebAPI request execution
executeWebApiRequest(
method: string,
endpoint: string,
body: string | null,
headers: string,
requiresAuth: boolean
): Promise<string>;
// Username management
setUsername(username: string): Promise<void>;
getUsername(): Promise<string | null>;
@@ -88,38 +87,6 @@ export interface Spec extends TurboModule {
// Server version management
isServerVersionGreaterThanOrEqualTo(targetVersion: string): Promise<boolean>;
// Vault sync - single method handles all sync logic including merge
// Returns detailed result about what action was taken
syncVaultWithServer(): Promise<{
success: boolean;
action: 'uploaded' | 'downloaded' | 'merged' | 'already_in_sync' | 'error';
newRevision: number;
wasOffline: boolean;
error: string | null;
}>;
// Sync state management (kept for local mutation tracking)
getSyncState(): Promise<{
isDirty: boolean;
mutationSequence: number;
serverRevision: number;
isSyncing: boolean;
}>;
storeEncryptedVaultWithSyncState(
encryptedVault: string,
markDirty: boolean,
serverRevision: number | null,
expectedMutationSeq: number | null
): Promise<{ success: boolean; mutationSequence: number }>;
markVaultClean(mutationSeqAtStart: number, newServerRevision: number): Promise<boolean>;
uploadVault(): Promise<{
success: boolean;
status: number;
newRevisionNumber: number;
mutationSeqAtStart: number;
error: string | null;
}>;
// PIN unlock methods
isPinEnabled(): Promise<boolean>;
removeAndDisablePin(): Promise<void>;

View File

@@ -77,20 +77,6 @@ class SqliteClient implements IDatabaseClient {
return this._logos;
}
// ===== Core Database Operations =====
/**
* Store the encrypted database via the native code implementation.
*/
public async storeEncryptedDatabase(base64EncryptedDb: string): Promise<void> {
try {
await NativeVaultManager.storeDatabase(base64EncryptedDb);
} catch (error) {
console.error('Error initializing SQLite database:', error);
throw error;
}
}
/**
* Store the vault metadata via the native code implementation.
*
@@ -280,10 +266,6 @@ class SqliteClient implements IDatabaseClient {
}
}
// ============================================================================
// Utility methods
// ============================================================================
/**
* Fetch all encryption keys.
*/
@@ -482,7 +464,6 @@ class SqliteClient implements IDatabaseClient {
const allVersions = vaultSqlGenerator.getAllVersions();
return allVersions[allVersions.length - 1];
}
}
export default SqliteClient;