Refactoring
This commit is contained in:
parent
43ccc12468
commit
4bcb862065
|
@ -30,6 +30,10 @@ extension MockKeychainService: KeychainService {
|
|||
static func getPrivateKey(applicationTag: String, attributes: [String: Any]) throws -> Data? {
|
||||
fatalError("not implemented")
|
||||
}
|
||||
|
||||
static func deleteKey(applicationTag: String) throws {
|
||||
fatalError("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
private extension MockKeychainService {
|
||||
|
|
|
@ -89,7 +89,7 @@ private extension NotificationService {
|
|||
let serverPublicKeyData = Data(base64Encoded: serverPublicKeyBase64)
|
||||
else { throw NotificationServiceError.userInfoDataAbsent }
|
||||
|
||||
let secretsService = SecretsService(identityID: identityID, keychainServiceType: LiveKeychainService.self)
|
||||
let secretsService = SecretsService(identityID: identityID, keychainService: LiveKeychainService.self)
|
||||
|
||||
guard
|
||||
let auth = try secretsService.getPushAuth(),
|
||||
|
|
|
@ -31,7 +31,7 @@ extension IdentitiesService {
|
|||
}
|
||||
|
||||
func authorizeIdentity(id: UUID, instanceURL: URL) -> AnyPublisher<Void, Error> {
|
||||
let secretsService = SecretsService(identityID: id, keychainServiceType: environment.keychainServiceType)
|
||||
let secretsService = SecretsService(identityID: id, keychainService: environment.keychainServiceType)
|
||||
let authenticationService = AuthenticationService(environment: environment)
|
||||
|
||||
return authenticationService.authorizeApp(instanceURL: instanceURL)
|
||||
|
@ -57,7 +57,7 @@ extension IdentitiesService {
|
|||
.tryMap { _ -> Void in
|
||||
try SecretsService(
|
||||
identityID: id,
|
||||
keychainServiceType: environment.keychainServiceType)
|
||||
keychainService: environment.keychainServiceType)
|
||||
.deleteAllItems()
|
||||
|
||||
return ()
|
||||
|
|
|
@ -32,7 +32,7 @@ class IdentityService {
|
|||
self.identity = identity
|
||||
secretsService = SecretsService(
|
||||
identityID: identityID,
|
||||
keychainServiceType: environment.keychainServiceType)
|
||||
keychainService: environment.keychainServiceType)
|
||||
networkClient = MastodonClient(session: environment.session)
|
||||
networkClient.instanceURL = identity.url
|
||||
networkClient.accessToken = try secretsService.item(.accessToken)
|
||||
|
|
|
@ -8,6 +8,7 @@ protocol KeychainService {
|
|||
static func getGenericPassword(account: String, service: String) throws -> Data?
|
||||
static func generateKeyAndReturnPublicKey(applicationTag: String, attributes: [String: Any]) throws -> Data
|
||||
static func getPrivateKey(applicationTag: String, attributes: [String: Any]) throws -> Data?
|
||||
static func deleteKey(applicationTag: String) throws
|
||||
}
|
||||
|
||||
struct LiveKeychainService {}
|
||||
|
@ -104,6 +105,14 @@ extension LiveKeychainService: KeychainService {
|
|||
throw NSError(status: status)
|
||||
}
|
||||
}
|
||||
|
||||
static func deleteKey(applicationTag: String) throws {
|
||||
let status = SecItemDelete(keyQueryDictionary(applicationTag: applicationTag) as CFDictionary)
|
||||
|
||||
if status != errSecSuccess {
|
||||
throw NSError(status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension LiveKeychainService {
|
||||
|
|
|
@ -13,11 +13,11 @@ enum SecretsStorableError: Error {
|
|||
|
||||
struct SecretsService {
|
||||
let identityID: UUID
|
||||
private let keychainServiceType: KeychainService.Type
|
||||
private let keychainService: KeychainService.Type
|
||||
|
||||
init(identityID: UUID, keychainServiceType: KeychainService.Type) {
|
||||
init(identityID: UUID, keychainService: KeychainService.Type) {
|
||||
self.identityID = identityID
|
||||
self.keychainServiceType = keychainServiceType
|
||||
self.keychainService = keychainService
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,16 +31,30 @@ extension SecretsService {
|
|||
}
|
||||
}
|
||||
|
||||
extension SecretsService.Item {
|
||||
enum Kind {
|
||||
case genericPassword
|
||||
case key
|
||||
}
|
||||
|
||||
var kind: Kind {
|
||||
switch self {
|
||||
case .pushKey: return .key
|
||||
default: return .genericPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SecretsService {
|
||||
func set(_ data: SecretsStorable, forItem item: Item) throws {
|
||||
try keychainServiceType.setGenericPassword(
|
||||
try keychainService.setGenericPassword(
|
||||
data: data.dataStoredInSecrets,
|
||||
forAccount: key(item: item),
|
||||
service: Self.keychainServiceName)
|
||||
}
|
||||
|
||||
func item<T: SecretsStorable>(_ item: Item) throws -> T? {
|
||||
guard let data = try keychainServiceType.getGenericPassword(
|
||||
guard let data = try keychainService.getGenericPassword(
|
||||
account: key(item: item),
|
||||
service: Self.keychainServiceName) else {
|
||||
return nil
|
||||
|
@ -51,20 +65,25 @@ extension SecretsService {
|
|||
|
||||
func deleteAllItems() throws {
|
||||
for item in SecretsService.Item.allCases {
|
||||
try keychainServiceType.deleteGenericPassword(
|
||||
account: key(item: item),
|
||||
service: Self.keychainServiceName)
|
||||
switch item.kind {
|
||||
case .genericPassword:
|
||||
try keychainService.deleteGenericPassword(
|
||||
account: key(item: item),
|
||||
service: Self.keychainServiceName)
|
||||
case .key:
|
||||
try keychainService.deleteKey(applicationTag: key(item: item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generatePushKeyAndReturnPublicKey() throws -> Data {
|
||||
try keychainServiceType.generateKeyAndReturnPublicKey(
|
||||
try keychainService.generateKeyAndReturnPublicKey(
|
||||
applicationTag: key(item: .pushKey),
|
||||
attributes: PushKey.attributes)
|
||||
}
|
||||
|
||||
func getPushKey() throws -> Data? {
|
||||
try keychainServiceType.getPrivateKey(
|
||||
try keychainService.getPrivateKey(
|
||||
applicationTag: key(item: .pushKey),
|
||||
attributes: PushKey.attributes)
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ extension RootViewModel {
|
|||
|
||||
func deleteIdentity(id: UUID) {
|
||||
identitiesService.deleteIdentity(id: id)
|
||||
.sink(receiveCompletion: { _ in }, receiveValue: {})
|
||||
.sink { _ in } receiveValue: { _ in }
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,29 +9,23 @@ class AddIdentityViewModelTests: XCTestCase {
|
|||
func testAddIdentity() throws {
|
||||
let identityDatabase = IdentityDatabase.fresh()
|
||||
let sut = AddIdentityViewModel(identitiesService: .fresh(identityDatabase: identityDatabase))
|
||||
let addedIDAndURLRecorder = sut.addedIdentityIDAndURL.record()
|
||||
let addedIDRecorder = sut.addedIdentityID.record()
|
||||
|
||||
sut.urlFieldText = "https://mastodon.social"
|
||||
sut.logInTapped()
|
||||
|
||||
let addedIdentityIDAndURL = try wait(for: addedIDAndURLRecorder.next(), timeout: 1)
|
||||
|
||||
// XCTAssertEqual(addedIdentityIDAndURL.0, addedIdentityID)
|
||||
XCTAssertEqual(addedIdentityIDAndURL.1, URL(string: "https://mastodon.social")!)
|
||||
_ = try wait(for: addedIDRecorder.next(), timeout: 1)
|
||||
}
|
||||
|
||||
func testAddIdentityWithoutScheme() throws {
|
||||
let identityDatabase = IdentityDatabase.fresh()
|
||||
let sut = AddIdentityViewModel(identitiesService: .fresh(identityDatabase: identityDatabase))
|
||||
let addedIDAndURLRecorder = sut.addedIdentityIDAndURL.record()
|
||||
let addedIDRecorder = sut.addedIdentityID.record()
|
||||
|
||||
sut.urlFieldText = "mastodon.social"
|
||||
sut.logInTapped()
|
||||
|
||||
let addedIdentityIDAndURL = try wait(for: addedIDAndURLRecorder.next(), timeout: 1)
|
||||
|
||||
// XCTAssertEqual(addedIdentityIDAndURL.0, addedIdentityID)
|
||||
XCTAssertEqual(addedIdentityIDAndURL.1, URL(string: "https://mastodon.social")!)
|
||||
_ = try wait(for: addedIDRecorder.next(), timeout: 1)
|
||||
}
|
||||
|
||||
func testInvalidURL() throws {
|
||||
|
|
|
@ -20,8 +20,8 @@ class RootViewModelTests: XCTestCase {
|
|||
|
||||
let addIdentityViewModel = sut.addIdentityViewModel()
|
||||
|
||||
addIdentityViewModel.addedIdentityIDAndURL
|
||||
.sink(receiveValue: sut.newIdentityCreated(id:instanceURL:))
|
||||
addIdentityViewModel.addedIdentityID
|
||||
.sink(receiveValue: sut.newIdentitySelected(id:))
|
||||
.store(in: &cancellables)
|
||||
|
||||
addIdentityViewModel.urlFieldText = "https://mastodon.social"
|
||||
|
|
Loading…
Reference in New Issue