267 lines
8.7 KiB
Swift
267 lines
8.7 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 = [String: AnyCodable]
|
|
|
|
let name = "user_profile.json"
|
|
let domain: StorageDomain = .fileSystem(directory: .documents)
|
|
let security: SecurityPolicy = .none
|
|
let serializer: Serializer<[String: AnyCodable]> = .json
|
|
let owner = "SampleApp"
|
|
let availability: PlatformAvailability = .phoneOnly
|
|
let syncPolicy: SyncPolicy = .never
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
}
|