mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-20 15:41:40 -04:00
Make vault save to server flow work in app (#771)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { StyleSheet, View, TextInput, TouchableOpacity, ScrollView, Platform, Animated } from 'react-native';
|
||||
import { StyleSheet, View, TextInput, TouchableOpacity, ScrollView, Platform, Animated, ActivityIndicator } from 'react-native';
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useLocalSearchParams, useNavigation, useRouter } from 'expo-router';
|
||||
import { ThemedText } from '@/components/ThemedText';
|
||||
@@ -6,19 +6,29 @@ import { ThemedView } from '@/components/ThemedView';
|
||||
import { ThemedSafeAreaView } from '@/components/ThemedSafeAreaView';
|
||||
import { useColors } from '@/hooks/useColorScheme';
|
||||
import { useDb } from '@/context/DbContext';
|
||||
import { useWebApi } from '@/context/WebApiContext';
|
||||
import { useVaultSync } from '@/hooks/useVaultSync';
|
||||
import { Credential } from '@/utils/types/Credential';
|
||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import { Gender } from "@/utils/generators/Identity/types/Gender";
|
||||
import emitter from '@/utils/EventEmitter';
|
||||
|
||||
import NativeVaultManager from '@/specs/NativeVaultManager';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
type CredentialMode = 'random' | 'manual';
|
||||
|
||||
interface VaultPostResponse {
|
||||
status: number;
|
||||
newRevisionNumber: number;
|
||||
}
|
||||
|
||||
export default function AddEditCredentialScreen() {
|
||||
const { id, serviceUrl } = useLocalSearchParams<{ id: string, serviceUrl?: string }>();
|
||||
const router = useRouter();
|
||||
const colors = useColors();
|
||||
const dbContext = useDb();
|
||||
const authContext = useAuth();
|
||||
const [mode, setMode] = useState<CredentialMode>('random');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const navigation = useNavigation();
|
||||
@@ -39,6 +49,9 @@ export default function AddEditCredentialScreen() {
|
||||
Email: ""
|
||||
},
|
||||
});
|
||||
const [syncStatus, setSyncStatus] = useState<string>('');
|
||||
const webApi = useWebApi();
|
||||
const { syncVault } = useVaultSync();
|
||||
|
||||
function extractServiceNameFromUrl(url: string): string {
|
||||
try {
|
||||
@@ -197,38 +210,26 @@ export default function AddEditCredentialScreen() {
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setSyncStatus('Checking for vault updates...');
|
||||
|
||||
let credentialToSave = credential as Credential;
|
||||
|
||||
// If mode is random, generate random values for all fields before saving.
|
||||
// TODO: replace this with actual identity generator logic.
|
||||
if (mode === 'random') {
|
||||
console.log('Generating random values');
|
||||
credentialToSave = generateRandomValues();
|
||||
}
|
||||
|
||||
if (isEditMode) {
|
||||
// Update existing credential
|
||||
await dbContext.sqliteClient!.updateCredentialById(credentialToSave);
|
||||
Toast.show({
|
||||
type: 'success',
|
||||
text1: 'Credential updated successfully',
|
||||
position: 'bottom'
|
||||
});
|
||||
} else {
|
||||
// Create new credential
|
||||
await dbContext.sqliteClient!.createCredential(credentialToSave);
|
||||
Toast.show({
|
||||
type: 'success',
|
||||
text1: 'Credential created successfully',
|
||||
position: 'bottom'
|
||||
});
|
||||
}
|
||||
|
||||
// Emit an event to notify list and detail views to refresh
|
||||
emitter.emit('credentialChanged', credentialToSave.Id);
|
||||
|
||||
router.back();
|
||||
// First check if there are any vault updates
|
||||
await syncVault({
|
||||
onStatus: (message) => setSyncStatus(message),
|
||||
onSuccess: async (hasNewVault) => {
|
||||
if (hasNewVault) {
|
||||
console.log('Vault was changed, but has now been reloaded so we can continue with the save.');
|
||||
}
|
||||
await handleSaveInner();
|
||||
},
|
||||
onError: (error) => {
|
||||
Toast.show({
|
||||
type: 'error',
|
||||
text1: 'Failed to sync vault',
|
||||
text2: error,
|
||||
position: 'bottom'
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error saving credential:', error);
|
||||
Toast.show({
|
||||
@@ -239,6 +240,96 @@ export default function AddEditCredentialScreen() {
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
setSyncStatus('');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveInner = async () => {
|
||||
let credentialToSave = credential as Credential;
|
||||
|
||||
// If mode is random, generate random values for all fields before saving.
|
||||
if (mode === 'random') {
|
||||
console.log('Generating random values');
|
||||
credentialToSave = generateRandomValues();
|
||||
}
|
||||
|
||||
setSyncStatus('Saving changes to vault...');
|
||||
|
||||
if (isEditMode) {
|
||||
// Update existing credential
|
||||
await dbContext.sqliteClient!.updateCredentialById(credentialToSave);
|
||||
} else {
|
||||
// Create new credential
|
||||
await dbContext.sqliteClient!.createCredential(credentialToSave);
|
||||
}
|
||||
|
||||
// Get the current vault revision number
|
||||
const currentRevision = await NativeVaultManager.getCurrentVaultRevisionNumber();
|
||||
|
||||
// Get the encrypted database
|
||||
const encryptedDb = await NativeVaultManager.getEncryptedDatabase();
|
||||
if (!encryptedDb) {
|
||||
throw new Error('Failed to get encrypted database');
|
||||
}
|
||||
|
||||
setSyncStatus('Uploading vault to server...');
|
||||
|
||||
// Get email addresses from credentials
|
||||
const credentials = await dbContext.sqliteClient!.getAllCredentials();
|
||||
const emailAddresses = credentials
|
||||
.filter(cred => cred.Alias?.Email != null)
|
||||
.map(cred => cred.Alias!.Email!)
|
||||
.filter((email, index, self) => self.indexOf(email) === index);
|
||||
|
||||
// Get username from the auth context
|
||||
const username = authContext.username;
|
||||
if (!username) {
|
||||
throw new Error('Username not found');
|
||||
}
|
||||
|
||||
// Create vault object for upload
|
||||
const newVault = {
|
||||
blob: encryptedDb,
|
||||
createdAt: new Date().toISOString(),
|
||||
credentialsCount: credentials.length,
|
||||
currentRevisionNumber: currentRevision,
|
||||
emailAddressList: emailAddresses,
|
||||
privateEmailDomainList: [], // Empty on purpose, API will not use this for vault updates
|
||||
publicEmailDomainList: [], // Empty on purpose, API will not use this for vault updates
|
||||
encryptionPublicKey: '', // Empty on purpose, only required if new public/private key pair is generated
|
||||
// TODO: can client be null? double check this.
|
||||
client: '', // Empty on purpose, API will not use this for vault updates
|
||||
updatedAt: new Date().toISOString(),
|
||||
username: username,
|
||||
version: await dbContext.sqliteClient!.getDatabaseVersion() ?? '0.0.0'
|
||||
};
|
||||
console.log('New vault current revision number:', currentRevision);
|
||||
|
||||
console.log('Trying to upload vault to server...');
|
||||
|
||||
// Upload to server
|
||||
const response = await webApi.post<typeof newVault, VaultPostResponse>('Vault', newVault);
|
||||
|
||||
console.log('Vault upload response:', response);
|
||||
|
||||
// Check if response is successful
|
||||
if (response.status === 0) {
|
||||
await NativeVaultManager.setCurrentVaultRevisionNumber(response.newRevisionNumber);
|
||||
|
||||
Toast.show({
|
||||
type: 'success',
|
||||
text1: isEditMode ? 'Credential updated successfully' : 'Credential created successfully',
|
||||
position: 'bottom'
|
||||
});
|
||||
|
||||
// Emit an event to notify list and detail views to refresh
|
||||
emitter.emit('credentialChanged', credentialToSave.Id);
|
||||
|
||||
router.back();
|
||||
} else if (response.status === 1) {
|
||||
throw new Error('Vault merge required. Please login via the web app to merge the multiple pending updates to your vault.');
|
||||
} else {
|
||||
throw new Error('Failed to upload vault to server');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -327,11 +418,36 @@ export default function AddEditCredentialScreen() {
|
||||
height: 100,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
loadingOverlay: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 1000,
|
||||
},
|
||||
syncStatus: {
|
||||
marginTop: 16,
|
||||
textAlign: 'center',
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<ThemedSafeAreaView style={styles.container}>
|
||||
<ThemedView style={styles.content}>
|
||||
{(isLoading || syncStatus) && (
|
||||
<View style={styles.loadingOverlay}>
|
||||
<ActivityIndicator size="large" color={colors.primary} />
|
||||
{syncStatus && (
|
||||
<ThemedText style={styles.syncStatus}>{syncStatus}</ThemedText>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
<ScrollView>
|
||||
{!isEditMode && (
|
||||
<View style={styles.modeSelector}>
|
||||
|
||||
@@ -12,6 +12,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RCTNativeVaultManager : NSObject <NativeVaultManagerSpec>
|
||||
|
||||
- (void)getEncryptedDatabase:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
|
||||
- (void)getCurrentVaultRevisionNumber:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
|
||||
- (void)setCurrentVaultRevisionNumber:(double)revisionNumber resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -116,4 +116,16 @@
|
||||
[vaultManager clearVault];
|
||||
}
|
||||
|
||||
- (void)getEncryptedDatabase:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
||||
[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];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -168,6 +168,31 @@ public class VaultManager: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
func getEncryptedDatabase(_ resolve: @escaping RCTPromiseResolveBlock,
|
||||
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
||||
if let encryptedDb = vaultStore.getEncryptedDatabase() {
|
||||
resolve(encryptedDb)
|
||||
} else {
|
||||
reject("DB_ERROR", "Failed to get encrypted database", nil)
|
||||
}
|
||||
}
|
||||
|
||||
@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 isVaultInitialized(_ resolve: @escaping RCTPromiseResolveBlock,
|
||||
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
||||
|
||||
13
mobile-app/ios/VaultModels/VaultMetadata.swift
Normal file
13
mobile-app/ios/VaultModels/VaultMetadata.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
import Foundation
|
||||
|
||||
public struct VaultMetadata: Codable {
|
||||
public var publicEmailDomains: [String]?
|
||||
public var privateEmailDomains: [String]?
|
||||
public var vaultRevisionNumber: Int
|
||||
|
||||
public init(publicEmailDomains: [String]? = nil, privateEmailDomains: [String]? = nil, vaultRevisionNumber: Int) {
|
||||
self.publicEmailDomains = publicEmailDomains
|
||||
self.privateEmailDomains = privateEmailDomains
|
||||
self.vaultRevisionNumber = vaultRevisionNumber
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ public class VaultStore {
|
||||
}
|
||||
|
||||
// Get the encrypted database as a base64 encoded string
|
||||
private func getEncryptedDatabase() -> String? {
|
||||
public func getEncryptedDatabase() -> String? {
|
||||
do {
|
||||
// Return the base64 encoded string
|
||||
return try String(contentsOf: getEncryptedDbPath(), encoding: .utf8)
|
||||
@@ -257,11 +257,51 @@ public class VaultStore {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the current vault revision number
|
||||
public func getCurrentVaultRevisionNumber() -> Int {
|
||||
guard let metadata = getVaultMetadataObject() else {
|
||||
return 0
|
||||
}
|
||||
return metadata.vaultRevisionNumber
|
||||
}
|
||||
|
||||
// Set the current vault revision number
|
||||
public func setCurrentVaultRevisionNumber(_ revisionNumber: Int) {
|
||||
var metadata: VaultMetadata
|
||||
|
||||
if let existingMetadata = getVaultMetadataObject() {
|
||||
metadata = existingMetadata
|
||||
} else {
|
||||
metadata = VaultMetadata(
|
||||
publicEmailDomains: [],
|
||||
privateEmailDomains: [],
|
||||
vaultRevisionNumber: revisionNumber
|
||||
)
|
||||
}
|
||||
|
||||
metadata.vaultRevisionNumber = revisionNumber
|
||||
if let data = try? JSONEncoder().encode(metadata),
|
||||
let jsonString = String(data: data, encoding: .utf8) {
|
||||
UserDefaults.standard.set(jsonString, forKey: vaultMetadataKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
|
||||
// Get the vault metadata from UserDefaults
|
||||
public func getVaultMetadata() -> String? {
|
||||
return UserDefaults.standard.string(forKey: vaultMetadataKey)
|
||||
}
|
||||
|
||||
// Helper to decode the JSON metadata into VaultMetadata object
|
||||
private func getVaultMetadataObject() -> VaultMetadata? {
|
||||
guard let jsonString = getVaultMetadata(),
|
||||
let data = jsonString.data(using: .utf8),
|
||||
let metadata = try? JSONDecoder().decode(VaultMetadata.self, from: data) else {
|
||||
return nil
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the database.
|
||||
*
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
CEE9098F2DA548C7008D568F /* Exceptions for "Autofill" folder in "Autofill" target */ = {
|
||||
CEE9098F2DA548C7008D568F /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Info.plist,
|
||||
@@ -218,73 +218,12 @@
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
CEE480882DBE86DC00F4A367 /* VaultStoreKit */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = VaultStoreKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEE480972DBE86DD00F4A367 /* VaultStoreKitTests */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = VaultStoreKitTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEE4816B2DBE8AC800F4A367 /* VaultUI */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = VaultUI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEE4817A2DBE8AC800F4A367 /* VaultUITests */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = VaultUITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEE482AB2DBE8EFE00F4A367 /* VaultModels */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = VaultModels;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEE909812DA548C7008D568F /* Autofill */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
CEE9098F2DA548C7008D568F /* Exceptions for "Autofill" folder in "Autofill" target */,
|
||||
);
|
||||
explicitFileTypes = {
|
||||
};
|
||||
explicitFolders = (
|
||||
);
|
||||
path = Autofill;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CEE480882DBE86DC00F4A367 /* VaultStoreKit */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultStoreKit; sourceTree = "<group>"; };
|
||||
CEE480972DBE86DD00F4A367 /* VaultStoreKitTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultStoreKitTests; sourceTree = "<group>"; };
|
||||
CEE4816B2DBE8AC800F4A367 /* VaultUI */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultUI; sourceTree = "<group>"; };
|
||||
CEE4817A2DBE8AC800F4A367 /* VaultUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultUITests; sourceTree = "<group>"; };
|
||||
CEE482AB2DBE8EFE00F4A367 /* VaultModels */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultModels; sourceTree = "<group>"; };
|
||||
CEE909812DA548C7008D568F /* Autofill */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (CEE9098F2DA548C7008D568F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Autofill; sourceTree = "<group>"; };
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -1270,10 +1209,7 @@
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
@@ -1328,10 +1264,7 @@
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
|
||||
37
mobile-app/native/NativeVaultManager.ts
Normal file
37
mobile-app/native/NativeVaultManager.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { TurboModule } from 'react-native';
|
||||
import { TurboModuleRegistry } from 'react-native';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
// Basic credential operations
|
||||
addCredential(username: string, password: string, service: string): Promise<void>;
|
||||
getCredentials(): Promise<{ credentials: Array<{ username: string; password: string; service: string }> }>;
|
||||
clearVault(): Promise<void>;
|
||||
|
||||
// Vault state management
|
||||
isVaultInitialized(): Promise<boolean>;
|
||||
isVaultUnlocked(): Promise<boolean>;
|
||||
getVaultMetadata(): Promise<any>;
|
||||
unlockVault(): Promise<boolean>;
|
||||
|
||||
// Database operations
|
||||
storeDatabase(base64EncryptedDb: string, metadata: string): Promise<void>;
|
||||
setAuthMethods(authMethods: string[]): Promise<void>;
|
||||
storeEncryptionKey(base64EncryptionKey: string): Promise<void>;
|
||||
getEncryptedDatabase(): Promise<string | null>;
|
||||
getCurrentVaultRevisionNumber(): Promise<number>;
|
||||
setCurrentVaultRevisionNumber(revisionNumber: number): Promise<void>;
|
||||
|
||||
// SQL operations
|
||||
executeQuery(query: string, params: any[]): Promise<any[]>;
|
||||
executeUpdate(query: string, params: any[]): Promise<number>;
|
||||
beginTransaction(): Promise<void>;
|
||||
commitTransaction(): Promise<void>;
|
||||
rollbackTransaction(): Promise<void>;
|
||||
|
||||
// Auto-lock settings
|
||||
setAutoLockTimeout(timeout: number): Promise<void>;
|
||||
getAutoLockTimeout(): Promise<number>;
|
||||
getAuthMethods(): Promise<string[]>;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('NativeVaultManager');
|
||||
@@ -17,6 +17,9 @@ export interface Spec extends TurboModule {
|
||||
storeDatabase(base64EncryptedDb: string, metadata: string): Promise<void>;
|
||||
setAuthMethods(authMethods: string[]): Promise<void>;
|
||||
storeEncryptionKey(base64EncryptionKey: string): Promise<void>;
|
||||
getEncryptedDatabase(): Promise<string | null>;
|
||||
getCurrentVaultRevisionNumber(): Promise<number>;
|
||||
setCurrentVaultRevisionNumber(revisionNumber: number): Promise<void>;
|
||||
|
||||
// SQL operations
|
||||
executeQuery(query: string, params: any[]): Promise<any[]>;
|
||||
|
||||
Reference in New Issue
Block a user