SecureStorageSample/SecureStorgageSample/StorageKeys.swift

272 lines
8.8 KiB
Swift

//
// StorageKeys.swift
// SecureStorgageSample
//
// Example StorageKey implementations demonstrating all variations
// supported by the LocalData package.
//
import Foundation
import LocalData
// MARK: - Sample Data Models
/// Simple credential model for keychain storage demo.
nonisolated(unsafe)
struct Credential: Codable, Sendable {
let username: String
let password: String
}
/// Location data model.
nonisolated(unsafe)
struct SampleLocationData: Codable, Sendable {
let lat: Double
let lon: Double
}
// MARK: - UserDefaults Keys
extension StorageKeys {
/// Stores the app version in standard UserDefaults.
/// - Domain: UserDefaults (standard)
/// - Security: None
/// - Sync: Automatic for small data
struct AppVersionKey: StorageKey {
typealias Value = String
let name = "last_app_version"
let domain: StorageDomain = .userDefaults(suite: nil)
let security: SecurityPolicy = .none
let serializer: Serializer<String> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .all
let syncPolicy: SyncPolicy = .automaticSmall
}
/// Stores user preferences in a custom suite.
/// - Domain: UserDefaults (custom suite)
/// - Security: None
/// - Sync: Never
struct UserPreferencesKey: StorageKey {
typealias Value = [String: AnyCodable]
let name = "user_preferences"
let domain: StorageDomain = .userDefaults(suite: "group.com.example.securestorage")
let security: SecurityPolicy = .none
let serializer: Serializer<[String: AnyCodable]> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .all
let syncPolicy: SyncPolicy = .never
}
}
// MARK: - Keychain Keys
extension StorageKeys {
/// Stores user credentials securely in keychain.
/// Configurable accessibility and access control.
struct CredentialsKey: StorageKey {
typealias Value = Credential
let name = "user_credentials"
let domain: StorageDomain = .keychain(service: "com.example.securestorage")
let security: SecurityPolicy
let serializer: Serializer<Credential> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .phoneOnly
let syncPolicy: SyncPolicy = .never
init(accessibility: KeychainAccessibility = .afterFirstUnlock, accessControl: KeychainAccessControl? = nil) {
self.security = .keychain(accessibility: accessibility, accessControl: accessControl)
}
}
/// Stores sensitive location data in keychain with biometric protection.
struct LastLocationKey: StorageKey {
typealias Value = SampleLocationData
let name = "last_known_location"
let domain: StorageDomain = .keychain(service: "com.example.app.security")
let security: SecurityPolicy = .keychain(
accessibility: .afterFirstUnlock,
accessControl: .userPresence
)
let serializer: Serializer<SampleLocationData> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .phoneOnly
let syncPolicy: SyncPolicy = .never
}
/// Stores API token in keychain.
struct APITokenKey: StorageKey {
typealias Value = String
let name = "api_token"
let domain: StorageDomain = .keychain(service: "com.example.securestorage.api")
let security: SecurityPolicy = .keychain(
accessibility: .whenUnlockedThisDeviceOnly,
accessControl: nil
)
let serializer: Serializer<String> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .phoneOnly
let syncPolicy: SyncPolicy = .never
}
}
// MARK: - File System Keys
extension StorageKeys {
/// Stores user profile as JSON file in documents.
struct UserProfileFileKey: StorageKey {
typealias Value = UserProfile
let name = UserProfile.storageKeyName
let domain: StorageDomain
let security: SecurityPolicy = .none
let serializer: Serializer<UserProfile> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .phoneWithWatchSync
let syncPolicy: SyncPolicy = .automaticSmall
init(directory: FileDirectory = .documents) {
self.domain = .fileSystem(directory: directory)
}
}
/// Stores cached data files.
struct CachedDataKey: StorageKey {
typealias Value = Data
let name = "cached_data.bin"
let domain: StorageDomain = .fileSystem(directory: .caches)
let security: SecurityPolicy = .none
let serializer: Serializer<Data> = .data
let owner = "SampleApp"
let availability: PlatformAvailability = .all
let syncPolicy: SyncPolicy = .never
}
/// Stores settings as property list.
struct SettingsPlistKey: StorageKey {
typealias Value = [String: AnyCodable]
let name = "settings.plist"
let domain: StorageDomain = .fileSystem(directory: .documents)
let security: SecurityPolicy = .none
let serializer: Serializer<[String: AnyCodable]> = .plist
let owner = "SampleApp"
let availability: PlatformAvailability = .all
let syncPolicy: SyncPolicy = .never
}
}
// MARK: - Encrypted File System Keys
extension StorageKeys {
/// Stores session logs with full encryption.
/// Configurable PBKDF2 iterations.
struct SessionLogsKey: StorageKey {
typealias Value = [String]
let name = "session_logs.json"
let domain: StorageDomain = .encryptedFileSystem(directory: .caches)
let security: SecurityPolicy
let serializer: Serializer<[String]> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .phoneOnly
let syncPolicy: SyncPolicy = .never
init(iterations: Int = 10_000) {
self.security = .encrypted(.aes256(keyDerivation: .pbkdf2(iterations: iterations)))
}
}
/// Stores private notes with encryption.
struct PrivateNotesKey: StorageKey {
typealias Value = String
let name = "private_notes.enc"
let domain: StorageDomain = .encryptedFileSystem(directory: .documents)
let security: SecurityPolicy = .encrypted(
.aes256(keyDerivation: .pbkdf2(iterations: 50_000))
)
let serializer: Serializer<String> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .phoneOnly
let syncPolicy: SyncPolicy = .never
}
}
// MARK: - Platform-Specific Keys
extension StorageKeys {
/// Watch-only setting for vibration.
struct WatchVibrationKey: StorageKey {
typealias Value = Bool
let name = "watch_vibration_enabled"
let domain: StorageDomain = .userDefaults(suite: nil)
let security: SecurityPolicy = .none
let serializer: Serializer<Bool> = .json
let owner = "SampleApp"
let availability: PlatformAvailability = .watchOnly
let syncPolicy: SyncPolicy = .never
}
/// Syncable setting with configurable platform and sync policy.
struct SyncableSettingKey: StorageKey {
typealias Value = String
let name = "syncable_setting"
let domain: StorageDomain = .userDefaults(suite: nil)
let security: SecurityPolicy = .none
let serializer: Serializer<String> = .json
let owner = "SampleApp"
let availability: PlatformAvailability
let syncPolicy: SyncPolicy
init(availability: PlatformAvailability = .all, syncPolicy: SyncPolicy = .never) {
self.availability = availability
self.syncPolicy = syncPolicy
}
}
}
// MARK: - Custom Serializer Example
extension StorageKeys {
/// Example using custom serializer for specialized encoding.
struct CustomEncodedKey: StorageKey {
typealias Value = String
let name = "custom_encoded"
let domain: StorageDomain = .fileSystem(directory: .documents)
let security: SecurityPolicy = .none
let serializer: Serializer<String> = .custom(
encode: { value in
// Example: Base64 encode
Data(value.utf8).base64EncodedData()
},
decode: { data in
guard let decoded = Data(base64Encoded: data),
let string = String(data: decoded, encoding: .utf8) else {
throw StorageError.deserializationFailed
}
return string
}
)
let owner = "SampleApp"
let availability: PlatformAvailability = .all
let syncPolicy: SyncPolicy = .never
}
}