diff --git a/app/settings.tsx b/app/settings.tsx index 795d465..9ced1ec 100644 --- a/app/settings.tsx +++ b/app/settings.tsx @@ -9,7 +9,10 @@ import { resetAppState } from "../src/lib/resetAppState"; import { useBiometricStore } from "../src/features/security/biometric.store"; import { usePushNotifications } from "../src/features/notifications"; import { useRouter } from "expo-router"; -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; +import { keyManager } from "../src/lib/keyManager"; +import type { KeyInfo } from "../src/lib/keyManager"; +import { asyncStoragePersister } from "../src/lib/queryPersister"; export default function Settings() { const router = useRouter(); @@ -17,6 +20,11 @@ export default function Settings() { const [isResetting, setIsResetting] = useState(false); const biometricRequired = useBiometricStore((s) => s.biometricRequired); const setBiometricRequired = useBiometricStore((s) => s.setBiometricRequired); + const [keyInfo, setKeyInfo] = useState(null); + + useEffect(() => { + keyManager.getKeyInfo().then(setKeyInfo); + }, []); const { enabled: pushEnabled, @@ -56,6 +64,40 @@ export default function Settings() { } }; + const handleRotateKey = () => { + Alert.alert( + "Rotate Encryption Key", + "Are you sure you want to rotate the encryption key now? This will clear your currently downloaded offline data.", + [ + { text: "Cancel", style: "cancel" }, + { + text: "Rotate Key", + style: "destructive", + onPress: async () => { + try { + await keyManager.rotateKey({ + reencrypt: async () => { + await asyncStoragePersister.removeClient(); + }, + }); + const newInfo = await keyManager.getKeyInfo(); + setKeyInfo(newInfo); + } catch (error) { + Alert.alert("Error", "Failed to rotate encryption key."); + } + }, + }, + ], + ); + }; + + const getRelativeTimeString = (timestamp: number) => { + const days = Math.floor((Date.now() - timestamp) / (1000 * 60 * 60 * 24)); + if (days === 0) return "Created today"; + if (days === 1) return "Created 1 day ago"; + return `Created ${days} days ago`; + }; + const apiUrl = appConfig.apiUrl; const chainId = appConfig.chainId; @@ -116,6 +158,30 @@ export default function Settings() { + Offline Data & Security + + + Local Encryption Key + {keyInfo ? ( + <> + + {getRelativeTimeString(keyInfo.createdAt)} + + + Status: {keyInfo.needsRotation ? "Rotation Due" : "Healthy"} + + + ) : ( + Loading... + )} +