Update Models, Services and tests

Summary:
- Sources: update Models, Services
- Tests: update tests for KeychainHelperTests.swift, LocalDataTests.swift

Stats:
- 4 files changed, 20 insertions(+), 24 deletions(-)
This commit is contained in:
Matt Bruce 2026-01-15 11:23:48 -06:00
parent 905330f1f0
commit 1519683d02
4 changed files with 20 additions and 24 deletions

View File

@ -20,15 +20,6 @@ public enum KeychainAccessibility: Sendable, CaseIterable {
/// Data is not migrated to a new device.
case afterFirstUnlockThisDeviceOnly
/// Item is always accessible, regardless of device lock state.
/// Least secure - use only when absolutely necessary.
@available(iOS, deprecated: 12.0, message: "Use an accessibility level that provides some user protection, such as afterFirstUnlock")
case always
/// Item is always accessible but not migrated to new devices.
@available(iOS, deprecated: 12.0, message: "Use an accessibility level that provides some user protection, such as afterFirstUnlockThisDeviceOnly")
case alwaysThisDeviceOnly
/// Item is only accessible when the device has a passcode set.
/// If passcode is removed, item becomes inaccessible.
case whenPasscodeSetThisDeviceOnly
@ -44,10 +35,6 @@ public enum KeychainAccessibility: Sendable, CaseIterable {
return kSecAttrAccessibleWhenUnlockedThisDeviceOnly
case .afterFirstUnlockThisDeviceOnly:
return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
case .always:
return kSecAttrAccessibleAlways
case .alwaysThisDeviceOnly:
return kSecAttrAccessibleAlwaysThisDeviceOnly
case .whenPasscodeSetThisDeviceOnly:
return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
}
@ -64,12 +51,18 @@ public enum KeychainAccessibility: Sendable, CaseIterable {
return "When Unlocked (This Device)"
case .afterFirstUnlockThisDeviceOnly:
return "After First Unlock (This Device)"
case .always:
return "Always"
case .alwaysThisDeviceOnly:
return "Always (This Device)"
case .whenPasscodeSetThisDeviceOnly:
return "When Passcode Set (This Device)"
}
}
public static var allCases: [KeychainAccessibility] {
[
.whenUnlocked,
.afterFirstUnlock,
.whenUnlockedThisDeviceOnly,
.afterFirstUnlockThisDeviceOnly,
.whenPasscodeSetThisDeviceOnly
]
}
}

View File

@ -316,7 +316,10 @@ public actor StorageRouter: StorageProviding {
// MARK: - Storage Operations
private func store(_ data: Data, for key: any StorageKey) async throws {
let descriptor = StorageKeyDescriptor.from(key)
try await store(data, for: .from(key))
}
private func store(_ data: Data, for descriptor: StorageKeyDescriptor) async throws {
switch descriptor.domain {
case .userDefaults(let suite):
try await UserDefaultsHelper.shared.set(data, forKey: descriptor.name, suite: suite)
@ -438,7 +441,7 @@ public actor StorageRouter: StorageProviding {
// The data received is already 'secured' (encrypted if necessary) by the sender.
// We can store it directly in our local domain.
try await store(data, for: entry)
try await store(data, for: entry.descriptor)
Logger.info("Successfully updated local storage from sync for key: \(keyName)")
}

View File

@ -12,7 +12,7 @@ struct KeychainHelperTests {
let data = Data("secret-password".utf8)
defer {
try? KeychainHelper.shared.delete(service: testService, key: key)
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
try await KeychainHelper.shared.set(
@ -47,7 +47,7 @@ struct KeychainHelperTests {
let data = Data("test".utf8)
defer {
try? KeychainHelper.shared.delete(service: testService, key: key)
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
let beforeExists = try await KeychainHelper.shared.exists(service: testService, key: key)
@ -70,7 +70,7 @@ struct KeychainHelperTests {
let updatedData = Data("updated".utf8)
defer {
try? KeychainHelper.shared.delete(service: testService, key: key)
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
try await KeychainHelper.shared.set(
@ -127,7 +127,7 @@ struct KeychainHelperTests {
let data = Data("data-for-\(accessibility)".utf8)
defer {
try? KeychainHelper.shared.delete(service: testService, key: key)
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
try await KeychainHelper.shared.set(

View File

@ -56,7 +56,7 @@ struct LocalDataTests {
#expect(fetched == storedValue)
try await StorageRouter.shared.remove(key)
#expect(throws: StorageError.notFound) {
await #expect(throws: StorageError.notFound) {
_ = try await StorageRouter.shared.get(key)
}
}