From 04937f5357f335c037256f14549f546033be4956 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 14 Jan 2026 11:41:37 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- README.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7492933..f4f3959 100644 --- a/README.md +++ b/README.md @@ -24,22 +24,29 @@ StorageRouter (main entry point) ### Services (Actors) - **StorageRouter** - Main entry point for all storage operations -- **KeychainHelper** - Secure keychain storage -- **EncryptionHelper** - AES-256-GCM or ChaCha20-Poly1305 with PBKDF2/HKDF -- **FileStorageHelper** - File system operations -- **UserDefaultsHelper** - UserDefaults with suite support -- **SyncHelper** - WatchConnectivity sync + +### Internal Helpers (Not Public API) +These helpers are internal implementation details used by `StorageRouter`. They are not part of the public API and should not be used directly. + +- **KeychainHelper** - Reads/writes secure items with Keychain APIs. +- **EncryptionHelper** - Handles encryption/decryption and key derivation. +- **FileStorageHelper** - Reads/writes files with appropriate protection. +- **UserDefaultsHelper** - Wraps UserDefaults and suites safely. +- **SyncHelper** - Manages WatchConnectivity sync. ### Models - **StorageDomain** - userDefaults, keychain, fileSystem, encryptedFileSystem - **SecurityPolicy** - none, keychain, encrypted (AES-256 or ChaCha20-Poly1305) - **Serializer** - JSON, plist, Data, or custom +- **KeyMaterialSource** - Identifier for external key material providers - **PlatformAvailability** - all, phoneOnly, watchOnly, phoneWithWatchSync - **SyncPolicy** - never, manual, automaticSmall - **KeychainAccessibility** - All 7 iOS accessibility options - **KeychainAccessControl** - All 6 access control options (biometry, passcode, etc.) - **FileDirectory** - documents, caches, custom URL - **StorageError** - Comprehensive error types +- **StorageKeyDescriptor** - Audit snapshot of a key’s storage metadata +- **AnyStorageKey** - Type-erased storage key for catalogs - **AnyCodable** - Type-erased Codable for mixed-type payloads ## Usage @@ -62,6 +69,7 @@ extension StorageKeys { ) let serializer: Serializer = .json let owner = "AuthService" + let description = "Stores the current user auth token." let availability: PlatformAvailability = .phoneOnly let syncPolicy: SyncPolicy = .never } @@ -116,7 +124,7 @@ try await StorageRouter.shared.remove(key) - Configurable PBKDF2 iteration count - Master key stored securely in keychain - Default security policy: `SecurityPolicy.recommended` (ChaCha20-Poly1305 + HKDF) -- External key material providers can be registered via `EncryptionHelper` +- External key material providers can be registered via `StorageRouter` ```swift struct RemoteKeyProvider: KeyMaterialProviding { @@ -127,7 +135,7 @@ struct RemoteKeyProvider: KeyMaterialProviding { } let source = KeyMaterialSource(id: "remote.key") -await EncryptionHelper.shared.registerKeyMaterialProvider(RemoteKeyProvider(), for: source) +await StorageRouter.shared.registerKeyMaterialProvider(RemoteKeyProvider(), for: source) let policy: SecurityPolicy.EncryptionPolicy = .external( source: source, @@ -155,6 +163,10 @@ The app owns WCSession activation and handling incoming updates. LocalData can generate a catalog of all configured storage keys, even if no data has been written yet. This is useful for security reviews and compliance. +### Why `AnyStorageKey`? + +`StorageKey` has an associated type (`Value`), which means you cannot store different keys in a single array using `[StorageKey]` or `some StorageKey`. Swift requires type erasure for heterogeneous protocol values, so the catalog uses `[AnyStorageKey]` and builds descriptors behind the scenes. + 1) Define a catalog in your app that lists all keys: ```swift @@ -185,6 +197,7 @@ do { } ``` +Each `StorageKey` must provide a human-readable `description` used in audit reports. Dynamic key names are intentionally not supported in the core API to keep storage auditing strict and predictable. If you need this later, see `FutureEnhancements.md` for a proposed design.