Show credentials when logged in (#771)

This commit is contained in:
Leendert de Borst
2025-04-11 16:41:42 +02:00
parent eda0fb4d4e
commit 653ea2b657
2 changed files with 152 additions and 3 deletions

View File

@@ -11,7 +11,7 @@ import { SrpUtility } from '@/utils/SrpUtility';
import EncryptionUtility from '@/utils/EncryptionUtility';
import { ApiAuthError } from '@/utils/types/errors/ApiAuthError';
import { useWebApi } from '@/context/WebApiContext';
import { Credential } from '@/utils/types/Credential';
export default function HomeScreen() {
const [credentials, setCredentials] = useState({
username: '',
@@ -99,11 +99,15 @@ export default function HomeScreen() {
throw new Error('Login failed -- no token returned');
}
console.log('validationResponse.token', validationResponse.token);
// Try to get latest vault manually providing auth token.
const vaultResponseJson = await webApi.authFetch<any>('Vault', { method: 'GET', headers: {
'Authorization': `Bearer ${validationResponse.token.token}`
} });
console.log('vaultResponseJson', vaultResponseJson);
const vaultError = webApi.validateVaultResponse(vaultResponseJson);
if (vaultError) {
console.error('vaultError', vaultError);
@@ -112,15 +116,22 @@ export default function HomeScreen() {
return;
}
console.log('vaultResponseJson', vaultResponseJson);
// All is good. Store auth info which is required to make requests to the web API.
await authContext.setAuthTokens(credentials.username, validationResponse.token.token, validationResponse.token.refreshToken);
console.log('auth tokens set');
// Initialize the SQLite context with the new vault data.
await dbContext.initializeDatabase(vaultResponseJson, passwordHashBase64);
console.log('database initialized');
// Set logged in status to true which refreshes the app.
await authContext.login();
console.log('logged in');
setIsLoading(false);
} catch (err) {
// Show API authentication errors as-is.
@@ -204,7 +215,31 @@ export default function HomeScreen() {
}
};
if (!isAuthenticated) {
const [credentialsList, setCredentialsList] = useState<Credential[]>([]);
const [isLoadingCredentials, setIsLoadingCredentials] = useState(false);
useEffect(() => {
if (!isAuthenticated || !isDatabaseAvailable) {
return;
}
const loadCredentials = async () => {
setIsLoadingCredentials(true);
try {
const credentialsList = await dbContext.sqliteClient!.getAllCredentials();
console.log('credentialsList', credentialsList);
setCredentialsList(credentialsList);
} catch (err) {
console.error('Error loading credentials:', err);
}
setIsLoadingCredentials(false);
};
loadCredentials();
}, [isAuthenticated, isDatabaseAvailable]);
if (!isAuthenticated || !isDatabaseAvailable) {
return (
<SafeAreaView style={styles.container}>
<ThemedView style={styles.content}>
@@ -312,7 +347,25 @@ export default function HomeScreen() {
<ThemedText type="title">AliasVault</ThemedText>
</ThemedView>
<ThemedView style={styles.stepContainer}>
<ThemedText type="subtitle">Logged in</ThemedText>
<ThemedText type="subtitle">Your Credentials</ThemedText>
{isLoadingCredentials ? (
<ActivityIndicator size="large" color="#f97316" />
) : (
<FlatList
data={credentialsList}
keyExtractor={(item) => item.Id}
renderItem={({ item }) => (
<View style={styles.credentialItem}>
<Text style={styles.serviceName}>{item.ServiceName ?? 'Unknown Service'}</Text>
{item.Username && <Text style={styles.credentialText}>Username: {item.Username}</Text>}
{item.Alias?.Email && <Text style={styles.credentialText}>Email: {item.Alias.Email}</Text>}
</View>
)}
ListEmptyComponent={
<Text style={styles.emptyText}>No credentials found</Text>
}
/>
)}
</ThemedView>
</ThemedView>
</SafeAreaView>
@@ -412,4 +465,38 @@ const styles = StyleSheet.create({
textAlign: 'center',
marginTop: 16,
},
logoutButton: {
backgroundColor: '#f97316',
padding: 12,
borderRadius: 8,
alignItems: 'center',
},
logoutButtonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
credentialItem: {
backgroundColor: '#fff',
padding: 16,
borderRadius: 8,
marginBottom: 8,
borderWidth: 1,
borderColor: '#d1d5db',
},
serviceName: {
fontSize: 16,
fontWeight: '600',
marginBottom: 4,
},
credentialText: {
fontSize: 14,
color: '#4b5563',
},
emptyText: {
textAlign: 'center',
fontSize: 16,
color: '#6b7280',
marginTop: 24,
},
});

View File

@@ -0,0 +1,62 @@
import { StyleSheet, Button, SafeAreaView, TouchableOpacity } from 'react-native';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { useWebApi } from '@/context/WebApiContext';
import { router } from 'expo-router';
export default function SettingsScreen() {
const webApi = useWebApi();
const handleLogout = async () => {
await webApi.logout();
router.replace('/');
};
return (
<SafeAreaView style={styles.container}>
<ThemedView style={styles.content}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Settings</ThemedText>
</ThemedView>
<ThemedView style={styles.settingsContainer}>
<TouchableOpacity
style={styles.logoutButton}
onPress={handleLogout}
>
<ThemedText style={styles.logoutButtonText}>Logout</ThemedText>
</TouchableOpacity>
</ThemedView>
</ThemedView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
padding: 16,
},
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
marginBottom: 16,
},
settingsContainer: {
flex: 1,
gap: 8,
},
logoutButton: {
backgroundColor: '#FF3B30',
padding: 16,
borderRadius: 8,
},
logoutButtonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: 'bold',
},
});