Refactoring

This commit is contained in:
Justin Mazzocchi 2020-08-08 18:29:05 -07:00
parent bffcac49e9
commit 330d796442
No known key found for this signature in database
GPG Key ID: E223E6937AAFB01C
8 changed files with 72 additions and 47 deletions

View File

@ -11,7 +11,7 @@ private let devIdentityID = UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E
private let devAccessToken = "DEVELOPMENT_ACCESS_TOKEN" private let devAccessToken = "DEVELOPMENT_ACCESS_TOKEN"
extension Secrets { extension Secrets {
static func fresh() -> Secrets { Secrets(keychain: FakeKeychain()) } static func fresh() -> Secrets { Secrets(keychainService: MockKeychainService()) }
static let development: Secrets = { static let development: Secrets = {
let secrets = Secrets.fresh() let secrets = Secrets.fresh()
@ -25,7 +25,7 @@ extension Secrets {
} }
extension Defaults { extension Defaults {
static func fresh() -> Defaults { Defaults(userDefaults: FakeUserDefaults()) } static func fresh() -> Defaults { Defaults(userDefaults: MockUserDefaults()) }
static let development: Defaults = { static let development: Defaults = {
let preferences = Defaults.fresh() let preferences = Defaults.fresh()

View File

@ -2,18 +2,20 @@
import Foundation import Foundation
typealias FakeKeychain = [String: Data] class MockKeychainService {
private var guts = [String: Data]()
extension FakeKeychain: KeychainType {
mutating func set(data: Data, forKey key: String) throws {
self[key] = data
} }
mutating func deleteData(key: String) throws { extension MockKeychainService: KeychainServiceType {
self[key] = nil func set(data: Data, forKey key: String) throws {
guts[key] = data
}
func deleteData(key: String) throws {
guts[key] = nil
} }
func getData(key: String) throws -> Data? { func getData(key: String) throws -> Data? {
self[key] guts[key]
} }
} }

View File

@ -0,0 +1,21 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Foundation
class MockKeychainService {
private var items = [String: Data]()
}
extension MockKeychainService: KeychainServiceType {
func set(data: Data, forKey key: String) throws {
items[key] = data
}
func deleteData(key: String) throws {
items[key] = nil
}
func getData(key: String) throws -> Data? {
items[key]
}
}

View File

@ -2,7 +2,7 @@
import Foundation import Foundation
class FakeUserDefaults: UserDefaults { class MockUserDefaults: UserDefaults {
convenience init() { convenience init() {
self.init(suiteName: Self.suiteName)! self.init(suiteName: Self.suiteName)!
} }
@ -16,6 +16,6 @@ class FakeUserDefaults: UserDefaults {
} }
} }
private extension FakeUserDefaults { private extension MockUserDefaults {
private static let suiteName = "com.metatext.metabolist.fake-user-defaults" private static let suiteName = "com.metatext.metabolist.mock-user-defaults"
} }

View File

@ -55,8 +55,8 @@
D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; }; D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; };
D04FD74324D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; }; D04FD74324D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; };
D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC624D749C800A80A7A /* RootViewModelTests.swift */; }; D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC624D749C800A80A7A /* RootViewModelTests.swift */; };
D052BBCA24D74C9200A80A7A /* FakeUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */; }; D052BBCA24D74C9200A80A7A /* MockUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */; };
D052BBCB24D74C9300A80A7A /* FakeUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */; }; D052BBCB24D74C9300A80A7A /* MockUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */; };
D052BBCF24D750C000A80A7A /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCE24D750C000A80A7A /* Defaults.swift */; }; D052BBCF24D750C000A80A7A /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCE24D750C000A80A7A /* Defaults.swift */; };
D052BBD024D750C000A80A7A /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCE24D750C000A80A7A /* Defaults.swift */; }; D052BBD024D750C000A80A7A /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCE24D750C000A80A7A /* Defaults.swift */; };
D052BBD124D750CA00A80A7A /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCC24D750A100A80A7A /* AppEnvironment.swift */; }; D052BBD124D750CA00A80A7A /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCC24D750A100A80A7A /* AppEnvironment.swift */; };
@ -134,12 +134,12 @@
D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC175A24D0154F00A75C65 /* MastodonAPI.swift */; }; D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC175A24D0154F00A75C65 /* MastodonAPI.swift */; };
D0DC175F24D016EA00A75C65 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = D0DC175E24D016EA00A75C65 /* Alamofire */; }; D0DC175F24D016EA00A75C65 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = D0DC175E24D016EA00A75C65 /* Alamofire */; };
D0DC176124D0171800A75C65 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = D0DC176024D0171800A75C65 /* Alamofire */; }; D0DC176124D0171800A75C65 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = D0DC176024D0171800A75C65 /* Alamofire */; };
D0DC177424D0B58800A75C65 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177324D0B58800A75C65 /* Keychain.swift */; }; D0DC177724D0CF2600A75C65 /* MockKeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */; };
D0DC177524D0B58800A75C65 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177324D0B58800A75C65 /* Keychain.swift */; }; D0DC177824D0CF2600A75C65 /* MockKeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */; };
D0DC177724D0CF2600A75C65 /* FakeKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */; };
D0DC177824D0CF2600A75C65 /* FakeKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */; };
D0EC8DC224DF7D9C00A08489 /* IdentityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */; }; D0EC8DC224DF7D9C00A08489 /* IdentityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */; };
D0EC8DC324DF7D9C00A08489 /* IdentityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */; }; D0EC8DC324DF7D9C00A08489 /* IdentityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */; };
D0EC8DC524DF842700A08489 /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC424DF842700A08489 /* KeychainService.swift */; };
D0EC8DC624DF842700A08489 /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC424DF842700A08489 /* KeychainService.swift */; };
D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */; }; D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */; };
D0ED1BB724CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; }; D0ED1BB724CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; };
D0ED1BB824CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; }; D0ED1BB824CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; };
@ -204,7 +204,7 @@
D04FD73B24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InstanceEndpoint+Stubbing.swift"; sourceTree = "<group>"; }; D04FD73B24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InstanceEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
D04FD74124D4AA34007D572D /* DevelopmentModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevelopmentModels.swift; sourceTree = "<group>"; }; D04FD74124D4AA34007D572D /* DevelopmentModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevelopmentModels.swift; sourceTree = "<group>"; };
D052BBC624D749C800A80A7A /* RootViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModelTests.swift; sourceTree = "<group>"; }; D052BBC624D749C800A80A7A /* RootViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModelTests.swift; sourceTree = "<group>"; };
D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeUserDefaults.swift; sourceTree = "<group>"; }; D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserDefaults.swift; sourceTree = "<group>"; };
D052BBCC24D750A100A80A7A /* AppEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = "<group>"; }; D052BBCC24D750A100A80A7A /* AppEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = "<group>"; };
D052BBCE24D750C000A80A7A /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; }; D052BBCE24D750C000A80A7A /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
D065F53A24D3B33A00741304 /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; }; D065F53A24D3B33A00741304 /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
@ -242,9 +242,9 @@
D0DC175424D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccessTokenEndpoint+Stubbing.swift"; sourceTree = "<group>"; }; D0DC175424D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccessTokenEndpoint+Stubbing.swift"; sourceTree = "<group>"; };
D0DC175724D0130800A75C65 /* HTTPStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStubs.swift; sourceTree = "<group>"; }; D0DC175724D0130800A75C65 /* HTTPStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStubs.swift; sourceTree = "<group>"; };
D0DC175A24D0154F00A75C65 /* MastodonAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAPI.swift; sourceTree = "<group>"; }; D0DC175A24D0154F00A75C65 /* MastodonAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAPI.swift; sourceTree = "<group>"; };
D0DC177324D0B58800A75C65 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; }; D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockKeychainService.swift; sourceTree = "<group>"; };
D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeKeychain.swift; sourceTree = "<group>"; };
D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityService.swift; sourceTree = "<group>"; }; D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityService.swift; sourceTree = "<group>"; };
D0EC8DC424DF842700A08489 /* KeychainService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainService.swift; sourceTree = "<group>"; };
D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddIdentityViewModelTests.swift; sourceTree = "<group>"; }; D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddIdentityViewModelTests.swift; sourceTree = "<group>"; };
D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthSession.swift; sourceTree = "<group>"; }; D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthSession.swift; sourceTree = "<group>"; };
D0ED1BC024CED48800B4899C /* HTTPClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = "<group>"; }; D0ED1BC024CED48800B4899C /* HTTPClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = "<group>"; };
@ -350,6 +350,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */, D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */,
D0EC8DC424DF842700A08489 /* KeychainService.swift */,
); );
path = Services; path = Services;
sourceTree = "<group>"; sourceTree = "<group>";
@ -437,7 +438,6 @@
D0666A5324C6C3E500F3F04B /* Emoji.swift */, D0666A5324C6C3E500F3F04B /* Emoji.swift */,
D0666A4A24C6C37700F3F04B /* Identity.swift */, D0666A4A24C6C37700F3F04B /* Identity.swift */,
D0666A4D24C6C39600F3F04B /* Instance.swift */, D0666A4D24C6C39600F3F04B /* Instance.swift */,
D0DC177324D0B58800A75C65 /* Keychain.swift */,
D0ED1BE224CFA84400B4899C /* MastodonError.swift */, D0ED1BE224CFA84400B4899C /* MastodonError.swift */,
D0CD847224DBDEC700CF380C /* MastodonPreferences.swift */, D0CD847224DBDEC700CF380C /* MastodonPreferences.swift */,
D0666A7124C6E0D300F3F04B /* Secrets.swift */, D0666A7124C6E0D300F3F04B /* Secrets.swift */,
@ -536,8 +536,8 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D04FD74124D4AA34007D572D /* DevelopmentModels.swift */, D04FD74124D4AA34007D572D /* DevelopmentModels.swift */,
D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */, D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */,
D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */, D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */,
D0DC175724D0130800A75C65 /* HTTPStubs.swift */, D0DC175724D0130800A75C65 /* HTTPStubs.swift */,
D0DC174824CFF13700A75C65 /* Mastodon API Stubs */, D0DC174824CFF13700A75C65 /* Mastodon API Stubs */,
D0DC174C24CFF1F100A75C65 /* Stubbing.swift */, D0DC174C24CFF1F100A75C65 /* Stubbing.swift */,
@ -783,13 +783,14 @@
D0DC175524D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */, D0DC175524D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */,
D0B23F0D24D210E90066F411 /* NSError+Extensions.swift in Sources */, D0B23F0D24D210E90066F411 /* NSError+Extensions.swift in Sources */,
D019E6D924DF728400697C7D /* MastodonDecoder.swift in Sources */, D019E6D924DF728400697C7D /* MastodonDecoder.swift in Sources */,
D052BBCA24D74C9200A80A7A /* FakeUserDefaults.swift in Sources */, D052BBCA24D74C9200A80A7A /* MockUserDefaults.swift in Sources */,
D0DC175224D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */, D0DC175224D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */,
D0BEC94A24CA231200E864C4 /* TimelineView.swift in Sources */, D0BEC94A24CA231200E864C4 /* TimelineView.swift in Sources */,
D0BEC93B24C96FD500E864C4 /* RootView.swift in Sources */, D0BEC93B24C96FD500E864C4 /* RootView.swift in Sources */,
D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */, D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */,
D0EC8DC524DF842700A08489 /* KeychainService.swift in Sources */,
D0DC175824D0130800A75C65 /* HTTPStubs.swift in Sources */, D0DC175824D0130800A75C65 /* HTTPStubs.swift in Sources */,
D0DC177724D0CF2600A75C65 /* FakeKeychain.swift in Sources */, D0DC177724D0CF2600A75C65 /* MockKeychainService.swift in Sources */,
D0EC8DC224DF7D9C00A08489 /* IdentityService.swift in Sources */, D0EC8DC224DF7D9C00A08489 /* IdentityService.swift in Sources */,
D0C963FB24CC359D003BD330 /* AlertItem.swift in Sources */, D0C963FB24CC359D003BD330 /* AlertItem.swift in Sources */,
D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */, D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */,
@ -802,7 +803,6 @@
D0091B6E24DD68090040E8D2 /* PreferencesView.swift in Sources */, D0091B6E24DD68090040E8D2 /* PreferencesView.swift in Sources */,
D0159F8F24DE743700E78478 /* IdentitiesView.swift in Sources */, D0159F8F24DE743700E78478 /* IdentitiesView.swift in Sources */,
D0DB6EF424C5228A00D965FE /* AddIdentityView.swift in Sources */, D0DB6EF424C5228A00D965FE /* AddIdentityView.swift in Sources */,
D0DC177424D0B58800A75C65 /* Keychain.swift in Sources */,
D074577724D29006004758DB /* StubbingWebAuthSession.swift in Sources */, D074577724D29006004758DB /* StubbingWebAuthSession.swift in Sources */,
D0159FA524DE989700E78478 /* NSMutableAttributedString+Extensions.swift in Sources */, D0159FA524DE989700E78478 /* NSMutableAttributedString+Extensions.swift in Sources */,
D0ED1BCE24CF768200B4899C /* MastodonEndpoint.swift in Sources */, D0ED1BCE24CF768200B4899C /* MastodonEndpoint.swift in Sources */,
@ -855,7 +855,7 @@
D019E6E424DF72E700697C7D /* PreferencesEndpoint.swift in Sources */, D019E6E424DF72E700697C7D /* PreferencesEndpoint.swift in Sources */,
D0DC175624D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */, D0DC175624D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */,
D0B23F0E24D210E90066F411 /* NSError+Extensions.swift in Sources */, D0B23F0E24D210E90066F411 /* NSError+Extensions.swift in Sources */,
D052BBCB24D74C9300A80A7A /* FakeUserDefaults.swift in Sources */, D052BBCB24D74C9300A80A7A /* MockUserDefaults.swift in Sources */,
D0DC175324D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */, D0DC175324D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */,
D0BEC94B24CA231200E864C4 /* TimelineView.swift in Sources */, D0BEC94B24CA231200E864C4 /* TimelineView.swift in Sources */,
D0BEC93C24C96FD500E864C4 /* RootView.swift in Sources */, D0BEC93C24C96FD500E864C4 /* RootView.swift in Sources */,
@ -863,7 +863,7 @@
D04FD74324D4AA34007D572D /* DevelopmentModels.swift in Sources */, D04FD74324D4AA34007D572D /* DevelopmentModels.swift in Sources */,
D0DC175924D0130800A75C65 /* HTTPStubs.swift in Sources */, D0DC175924D0130800A75C65 /* HTTPStubs.swift in Sources */,
D019E6DA24DF728400697C7D /* MastodonDecoder.swift in Sources */, D019E6DA24DF728400697C7D /* MastodonDecoder.swift in Sources */,
D0DC177824D0CF2600A75C65 /* FakeKeychain.swift in Sources */, D0DC177824D0CF2600A75C65 /* MockKeychainService.swift in Sources */,
D0C963FC24CC359D003BD330 /* AlertItem.swift in Sources */, D0C963FC24CC359D003BD330 /* AlertItem.swift in Sources */,
D019E6E224DF72E700697C7D /* AppAuthorizationEndpoint.swift in Sources */, D019E6E224DF72E700697C7D /* AppAuthorizationEndpoint.swift in Sources */,
D0DC174724CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */, D0DC174724CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */,
@ -874,7 +874,6 @@
D0091B6F24DD68090040E8D2 /* PreferencesView.swift in Sources */, D0091B6F24DD68090040E8D2 /* PreferencesView.swift in Sources */,
D0DB6EF524C5233E00D965FE /* AddIdentityView.swift in Sources */, D0DB6EF524C5233E00D965FE /* AddIdentityView.swift in Sources */,
D019E6EA24DF72E700697C7D /* InstanceEndpoint.swift in Sources */, D019E6EA24DF72E700697C7D /* InstanceEndpoint.swift in Sources */,
D0DC177524D0B58800A75C65 /* Keychain.swift in Sources */,
D0159F9C24DE748C00E78478 /* SidebarNavigationView.swift in Sources */, D0159F9C24DE748C00E78478 /* SidebarNavigationView.swift in Sources */,
D019E6F124DF7C2F00697C7D /* DatabaseError.swift in Sources */, D019E6F124DF7C2F00697C7D /* DatabaseError.swift in Sources */,
D074577824D29006004758DB /* StubbingWebAuthSession.swift in Sources */, D074577824D29006004758DB /* StubbingWebAuthSession.swift in Sources */,
@ -889,6 +888,7 @@
D04FD73D24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */, D04FD73D24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */,
D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */, D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */,
D0ED1BD224CF779B00B4899C /* MastodonTarget.swift in Sources */, D0ED1BD224CF779B00B4899C /* MastodonTarget.swift in Sources */,
D0EC8DC624DF842700A08489 /* KeychainService.swift in Sources */,
D0CD847D24DBEA9F00CF380C /* Unknowable.swift in Sources */, D0CD847D24DBEA9F00CF380C /* Unknowable.swift in Sources */,
D0666A7024C6DFB300F3F04B /* AccessToken.swift in Sources */, D0666A7024C6DFB300F3F04B /* AccessToken.swift in Sources */,
D0ED1BCC24CF744200B4899C /* MastodonClient.swift in Sources */, D0ED1BCC24CF744200B4899C /* MastodonClient.swift in Sources */,

View File

@ -19,7 +19,7 @@ struct MetatextApp: App {
URLSessionConfiguration: .default, URLSessionConfiguration: .default,
identityDatabase: identityDatabase, identityDatabase: identityDatabase,
defaults: Defaults(userDefaults: .standard), defaults: Defaults(userDefaults: .standard),
secrets: Secrets(keychain: Keychain(service: "com.metabolist.metatext")), secrets: Secrets(keychainService: KeychainService(serviceName: "com.metabolist.metatext")),
webAuthSessionType: RealWebAuthSession.self) webAuthSessionType: RealWebAuthSession.self)
} }

View File

@ -12,10 +12,10 @@ enum SecretsStorableError: Error {
} }
class Secrets { class Secrets {
private var keychain: KeychainType private let keychainService: KeychainServiceType
init(keychain: KeychainType) { init(keychainService: KeychainServiceType) {
self.keychain = keychain self.keychainService = keychainService
} }
} }
@ -29,17 +29,19 @@ extension Secrets {
extension Secrets { extension Secrets {
func set(_ data: SecretsStorable, forItem item: Item, forIdentityID identityID: UUID) throws { func set(_ data: SecretsStorable, forItem item: Item, forIdentityID identityID: UUID) throws {
try keychain.set(data: data.dataStoredInSecrets, forKey: Self.key(item: item, identityID: identityID)) try keychainService.set(data: data.dataStoredInSecrets, forKey: Self.key(item: item, identityID: identityID))
} }
func item<T: SecretsStorable>(_ item: Item, forIdentityID identityID: UUID) throws -> T? { func item<T: SecretsStorable>(_ item: Item, forIdentityID identityID: UUID) throws -> T? {
guard let data = try keychain.getData(key: Self.key(item: item, identityID: identityID)) else { return nil } guard let data = try keychainService.getData(key: Self.key(item: item, identityID: identityID)) else {
return nil
}
return try T.fromDataStoredInSecrets(data) return try T.fromDataStoredInSecrets(data)
} }
func delete(_ item: Item, forIdentityID identityID: UUID) throws { func delete(_ item: Item, forIdentityID identityID: UUID) throws {
try keychain.deleteData(key: Self.key(item: item, identityID: identityID)) try keychainService.deleteData(key: Self.key(item: item, identityID: identityID))
} }
} }

View File

@ -2,18 +2,18 @@
import Foundation import Foundation
protocol KeychainType { protocol KeychainServiceType {
mutating func set(data: Data, forKey key: String) throws func set(data: Data, forKey key: String) throws
mutating func deleteData(key: String) throws func deleteData(key: String) throws
func getData(key: String) throws -> Data? func getData(key: String) throws -> Data?
} }
struct Keychain { struct KeychainService {
let service: String let serviceName: String
} }
extension Keychain: KeychainType { extension KeychainService: KeychainServiceType {
mutating func set(data: Data, forKey key: String) throws { func set(data: Data, forKey key: String) throws {
var query = queryDictionary(key: key) var query = queryDictionary(key: key)
query[kSecValueData as String] = data query[kSecValueData as String] = data
@ -25,7 +25,7 @@ extension Keychain: KeychainType {
} }
} }
mutating func deleteData(key: String) throws { func deleteData(key: String) throws {
let status = SecItemDelete(queryDictionary(key: key) as CFDictionary) let status = SecItemDelete(queryDictionary(key: key) as CFDictionary)
if status != errSecSuccess { if status != errSecSuccess {
@ -53,10 +53,10 @@ extension Keychain: KeychainType {
} }
} }
private extension Keychain { private extension KeychainService {
private func queryDictionary(key: String) -> [String: Any] { private func queryDictionary(key: String) -> [String: Any] {
[ [
kSecAttrService as String: service, kSecAttrService as String: serviceName,
kSecAttrAccount as String: key, kSecAttrAccount as String: key,
kSecClass as String: kSecClassGenericPassword kSecClass as String: kSecClassGenericPassword
] ]