Show saved credentials in react native (#771)

This commit is contained in:
Leendert de Borst
2025-04-08 17:19:58 +02:00
parent a6c4d1e8a5
commit 8a1154522e
4 changed files with 96 additions and 41 deletions

View File

@@ -1,27 +1,61 @@
import { Image, StyleSheet, Platform, Button, View } from 'react-native';
import { Image, StyleSheet, Platform, Button, View, FlatList, Text } from 'react-native';
import { NativeModules } from 'react-native';
import { useEffect, useState } from 'react';
import { HelloWave } from '@/components/HelloWave';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
interface Credential {
username: string;
password: string;
service: string;
}
export default function HomeScreen() {
const handleInsertEntry = () => {
const [credentials, setCredentials] = useState<Credential[]>([]);
const fetchCredentials = async () => {
try {
const result = await NativeModules.CredentialManager.getCredentials();
setCredentials(result);
} catch (error) {
console.error('Error fetching credentials:', error);
}
};
useEffect(() => {
fetchCredentials();
}, []);
const handleInsertEntry = async () => {
// Generate a random credential
const randomUsername = `user${Math.floor(Math.random() * 1000)}`;
const randomPassword = `pass${Math.floor(Math.random() * 1000)}`;
const randomService = `service${Math.floor(Math.random() * 1000)}`;
// Call native module to add credential
NativeModules.CredentialManager.addCredential(randomUsername, randomPassword, randomService);
await NativeModules.CredentialManager.addCredential(randomUsername, randomPassword, randomService);
// Add a small delay to ensure the operation is complete
await new Promise(resolve => setTimeout(resolve, 100));
fetchCredentials(); // Refresh the list
};
const handleClearVault = () => {
const handleClearVault = async () => {
// Call native module to clear credentials
NativeModules.CredentialManager.clearCredentials();
await NativeModules.CredentialManager.clearCredentials();
setCredentials([]); // Clear the list
};
const renderCredential = (item: Credential) => (
<ThemedView style={styles.credentialItem} key={`${item.service}-${item.username}`}>
<ThemedText type="defaultSemiBold">Service: {item.service}</ThemedText>
<ThemedText>Username: {item.username}</ThemedText>
<ThemedText>Password: {item.password}</ThemedText>
</ThemedView>
);
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
@@ -32,7 +66,7 @@ export default function HomeScreen() {
/>
}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Welcome!</ThemedText>
<ThemedText type="title">AliasVault</ThemedText>
<HelloWave />
</ThemedView>
@@ -41,37 +75,12 @@ export default function HomeScreen() {
<View style={styles.buttonSpacer} />
<Button title="Clear Vault" onPress={handleClearVault} color="red" />
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 1: Try it</ThemedText>
<ThemedText>
Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
Press{' '}
<ThemedText type="defaultSemiBold">
{Platform.select({
ios: 'cmd + d',
android: 'cmd + m',
web: 'F12'
})}
</ThemedText>{' '}
to open developer tools.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 2: Explore</ThemedText>
<ThemedText>
Tap the Explore tab to learn more about what's included in this starter app.
</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText>
<ThemedText>
When you're ready, run{' '}
<ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '}
<ThemedText type="defaultSemiBold">app</ThemedText> to{' '}
<ThemedText type="defaultSemiBold">app-example</ThemedText>.
</ThemedText>
<ThemedView style={styles.credentialsContainer}>
<ThemedText type="subtitle">Stored Credentials</ThemedText>
<View style={styles.credentialsList}>
{credentials.map(renderCredential)}
</View>
</ThemedView>
</ParallaxScrollView>
);
@@ -83,10 +92,6 @@ const styles = StyleSheet.create({
alignItems: 'center',
gap: 8,
},
stepContainer: {
gap: 8,
marginBottom: 8,
},
buttonContainer: {
marginVertical: 16,
paddingHorizontal: 16,
@@ -94,6 +99,19 @@ const styles = StyleSheet.create({
buttonSpacer: {
height: 8,
},
credentialsContainer: {
marginTop: 16,
paddingHorizontal: 16,
},
credentialsList: {
marginTop: 8,
},
credentialItem: {
padding: 12,
marginBottom: 8,
borderRadius: 8,
backgroundColor: '#f0f0f0',
},
reactLogo: {
height: 178,
width: 290,

View File

@@ -4,6 +4,7 @@
RCT_EXTERN_METHOD(addCredential:(NSString *)username password:(NSString *)password service:(NSString *)service)
RCT_EXTERN_METHOD(clearCredentials)
RCT_EXTERN_METHOD(getCredentials)
RCT_EXTERN_METHOD(requiresMainQueueSetup)
@end

View File

@@ -14,6 +14,19 @@ class CredentialManager: NSObject {
func clearCredentials() {
SharedCredentialStore.shared.clearAllCredentials()
}
@objc
func getCredentials() -> [[String: String]] {
let credentials = SharedCredentialStore.shared.getAllCredentials()
let credentialDicts = credentials.map { credential in
return [
"username": credential.username,
"password": credential.password,
"service": credential.service
]
}
return credentialDicts
}
@objc
static func requiresMainQueueSetup() -> Bool {

View File

@@ -15,6 +15,19 @@ class CredentialManager: NSObject {
SharedCredentialStore.shared.clearAllCredentials()
}
@objc
func getCredentials(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
let credentials = SharedCredentialStore.shared.getAllCredentials()
let credentialDicts = credentials.map { credential in
return [
"username": credential.username,
"password": credential.password,
"service": credential.service
]
}
resolve(credentialDicts)
}
@objc
static func requiresMainQueueSetup() -> Bool {
return false
@@ -24,4 +37,14 @@ class CredentialManager: NSObject {
static func moduleName() -> String! {
return "CredentialManager"
}
@objc
func constantsToExport() -> [AnyHashable : Any]! {
return [:]
}
@objc
func methodsToExport() -> [String]! {
return ["addCredential", "clearCredentials", "getCredentials"]
}
}