SecureStorageSample/SecureStorageSample/SecureStorageSampleApp.swift
Matt Bruce f4a4f1a527 comments
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
2026-01-17 12:18:05 -06:00

81 lines
3.6 KiB
Swift

//
// SecureStorageSampleApp.swift
// SecureStorageSample
//
// Created by Matt Bruce on 1/13/26.
//
import SwiftUI
import LocalData
import SharedKit
@main
/// App entry point that centralizes LocalData configuration and storage key registration.
/// Keeping this bootstrap in one place makes the sample's storage behavior easy to audit.
struct SecureStorageSampleApp: App {
init() {
// Log derived identifiers up front so it's obvious which services the sample uses.
StorageServiceIdentifiers.logConfiguration()
// Spin up WCSession early so background sync opportunities aren't missed.
_ = WatchConnectivityService.shared
Task {
// 1. Global Encryption Configuration
// We isolate our library's master key in the Keychain by providing a specific service
// and account name. This prevents conflicts with other apps using the same library.
// We also set PBKDF2 iterations for consistent security across the app.
let config = EncryptionConfiguration(
masterKeyService: "SecureStorageSample",
masterKeyAccount: "AppMasterKey",
pbkdf2Iterations: 20_000
)
await StorageRouter.shared.updateEncryptionConfiguration(config)
// 2. Global Sync Configuration
// Overriding the default 100KB limit for automatic Watch sync to 50KB.
// This demonstrates how to tune performance for low-bandwidth scenarios.
let syncConfig = SyncConfiguration(maxAutoSyncSize: 50_000)
await StorageRouter.shared.updateSyncConfiguration(syncConfig)
// 3. Global File Storage Configuration
// We scope all our library files into a "SecureStorage" sub-directory
// underneath the standard Documents/Caches folders.
let fileConfig = FileStorageConfiguration(subDirectory: "SecureStorage")
await StorageRouter.shared.updateFileStorageConfiguration(fileConfig)
// 4. Global Storage Defaults
// Setting default identifiers for Keychain and App Groups.
// This allows keys to be defined more concisely without repeating these IDs.
let storageConfig = StorageConfiguration(
defaultKeychainService: StorageServiceIdentifiers.bundleIdentifier,
defaultAppGroupIdentifier: StorageServiceIdentifiers.appGroupIdentifier
)
await StorageRouter.shared.updateStorageConfiguration(storageConfig)
// Register keys once so LocalData can validate and migrate them consistently.
do {
try await StorageRouter.shared.registerCatalog(AppStorageCatalog(), migrateImmediately: true)
} catch {
assertionFailure("Storage catalog registration failed: \(error)")
}
// Provide external key material for the encrypted storage demo.
await StorageRouter.shared.registerKeyMaterialProvider(
ExternalKeyMaterialProvider(),
for: SampleKeyMaterialSources.external
)
// If a watch is paired, send the current syncable payloads on launch.
await StorageRouter.shared.syncRegisteredKeysIfNeeded()
}
#if DEBUG
// Disabled to keep console focused on sync logs.
// let report = StorageAuditReport.renderText(AppStorageCatalog())
// print(report)
#endif
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}