// // EncryptedStorageDemo.swift // SecureStorgageSample // // Demonstrates encrypted file storage with LocalData package. // import SwiftUI import LocalData struct EncryptedStorageDemo: View { @State private var logEntry = "" @State private var storedLogs: [String] = [] @State private var statusMessage = "" @State private var isLoading = false @State private var iterations = 10_000 @State private var useExternalKeyProvider = false @FocusState private var isFieldFocused: Bool var body: some View { Form { Section { Text("Encrypted file storage uses AES-256-GCM encryption with PBKDF2 key derivation. You can also switch to an external key provider that derives keys via HKDF. Data is encrypted before being written to disk with complete file protection.") .font(.caption) .foregroundStyle(.secondary) } Section("Add Log Entry") { TextField("Enter log message", text: $logEntry, axis: .vertical) .lineLimit(3, reservesSpace: true) .focused($isFieldFocused) Toggle("Use External Key Provider", isOn: $useExternalKeyProvider) if !useExternalKeyProvider { Stepper("PBKDF2 Iterations: \(iterations)", value: $iterations, in: 1000...100000, step: 1000) .font(.caption) Text("Higher iterations = more secure but slower") .font(.caption2) .foregroundStyle(.secondary) } else { Text("Key material is resolved from a registered provider.") .font(.caption2) .foregroundStyle(.secondary) } } Section("Actions") { Button(action: addLogEntry) { HStack { Image(systemName: "plus.circle.fill") Text("Add Encrypted Log Entry") } } .disabled(logEntry.isEmpty || isLoading) Button(action: loadLogs) { HStack { Image(systemName: "lock.open.fill") Text("Decrypt and Load Logs") } } .disabled(isLoading) Button(action: clearLogs) { HStack { Image(systemName: "trash") Text("Clear All Logs") } } .foregroundStyle(.red) .disabled(isLoading) } if !storedLogs.isEmpty { Section("Decrypted Logs (\(storedLogs.count))") { ForEach(Array(storedLogs.enumerated()), id: \.offset) { index, log in HStack { Text("\(index + 1).") .foregroundStyle(.secondary) Text(log) } .font(.system(.caption, design: .monospaced)) } } } if !statusMessage.isEmpty { Section { Text(statusMessage) .font(.caption) .foregroundStyle(statusMessage.contains("Error") ? .red : .green) } } Section("Encryption Details") { LabeledContent("Algorithm", value: useExternalKeyProvider ? "ChaCha20-Poly1305" : "AES-256-GCM") LabeledContent("Key Derivation", value: useExternalKeyProvider ? "HKDF-SHA256" : "PBKDF2-SHA256") if !useExternalKeyProvider { LabeledContent("Iterations", value: "\(iterations)") } else { LabeledContent("Key Source", value: "External Provider") } LabeledContent("File Protection", value: "Complete") } Section("Key Configuration") { LabeledContent("Domain", value: "Encrypted File System") LabeledContent("Directory", value: "Caches") LabeledContent("Security", value: useExternalKeyProvider ? "External Key Provider" : "AES-256 Encrypted") LabeledContent("Platform", value: "Phone Only") } } .navigationTitle("Encrypted Storage") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { isFieldFocused = false } } } } private func addLogEntry() { isLoading = true Task { do { if useExternalKeyProvider { let key = StorageKeys.ExternalSessionLogsKey() let logs = try await updatedLogs(for: key) try await StorageRouter.shared.set(logs, for: key) storedLogs = logs } else { let key = StorageKeys.SessionLogsKey(iterations: iterations) let logs = try await updatedLogs(for: key) try await StorageRouter.shared.set(logs, for: key) storedLogs = logs } logEntry = "" statusMessage = "✓ Entry encrypted and saved" } catch { statusMessage = "Error: \(error.localizedDescription)" } isLoading = false } } private func loadLogs() { isLoading = true Task { do { if useExternalKeyProvider { let key = StorageKeys.ExternalSessionLogsKey() storedLogs = try await StorageRouter.shared.get(key) } else { let key = StorageKeys.SessionLogsKey(iterations: iterations) storedLogs = try await StorageRouter.shared.get(key) } statusMessage = "✓ Decrypted \(storedLogs.count) log entries" } catch StorageError.notFound { storedLogs = [] statusMessage = "No encrypted logs found" } catch { statusMessage = "Error: \(error.localizedDescription)" } isLoading = false } } private func clearLogs() { isLoading = true Task { do { if useExternalKeyProvider { let key = StorageKeys.ExternalSessionLogsKey() try await StorageRouter.shared.remove(key) } else { let key = StorageKeys.SessionLogsKey(iterations: iterations) try await StorageRouter.shared.remove(key) } storedLogs = [] statusMessage = "✓ Encrypted logs cleared" } catch { statusMessage = "Error: \(error.localizedDescription)" } isLoading = false } } private func updatedLogs(for key: Key) async throws -> [String] where Key.Value == [String] { var logs: [String] do { logs = try await StorageRouter.shared.get(key) } catch StorageError.notFound { logs = [] } let timestamp = Date().formatted(date: .abbreviated, time: .standard) logs.append("[\(timestamp)] \(logEntry)") return logs } } #Preview { NavigationStack { EncryptedStorageDemo() } }