diff --git a/Keychain/.gitignore b/Keychain/.gitignore new file mode 100644 index 0000000..95c4320 --- /dev/null +++ b/Keychain/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ diff --git a/Keychain/Package.swift b/Keychain/Package.swift new file mode 100644 index 0000000..8f597ee --- /dev/null +++ b/Keychain/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version:5.3 + +import PackageDescription + +let package = Package( + name: "Keychain", + platforms: [ + .iOS(.v14), + .macOS(.v11) + ], + products: [ + .library( + name: "Keychain", + targets: ["Keychain"]), + .library( + name: "MockKeychain", + targets: ["MockKeychain"]) + ], + dependencies: [], + targets: [ + .target( + name: "Keychain", + dependencies: []), + .target( + name: "MockKeychain", + dependencies: ["Keychain"]), + .testTarget( + name: "KeychainTests", + dependencies: ["MockKeychain"]) + ] +) diff --git a/ServiceLayer/Sources/ServiceLayer/Extensions/NSError+Extensions.swift b/Keychain/Sources/Keychain/Extensions/NSError+Extensions.swift similarity index 100% rename from ServiceLayer/Sources/ServiceLayer/Extensions/NSError+Extensions.swift rename to Keychain/Sources/Keychain/Extensions/NSError+Extensions.swift diff --git a/ServiceLayer/Sources/ServiceLayer/KeychainService.swift b/Keychain/Sources/Keychain/Keychain.swift similarity index 96% rename from ServiceLayer/Sources/ServiceLayer/KeychainService.swift rename to Keychain/Sources/Keychain/Keychain.swift index 1a7c2ca..65b1eca 100644 --- a/ServiceLayer/Sources/ServiceLayer/KeychainService.swift +++ b/Keychain/Sources/Keychain/Keychain.swift @@ -2,7 +2,7 @@ import Foundation -public protocol KeychainService { +public protocol Keychain { static func setGenericPassword(data: Data, forAccount key: String, service: String) throws static func deleteGenericPassword(account: String, service: String) throws static func getGenericPassword(account: String, service: String) throws -> Data? @@ -11,9 +11,9 @@ public protocol KeychainService { static func deleteKey(applicationTag: String) throws } -public struct LiveKeychainService {} +public struct LiveKeychain {} -extension LiveKeychainService: KeychainService { +extension LiveKeychain: Keychain { public static func setGenericPassword(data: Data, forAccount account: String, service: String) throws { var query = genericPasswordQueryDictionary(account: account, service: service) @@ -115,7 +115,7 @@ extension LiveKeychainService: KeychainService { } } -private extension LiveKeychainService { +private extension LiveKeychain { static func genericPasswordQueryDictionary(account: String, service: String) -> [String: Any] { [kSecAttrService as String: service, kSecAttrAccount as String: account, diff --git a/ServiceLayer/Sources/ServiceLayerMocks/MockKeychainService.swift b/Keychain/Sources/MockKeychain/MockKeychainService.swift similarity index 84% rename from ServiceLayer/Sources/ServiceLayerMocks/MockKeychainService.swift rename to Keychain/Sources/MockKeychain/MockKeychainService.swift index fd68117..5622970 100644 --- a/ServiceLayer/Sources/ServiceLayerMocks/MockKeychainService.swift +++ b/Keychain/Sources/MockKeychain/MockKeychainService.swift @@ -1,17 +1,17 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation -import ServiceLayer +import Keychain -public struct MockKeychainService {} +public struct MockKeychain {} -public extension MockKeychainService { +public extension MockKeychain { static func reset() { items = [String: Data]() } } -extension MockKeychainService: KeychainService { +extension MockKeychain: Keychain { public static func setGenericPassword(data: Data, forAccount key: String, service: String) throws { items[key] = data } @@ -37,6 +37,6 @@ extension MockKeychainService: KeychainService { } } -private extension MockKeychainService { +private extension MockKeychain { static var items = [String: Data]() } diff --git a/Keychain/Tests/KeychainTests/KeychainTests.swift b/Keychain/Tests/KeychainTests/KeychainTests.swift new file mode 100644 index 0000000..ddb8d72 --- /dev/null +++ b/Keychain/Tests/KeychainTests/KeychainTests.swift @@ -0,0 +1,10 @@ +import XCTest +@testable import Keychain + +final class KeychainTests: XCTestCase { + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + } +} diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index c5cc533..720675b 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -7,18 +7,19 @@ objects = { /* Begin PBXBuildFile section */ - D0175CAC24FE2D6300B085F6 /* PreviewViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D0175CAB24FE2D6300B085F6 /* PreviewViewModels */; }; D01F41D724F880C400D55A2D /* StatusTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D01F41D424F880C400D55A2D /* StatusTableViewCell.xib */; }; D01F41D824F880C400D55A2D /* StatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D524F880C400D55A2D /* StatusTableViewCell.swift */; }; D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; }; D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41E224F8889700D55A2D /* AttachmentsView.swift */; }; D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06B492224D4611300642749 /* KingfisherSwiftUI */; }; - D0BDF66B24FD7CEC00C7FA1C /* ServiceLayer in Frameworks */ = {isa = PBXBuildFile; productRef = D0BDF66A24FD7CEC00C7FA1C /* ServiceLayer */; }; D0BEB1F324F8EE8C001B0F04 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* AttachmentView.swift */; }; D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */; }; D0BEB1FF24F9E5BB001B0F04 /* ListsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1FE24F9E5BB001B0F04 /* ListsView.swift */; }; D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB20424FA1107001B0F04 /* FiltersView.swift */; }; D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB21024FA2A90001B0F04 /* EditFilterView.swift */; }; + D0BECB982501C0FC002C1B13 /* Secrets in Frameworks */ = {isa = PBXBuildFile; productRef = D0BECB972501C0FC002C1B13 /* Secrets */; }; + D0BECB9A2501C15F002C1B13 /* Mastodon in Frameworks */ = {isa = PBXBuildFile; productRef = D0BECB992501C15F002C1B13 /* Mastodon */; }; + D0BECB9C2501C731002C1B13 /* PreviewViewModels in Frameworks */ = {isa = PBXBuildFile; productRef = D0BECB9B2501C731002C1B13 /* PreviewViewModels */; }; D0C7D49724F7616A001EBDBB /* IdentitiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42224F76169001EBDBB /* IdentitiesView.swift */; }; D0C7D49824F7616A001EBDBB /* CustomEmojiText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42324F76169001EBDBB /* CustomEmojiText.swift */; }; D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C7D42424F76169001EBDBB /* AddIdentityView.swift */; }; @@ -92,6 +93,8 @@ D0BEB1FE24F9E5BB001B0F04 /* ListsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsView.swift; sourceTree = ""; }; D0BEB20424FA1107001B0F04 /* FiltersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersView.swift; sourceTree = ""; }; D0BEB21024FA2A90001B0F04 /* EditFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditFilterView.swift; sourceTree = ""; }; + D0BECB952501B3DD002C1B13 /* Keychain */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Keychain; sourceTree = ""; }; + D0BECB962501BCE0002C1B13 /* Secrets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Secrets; sourceTree = ""; }; D0BFDAF524FC7C5300C86618 /* HTTP */ = {isa = PBXFileReference; lastKnownFileType = folder; path = HTTP; sourceTree = ""; }; D0C7D41E24F76169001EBDBB /* Metatext.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Metatext.entitlements; sourceTree = ""; }; D0C7D41F24F76169001EBDBB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -132,7 +135,7 @@ files = ( D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */, D0E2C1D124FD97F000854680 /* ViewModels in Frameworks */, - D0175CAC24FE2D6300B085F6 /* PreviewViewModels in Frameworks */, + D0BECB9C2501C731002C1B13 /* PreviewViewModels in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -147,7 +150,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D0BDF66B24FD7CEC00C7FA1C /* ServiceLayer in Frameworks */, + D0BECB982501C0FC002C1B13 /* Secrets in Frameworks */, + D0BECB9A2501C15F002C1B13 /* Mastodon in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -181,10 +185,12 @@ D0C7D46824F76169001EBDBB /* Extensions */, D0666A7924C7745A00F3F04B /* Frameworks */, D0BFDAF524FC7C5300C86618 /* HTTP */, + D0BECB952501B3DD002C1B13 /* Keychain */, D0C7D45624F76169001EBDBB /* Localizations */, D0E0F1E424FC49FC002C04BF /* Mastodon */, D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */, D047FA8D24C3E21200AF17C5 /* Products */, + D0BECB962501BCE0002C1B13 /* Secrets */, D0BDF66524FD7A6400C7FA1C /* ServiceLayer */, D0C7D41D24F76169001EBDBB /* Supporting Files */, D0C7D45324F76169001EBDBB /* System */, @@ -323,7 +329,7 @@ packageProductDependencies = ( D06B492224D4611300642749 /* KingfisherSwiftUI */, D0E2C1D024FD97F000854680 /* ViewModels */, - D0175CAB24FE2D6300B085F6 /* PreviewViewModels */, + D0BECB9B2501C731002C1B13 /* PreviewViewModels */, ); productName = "Metatext (iOS)"; productReference = D047FA8C24C3E21200AF17C5 /* Metatext.app */; @@ -363,7 +369,8 @@ ); name = "Notification Service Extension"; packageProductDependencies = ( - D0BDF66A24FD7CEC00C7FA1C /* ServiceLayer */, + D0BECB972501C0FC002C1B13 /* Secrets */, + D0BECB992501C15F002C1B13 /* Mastodon */, ); productName = "Notification Service Extension"; productReference = D0E5361924E3EB4D00FB1CE1 /* Notification Service Extension.appex */; @@ -841,18 +848,22 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - D0175CAB24FE2D6300B085F6 /* PreviewViewModels */ = { - isa = XCSwiftPackageProductDependency; - productName = PreviewViewModels; - }; D06B492224D4611300642749 /* KingfisherSwiftUI */ = { isa = XCSwiftPackageProductDependency; package = D06B492124D4611300642749 /* XCRemoteSwiftPackageReference "Kingfisher" */; productName = KingfisherSwiftUI; }; - D0BDF66A24FD7CEC00C7FA1C /* ServiceLayer */ = { + D0BECB972501C0FC002C1B13 /* Secrets */ = { isa = XCSwiftPackageProductDependency; - productName = ServiceLayer; + productName = Secrets; + }; + D0BECB992501C15F002C1B13 /* Mastodon */ = { + isa = XCSwiftPackageProductDependency; + productName = Mastodon; + }; + D0BECB9B2501C731002C1B13 /* PreviewViewModels */ = { + isa = XCSwiftPackageProductDependency; + productName = PreviewViewModels; }; D0E2C1D024FD97F000854680 /* ViewModels */ = { isa = XCSwiftPackageProductDependency; diff --git a/Notification Service Extension/NotificationService.swift b/Notification Service Extension/NotificationService.swift index 5cbc996..c256046 100644 --- a/Notification Service Extension/NotificationService.swift +++ b/Notification Service Extension/NotificationService.swift @@ -2,8 +2,9 @@ import UserNotifications import CryptoKit +import Keychain import Mastodon -import ServiceLayer +import Secrets class NotificationService: UNNotificationServiceExtension { @@ -91,7 +92,7 @@ private extension NotificationService { let serverPublicKeyData = Data(base64Encoded: serverPublicKeyBase64) else { throw NotificationServiceError.userInfoDataAbsent } - let secretsService = SecretsService(identityID: identityID, keychainService: LiveKeychainService.self) + let secretsService = Secrets(identityID: identityID, keychain: LiveKeychain.self) guard let auth = try secretsService.getPushAuth(), diff --git a/Secrets/.gitignore b/Secrets/.gitignore new file mode 100644 index 0000000..95c4320 --- /dev/null +++ b/Secrets/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ diff --git a/Secrets/Package.swift b/Secrets/Package.swift new file mode 100644 index 0000000..65bbbca --- /dev/null +++ b/Secrets/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version:5.3 + +import PackageDescription + +let package = Package( + name: "Secrets", + platforms: [ + .iOS(.v14), + .macOS(.v11) + ], + products: [ + .library( + name: "Secrets", + targets: ["Secrets"]) + ], + dependencies: [ + .package(path: "Keychain") + ], + targets: [ + .target( + name: "Secrets", + dependencies: ["Keychain"]), + .testTarget( + name: "SecretsTests", + dependencies: ["Secrets"]) + ] +) diff --git a/ServiceLayer/Sources/ServiceLayer/SecretsService.swift b/Secrets/Sources/Secrets/Secrets.swift similarity index 81% rename from ServiceLayer/Sources/ServiceLayer/SecretsService.swift rename to Secrets/Sources/Secrets/Secrets.swift index 5fd7bce..286dd6d 100644 --- a/ServiceLayer/Sources/ServiceLayer/SecretsService.swift +++ b/Secrets/Sources/Secrets/Secrets.swift @@ -1,6 +1,7 @@ // Copyright © 2020 Metabolist. All rights reserved. import Foundation +import Keychain public protocol SecretsStorable { var dataStoredInSecrets: Data { get } @@ -11,17 +12,17 @@ enum SecretsStorableError: Error { case conversionFromDataStoredInSecrets(Data) } -public struct SecretsService { +public struct Secrets { public let identityID: UUID - private let keychainService: KeychainService.Type + private let keychain: Keychain.Type - public init(identityID: UUID, keychainService: KeychainService.Type) { + public init(identityID: UUID, keychain: Keychain.Type) { self.identityID = identityID - self.keychainService = keychainService + self.keychain = keychain } } -public extension SecretsService { +public extension Secrets { enum Item: String, CaseIterable { case clientID case clientSecret @@ -35,7 +36,7 @@ enum SecretsServiceError: Error { case itemAbsent } -extension SecretsService.Item { +extension Secrets.Item { enum Kind { case genericPassword case key @@ -49,16 +50,16 @@ extension SecretsService.Item { } } -public extension SecretsService { +public extension Secrets { func set(_ data: SecretsStorable, forItem item: Item) throws { - try keychainService.setGenericPassword( + try keychain.setGenericPassword( data: data.dataStoredInSecrets, forAccount: key(item: item), service: Self.keychainServiceName) } func item(_ item: Item) throws -> T { - guard let data = try keychainService.getGenericPassword( + guard let data = try keychain.getGenericPassword( account: key(item: item), service: Self.keychainServiceName) else { throw SecretsServiceError.itemAbsent @@ -68,26 +69,26 @@ public extension SecretsService { } func deleteAllItems() throws { - for item in SecretsService.Item.allCases { + for item in Secrets.Item.allCases { switch item.kind { case .genericPassword: - try keychainService.deleteGenericPassword( + try keychain.deleteGenericPassword( account: key(item: item), service: Self.keychainServiceName) case .key: - try keychainService.deleteKey(applicationTag: key(item: item)) + try keychain.deleteKey(applicationTag: key(item: item)) } } } func generatePushKeyAndReturnPublicKey() throws -> Data { - try keychainService.generateKeyAndReturnPublicKey( + try keychain.generateKeyAndReturnPublicKey( applicationTag: key(item: .pushKey), attributes: PushKey.attributes) } func getPushKey() throws -> Data? { - try keychainService.getPrivateKey( + try keychain.getPrivateKey( applicationTag: key(item: .pushKey), attributes: PushKey.attributes) } @@ -109,7 +110,7 @@ public extension SecretsService { } } -private extension SecretsService { +private extension Secrets { static let keychainServiceName = "com.metabolist.metatext" func key(item: Item) -> String { diff --git a/Secrets/Tests/SecretsTests/SecretsTests.swift b/Secrets/Tests/SecretsTests/SecretsTests.swift new file mode 100644 index 0000000..77d3bf6 --- /dev/null +++ b/Secrets/Tests/SecretsTests/SecretsTests.swift @@ -0,0 +1,10 @@ +import XCTest +@testable import Secrets + +final class SecretsTests: XCTestCase { + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + } +} diff --git a/ServiceLayer/Package.swift b/ServiceLayer/Package.swift index 5cf3294..4d06236 100644 --- a/ServiceLayer/Package.swift +++ b/ServiceLayer/Package.swift @@ -19,15 +19,20 @@ let package = Package( dependencies: [ .package(url: "https://github.com/groue/CombineExpectations.git", .upToNextMajor(from: "0.5.0")), .package(path: "DB"), - .package(path: "Mastodon") + .package(path: "Keychain"), + .package(path: "Mastodon"), + .package(path: "Secrets") ], targets: [ .target( name: "ServiceLayer", - dependencies: ["DB"]), + dependencies: ["DB", "Secrets"]), .target( name: "ServiceLayerMocks", - dependencies: ["ServiceLayer", .product(name: "MastodonStubs", package: "Mastodon")]), + dependencies: [ + "ServiceLayer", + .product(name: "MastodonStubs", package: "Mastodon"), + .product(name: "MockKeychain", package: "Keychain")]), .testTarget( name: "ServiceLayerTests", dependencies: ["CombineExpectations", "ServiceLayerMocks"]) diff --git a/ServiceLayer/Sources/ServiceLayer/AllIdentitiesService.swift b/ServiceLayer/Sources/ServiceLayer/AllIdentitiesService.swift index 8074b16..62f2454 100644 --- a/ServiceLayer/Sources/ServiceLayer/AllIdentitiesService.swift +++ b/ServiceLayer/Sources/ServiceLayer/AllIdentitiesService.swift @@ -4,6 +4,7 @@ import DB import Foundation import Combine import Mastodon +import Secrets public struct AllIdentitiesService { public let mostRecentlyUsedIdentityID: AnyPublisher @@ -34,24 +35,24 @@ public extension AllIdentitiesService { } func authorizeIdentity(id: UUID, instanceURL: URL) -> AnyPublisher { - let secretsService = SecretsService(identityID: id, keychainService: environment.keychainServiceType) + let secrets = Secrets(identityID: id, keychain: environment.keychain) let authenticationService = AuthenticationService(environment: environment) return authenticationService.authorizeApp(instanceURL: instanceURL) .tryMap { appAuthorization -> (URL, AppAuthorization) in - try secretsService.set(appAuthorization.clientId, forItem: .clientID) - try secretsService.set(appAuthorization.clientSecret, forItem: .clientSecret) + try secrets.set(appAuthorization.clientId, forItem: .clientID) + try secrets.set(appAuthorization.clientSecret, forItem: .clientSecret) return (instanceURL, appAuthorization) } .flatMap(authenticationService.authenticate(instanceURL:appAuthorization:)) - .tryMap { try secretsService.set($0.accessToken, forItem: .accessToken) } + .tryMap { try secrets.set($0.accessToken, forItem: .accessToken) } .ignoreOutput() .eraseToAnyPublisher() } func deleteIdentity(_ identity: Identity) -> AnyPublisher { - let secretsService = SecretsService(identityID: identity.id, keychainService: environment.keychainServiceType) + let secrets = Secrets(identityID: identity.id, keychain: environment.keychain) let networkClient = APIClient(session: environment.session) networkClient.instanceURL = identity.url @@ -60,14 +61,14 @@ public extension AllIdentitiesService { .collect() .tryMap { _ in DeletionEndpoint.oauthRevoke( - token: try secretsService.item(.accessToken), - clientID: try secretsService.item(.clientID), - clientSecret: try secretsService.item(.clientSecret)) + token: try secrets.item(.accessToken), + clientID: try secrets.item(.clientID), + clientSecret: try secrets.item(.clientSecret)) } .flatMap(networkClient.request) .collect() .tryMap { _ in - try secretsService.deleteAllItems() + try secrets.deleteAllItems() try ContentDatabase.delete(forIdentityID: identity.id) } .ignoreOutput() diff --git a/ServiceLayer/Sources/ServiceLayer/Entities/AppEnvironment.swift b/ServiceLayer/Sources/ServiceLayer/Entities/AppEnvironment.swift index 18ccb07..9e72ea1 100644 --- a/ServiceLayer/Sources/ServiceLayer/Entities/AppEnvironment.swift +++ b/ServiceLayer/Sources/ServiceLayer/Entities/AppEnvironment.swift @@ -3,13 +3,14 @@ import DB import Foundation import HTTP +import Keychain import Mastodon import UserNotifications public struct AppEnvironment { let session: Session let webAuthSessionType: WebAuthSession.Type - let keychainServiceType: KeychainService.Type + let keychain: Keychain.Type let userDefaults: UserDefaults let userNotificationClient: UserNotificationClient let inMemoryContent: Bool @@ -17,14 +18,14 @@ public struct AppEnvironment { public init(session: Session, webAuthSessionType: WebAuthSession.Type, - keychainServiceType: KeychainService.Type, + keychain: Keychain.Type, userDefaults: UserDefaults, userNotificationClient: UserNotificationClient, inMemoryContent: Bool, identityFixture: IdentityFixture?) { self.session = session self.webAuthSessionType = webAuthSessionType - self.keychainServiceType = keychainServiceType + self.keychain = keychain self.userDefaults = userDefaults self.userNotificationClient = userNotificationClient self.inMemoryContent = inMemoryContent @@ -37,7 +38,7 @@ public extension AppEnvironment { Self( session: Session(configuration: .default), webAuthSessionType: LiveWebAuthSession.self, - keychainServiceType: LiveKeychainService.self, + keychain: LiveKeychain.self, userDefaults: .standard, userNotificationClient: .live(userNotificationCenter), inMemoryContent: false, diff --git a/ServiceLayer/Sources/ServiceLayer/IdentityService.swift b/ServiceLayer/Sources/ServiceLayer/IdentityService.swift index 7ac7c01..1494548 100644 --- a/ServiceLayer/Sources/ServiceLayer/IdentityService.swift +++ b/ServiceLayer/Sources/ServiceLayer/IdentityService.swift @@ -4,6 +4,7 @@ import DB import Foundation import Combine import Mastodon +import Secrets public class IdentityService { @Published public private(set) var identity: Identity @@ -13,7 +14,7 @@ public class IdentityService { private let contentDatabase: ContentDatabase private let environment: AppEnvironment private let networkClient: APIClient - private let secretsService: SecretsService + private let secrets: Secrets private let observationErrorsInput = PassthroughSubject() init(identityID: UUID, @@ -33,12 +34,12 @@ public class IdentityService { guard let identity = initialIdentity else { throw IdentityDatabaseError.identityNotFound } self.identity = identity - secretsService = SecretsService( + secrets = Secrets( identityID: identityID, - keychainService: environment.keychainServiceType) + keychain: environment.keychain) networkClient = APIClient(session: environment.session) networkClient.instanceURL = identity.url - networkClient.accessToken = try? secretsService.item(.accessToken) + networkClient.accessToken = try? secrets.item(.accessToken) contentDatabase = try ContentDatabase(identityID: identityID, inMemory: environment.inMemoryContent) @@ -168,8 +169,8 @@ public extension IdentityService { let auth: String do { - publicKey = try secretsService.generatePushKeyAndReturnPublicKey().base64EncodedString() - auth = try secretsService.generatePushAuth().base64EncodedString() + publicKey = try secrets.generatePushKeyAndReturnPublicKey().base64EncodedString() + auth = try secrets.generatePushAuth().base64EncodedString() } catch { return Fail(error: error).eraseToAnyPublisher() } diff --git a/ServiceLayer/Sources/ServiceLayerMocks/MockAppEnvironment.swift b/ServiceLayer/Sources/ServiceLayerMocks/MockAppEnvironment.swift index dd088cb..89f1054 100644 --- a/ServiceLayer/Sources/ServiceLayerMocks/MockAppEnvironment.swift +++ b/ServiceLayer/Sources/ServiceLayerMocks/MockAppEnvironment.swift @@ -3,6 +3,7 @@ import DB import Foundation import HTTP +import MockKeychain import ServiceLayer import Stubbing @@ -11,7 +12,7 @@ public extension AppEnvironment { AppEnvironment( session: Session(configuration: .stubbing), webAuthSessionType: SuccessfulMockWebAuthSession.self, - keychainServiceType: MockKeychainService.self, + keychain: MockKeychain.self, userDefaults: MockUserDefaults(), userNotificationClient: .mock, inMemoryContent: true, diff --git a/ViewModels/Tests/ViewModelsTests/AddIdentityViewModelTests.swift b/ViewModels/Tests/ViewModelsTests/AddIdentityViewModelTests.swift index 7dadee0..4d56831 100644 --- a/ViewModels/Tests/ViewModelsTests/AddIdentityViewModelTests.swift +++ b/ViewModels/Tests/ViewModelsTests/AddIdentityViewModelTests.swift @@ -5,6 +5,7 @@ import Combine import CombineExpectations import HTTP import Mastodon +import MockKeychain import ServiceLayer import ServiceLayerMocks @testable import ViewModels @@ -48,7 +49,7 @@ class AddIdentityViewModelTests: XCTestCase { let environment = AppEnvironment( session: Session(configuration: .stubbing), webAuthSessionType: CanceledLoginMockWebAuthSession.self, - keychainServiceType: MockKeychainService.self, + keychain: MockKeychain.self, userDefaults: MockUserDefaults(), userNotificationClient: .mock, inMemoryContent: true,