SecureStorageSample/SecureStorgageSample/Views/EncryptedStorageDemo.swift

183 lines
6.2 KiB
Swift

//
// 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
@FocusState private var isFieldFocused: Bool
var body: some View {
Form {
Section {
Text("Encrypted file storage uses AES-256-GCM encryption with PBKDF2 key derivation. 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)
Stepper("PBKDF2 Iterations: \(iterations)", value: $iterations, in: 1000...100000, step: 1000)
.font(.caption)
Text("Higher iterations = more secure but slower")
.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: "AES-256-GCM")
LabeledContent("Key Derivation", value: "PBKDF2-SHA256")
LabeledContent("Iterations", value: "\(iterations)")
LabeledContent("File Protection", value: "Complete")
}
Section("Key Configuration") {
LabeledContent("Domain", value: "Encrypted File System")
LabeledContent("Directory", value: "Caches")
LabeledContent("Security", value: "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 {
let key = StorageKeys.SessionLogsKey(iterations: iterations)
// Load existing logs
var logs: [String]
do {
logs = try await StorageRouter.shared.get(key)
} catch StorageError.notFound {
logs = []
}
// Add new entry with timestamp
let timestamp = Date().formatted(date: .abbreviated, time: .standard)
logs.append("[\(timestamp)] \(logEntry)")
// Save encrypted
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 {
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 {
let key = StorageKeys.SessionLogsKey(iterations: iterations)
try await StorageRouter.shared.remove(key)
storedLogs = []
statusMessage = "✓ Encrypted logs cleared"
} catch {
statusMessage = "Error: \(error.localizedDescription)"
}
isLoading = false
}
}
}
#Preview {
NavigationStack {
EncryptedStorageDemo()
}
}