From b909a92d6083a18e1aa6072f918018af5876a86b Mon Sep 17 00:00:00 2001 From: ykyivskyi-gd Date: Thu, 15 Jul 2021 16:16:18 +0300 Subject: [PATCH 1/8] Created org rules permission services; Checking org rules permission on setup; Added method for getting private keys from EKM; --- FlowCrypt.xcodeproj/project.pbxproj | 4 ++ .../Setup/SetupInitialViewController.swift | 31 +++++++++--- .../Extensions/URLSessionExtension.swift | 3 +- .../Functionality/Services/GlobalRouter.swift | 8 ++-- ...ganisationalRulesPersmissionsService.swift | 47 +++++++++++++++++++ .../OrganisationalRulesService.swift | 29 ++++++++++++ FlowCrypt/Models/OrganisationalRule.swift | 8 ++++ .../Resources/en.lproj/Localizable.strings | 7 +++ .../Extensions/StringExtensions.swift | 9 +++- 9 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index bd58fa6ab..2932df3eb 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 04B472951ECE29F600B8266F /* MyMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04B472921ECE29F600B8266F /* MyMenuViewController.swift */; }; 04B472961ECE29F600B8266F /* SideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04B472931ECE29F600B8266F /* SideMenuNavigationController.swift */; }; 211392A5266511E6009202EC /* PubLookup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 211392A4266511E6009202EC /* PubLookup.swift */; }; + 2133D51626A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2133D51526A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift */; }; 21489B78267CB42400BDE4AC /* ClientConfigurationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */; }; 21489B7A267CB4DF00BDE4AC /* ClientConfigurationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B79267CB4DF00BDE4AC /* ClientConfigurationObject.swift */; }; 21489B7C267CBA0E00BDE4AC /* ClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B7B267CBA0E00BDE4AC /* ClientConfiguration.swift */; }; @@ -365,6 +366,7 @@ 113F04B20ECC35FC59A81A6C /* Pods-FlowCryptTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlowCryptTests.release.xcconfig"; path = "Target Support Files/Pods-FlowCryptTests/Pods-FlowCryptTests.release.xcconfig"; sourceTree = ""; }; 11C1375F41411882DC4C9431 /* Pods-FlowCryptUIApplication.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlowCryptUIApplication.release.xcconfig"; path = "Target Support Files/Pods-FlowCryptUIApplication/Pods-FlowCryptUIApplication.release.xcconfig"; sourceTree = ""; }; 211392A4266511E6009202EC /* PubLookup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PubLookup.swift; sourceTree = ""; }; + 2133D51526A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRulesPersmissionsService.swift; sourceTree = ""; }; 21489B6A267B7BD800BDE4AC /* FilesManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesManagerTests.swift; sourceTree = ""; }; 21489B6D267B7D5000BDE4AC /* FileMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMock.swift; sourceTree = ""; }; 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationProvider.swift; sourceTree = ""; }; @@ -791,6 +793,7 @@ 21489B81267CC3BC00BDE4AC /* Organisational Rules Service */ = { isa = PBXGroup; children = ( + 2133D51526A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift */, 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */, 21489B7F267CC39E00BDE4AC /* OrganisationalRulesService.swift */, 21489B82267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift */, @@ -2461,6 +2464,7 @@ D2F6D147243506DA00DB4065 /* MailSettingsCredentials.swift in Sources */, 9F9361A52573CE260009912F /* MessageProvider.swift in Sources */, 32DCA2BB910FA1B19BA8B328 /* Imap.swift in Sources */, + 2133D51626A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift in Sources */, D274724424FD1932006BA6EF /* FolderObject.swift in Sources */, 9FE1B3802563F85400D6D086 /* MessagesListProvider.swift in Sources */, 32DCA1B95DDC04D671F662F8 /* URLSessionExtension.swift in Sources */, diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index 29b81d6b5..0446cb758 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -23,12 +23,12 @@ final class SetupInitialViewController: TableNodeViewController { } private enum State { - case idle, searching, noKeyBackups, error(Error) + case idle, checkingPermissions, searching, noKeyBackups, error(Error) var numberOfRows: Int { switch self { // title - case .idle: + case .idle, .checkingPermissions: return 1 // title, loading case .searching: @@ -54,6 +54,7 @@ final class SetupInitialViewController: TableNodeViewController { private let router: GlobalRouterType private let decorator: SetupViewDecorator private let organisationalRules: OrganisationalRules + private let organisationalRulesPersmissionsService: OrganisationalRulesPersmissionsServiceType private lazy var logger = Logger.nested(in: Self.self, with: .setup) @@ -62,13 +63,15 @@ final class SetupInitialViewController: TableNodeViewController { backupService: BackupServiceType = BackupService(), router: GlobalRouterType = GlobalRouter(), decorator: SetupViewDecorator = SetupViewDecorator(), - organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService() + organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService(), + organisationalRulesPermissionsService: OrganisationalRulesPersmissionsServiceType = OrganisationalRulesPersmissionsService() ) { self.user = user self.backupService = backupService self.router = router self.decorator = decorator self.organisationalRules = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() + self.organisationalRulesPersmissionsService = organisationalRulesPermissionsService super.init(node: TableNode()) } @@ -86,7 +89,7 @@ final class SetupInitialViewController: TableNodeViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setNeedsStatusBarAppearanceUpdate() - state = .searching + state = .checkingPermissions } } @@ -99,7 +102,9 @@ extension SetupInitialViewController { switch state { case .searching: searchBackups() - default: + case .checkingPermissions: + checkForPermessions() + case .error, .idle, .noKeyBackups: break } node.reloadData() @@ -131,6 +136,20 @@ extension SetupInitialViewController { handleCommon(error: error) state = .error(error) } + + private func checkForPermessions() { + organisationalRulesPersmissionsService.checkForUsingKeyManager() + .then { [weak self] errorMessage in + guard let errorMessage = errorMessage else { + self?.state = .searching + return + } + + self?.showAlert(message: errorMessage) { + self?.router.signOut() + } + } + } } // MARK: - ASTableDelegate, ASTableDataSource @@ -144,7 +163,7 @@ extension SetupInitialViewController: ASTableDelegate, ASTableDataSource { guard let self = self else { return ASCellNode() } switch self.state { - case .idle: + case .idle, .checkingPermissions: return ASCellNode() case .searching: return self.searchStateNode(for: indexPath) diff --git a/FlowCrypt/Extensions/URLSessionExtension.swift b/FlowCrypt/Extensions/URLSessionExtension.swift index 4ab1fb449..613a60ead 100644 --- a/FlowCrypt/Extensions/URLSessionExtension.swift +++ b/FlowCrypt/Extensions/URLSessionExtension.swift @@ -28,7 +28,8 @@ extension URLSession { let status = res?.statusCode ?? GeneralConstants.Global.generalError let urlMethod = urlRequest.httpMethod ?? "GET" let urlString = urlRequest.url?.absoluteString ?? "??" - let message = "URLSession.call status:\(status) ms:\(trace.finish()) \(urlMethod) \(urlString)" + let headers = urlRequest.allHTTPHeaderFields ?? [:] + let message = "URLSession.call status:\(status) ms:\(trace.finish()) \(urlMethod) \(urlString), headers: \(headers)" Logger.nested("URLSession").logInfo(message) let validStatusCode = 200 ... 299 diff --git a/FlowCrypt/Functionality/Services/GlobalRouter.swift b/FlowCrypt/Functionality/Services/GlobalRouter.swift index c0d2d3709..f7b4274a3 100644 --- a/FlowCrypt/Functionality/Services/GlobalRouter.swift +++ b/FlowCrypt/Functionality/Services/GlobalRouter.swift @@ -11,7 +11,7 @@ import UIKit protocol GlobalRouterType { func proceed() - func signIn(with rout: GlobalRoutingType) + func signIn(with route: GlobalRoutingType) func switchActive(user: User) func signOut() } @@ -71,10 +71,10 @@ extension GlobalRouter { // MARK: - extension GlobalRouter { - func signIn(with rout: GlobalRoutingType) { - logger.logInfo("Sign in with \(rout)") + func signIn(with route: GlobalRoutingType) { + logger.logInfo("Sign in with \(route)") - switch rout { + switch route { case .gmailLogin(let viewController): googleService.signIn(in: viewController) .then(on: .main) { [weak self] session in diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift new file mode 100644 index 000000000..dc6bec3fa --- /dev/null +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift @@ -0,0 +1,47 @@ +// +// OrgRulesSignInPersmissionsService.swift +// FlowCrypt +// +// Created by Yevhen Kyivskyi on 15.07.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Promises + +protocol OrganisationalRulesPersmissionsServiceType { + func checkForUsingKeyManager() -> Promise +} + +class OrganisationalRulesPersmissionsService: OrganisationalRulesPersmissionsServiceType { + + private let organisationalRulesService: OrganisationalRulesServiceType + + init(organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService()) { + self.organisationalRulesService = organisationalRulesService + } + + /// - Returns: Error message if not using key manager + func checkForUsingKeyManager() -> Promise { + Promise { resolve, _ in + let organisationalRules = self.organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() + if organisationalRules.isUsingKeyManager { + resolve(nil) + } + if !organisationalRules.mustAutoImportOrAutogenPrvWithKeyManager { + resolve("organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized) + } + if organisationalRules.mustAutogenPassPhraseQuietly { + resolve("organisational_rules_autogen_passphrase_quitely_error".localized) + } + if !organisationalRules.forbidStoringPassPhrase { + resolve("organisational_rules_forbid_storing_passphrase_error".localized) + } + if organisationalRules.mustSubmitAttester { + resolve("organisational_rules_must_submit_attester_error".localized) + } + if !organisationalRules.canCreateKeys { + resolve("organisational_rules_can_create_keys_error".localized) + } + } + } +} diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift index 3f1d15ee6..231f195c0 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift @@ -6,6 +6,7 @@ // Copyright © 2021 FlowCrypt Limited. All rights reserved. // +import FlowCryptCommon import Foundation import Promises @@ -14,6 +15,8 @@ protocol OrganisationalRulesServiceType { func fetchOrganisationalRules(for email: String) -> Promise func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules + + func getEmailKeyManagerPrivateKeys() -> Promise } final class OrganisationalRulesService { @@ -67,6 +70,32 @@ extension OrganisationalRulesService: OrganisationalRulesServiceType { } } + func getEmailKeyManagerPrivateKeys() -> Promise { + Promise { [weak self] resolve, _ in + guard let self = self else { return } + let organisationalRules = self.getSavedOrganisationalRulesForCurrentUser() + guard let keyManagerUrlString = organisationalRules.keyManagerUrlString else { + resolve(()) + return + } + let urlString = "\(keyManagerUrlString.addTrailingSlashIfNeeded)v1/keys/private" + let headers = [ + URLHeader( + value: "Bearer \(DataService.shared.token ?? "")", + httpHeaderField: "Authorization" + )] + let request = URLRequest.urlRequest( + with: urlString, + method: .get, + body: nil, + headers: headers + ) + + let _ = try? awaitPromise(URLSession.shared.call(request)) + resolve(()) + } + } + func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules { guard let configuration = self.clientConfigurationProvider.fetch() else { assertionFailure("There should not be a user without OrganisationalRules") diff --git a/FlowCrypt/Models/OrganisationalRule.swift b/FlowCrypt/Models/OrganisationalRule.swift index fa8747da1..32111ad51 100644 --- a/FlowCrypt/Models/OrganisationalRule.swift +++ b/FlowCrypt/Models/OrganisationalRule.swift @@ -121,4 +121,12 @@ class OrganisationalRules { var shouldHideArmorMeta: Bool { (clientConfiguration.flags ?? []).contains(.hideArmorMeta) } + + var forbidStoringPassPhrase: Bool { + (clientConfiguration.flags ?? []).contains(.forbidStoringPassphrase) + } + + var keyManagerUrlString: String? { + clientConfiguration.keyManagerUrl + } } diff --git a/FlowCrypt/Resources/en.lproj/Localizable.strings b/FlowCrypt/Resources/en.lproj/Localizable.strings index 81c300f9f..dad5e0ea6 100644 --- a/FlowCrypt/Resources/en.lproj/Localizable.strings +++ b/FlowCrypt/Resources/en.lproj/Localizable.strings @@ -203,3 +203,10 @@ // Organisational rules error "organisational_rules_parse_error_description" = "Couldn't parse data while getting organisational rules"; "organisational_rules_email_format_error_description" = "Wrong user email format"; + +"organisational_rules_autoimport_or_autogen_with_private_key_manager_error" = "Combination of rules (key_manager_url set but PRV_AUTOIMPORT_OR_AUTOGEN is missing) is not supported on this platform"; +"organisational_rules_autogen_passphrase_quitely_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + PASS_PHRASE_QUIET_AUTOGEN) is not supported on this platform"; +"organisational_rules_forbid_storing_passphrase_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + missing FORBID_STORING_PASS_PHRASE) is not supported on this platform"; +"organisational_rules_must_submit_attester_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + ENFORCE_ATTESTER_SUBMIT) is not supported on this platform"; +"organisational_rules_can_create_keys_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + missing NO_PRV_CREATE) is not supported on this platform"; + diff --git a/FlowCryptCommon/Extensions/StringExtensions.swift b/FlowCryptCommon/Extensions/StringExtensions.swift index 15ce79b66..52f448087 100644 --- a/FlowCryptCommon/Extensions/StringExtensions.swift +++ b/FlowCryptCommon/Extensions/StringExtensions.swift @@ -15,7 +15,14 @@ public extension String { } return self } - + + var addTrailingSlashIfNeeded: String { + if self.last != "/" { + return "\(self)/" + } + return self + } + func data() -> Data { data(using: .utf8)! } From 468b346b517bbe650c7443d5961433c9e121893a Mon Sep 17 00:00:00 2001 From: ykyivskyi-gd Date: Fri, 16 Jul 2021 19:08:00 +0300 Subject: [PATCH 2/8] Fixed PR comments; Completed EKMKeys checking; --- FlowCrypt.xcodeproj/project.pbxproj | 12 +++-- .../Setup/SetupInitialViewController.swift | 48 ++++++++++++------- .../Core/Models/DecryptedPrivateKey.swift | 19 ++++++++ .../Services/GoogleUserService.swift | 6 +++ .../ClientConfigurationService.swift | 46 ++++++++++++++++++ ...ganisationalRulesPersmissionsService.swift | 47 ------------------ .../OrganisationalRulesService.swift | 22 +++++---- FlowCrypt/Models/OrganisationalRule.swift | 3 +- .../Resources/en.lproj/Localizable.strings | 1 + 9 files changed, 124 insertions(+), 80 deletions(-) create mode 100644 FlowCrypt/Core/Models/DecryptedPrivateKey.swift create mode 100644 FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift delete mode 100644 FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index 2932df3eb..2346a5144 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -11,7 +11,8 @@ 04B472951ECE29F600B8266F /* MyMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04B472921ECE29F600B8266F /* MyMenuViewController.swift */; }; 04B472961ECE29F600B8266F /* SideMenuNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04B472931ECE29F600B8266F /* SideMenuNavigationController.swift */; }; 211392A5266511E6009202EC /* PubLookup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 211392A4266511E6009202EC /* PubLookup.swift */; }; - 2133D51626A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2133D51526A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift */; }; + 2133D51626A0571F00CC686F /* ClientConfigurationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2133D51526A0571F00CC686F /* ClientConfigurationService.swift */; }; + 2133D51826A1E45400CC686F /* DecryptedPrivateKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2133D51726A1E45300CC686F /* DecryptedPrivateKey.swift */; }; 21489B78267CB42400BDE4AC /* ClientConfigurationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */; }; 21489B7A267CB4DF00BDE4AC /* ClientConfigurationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B79267CB4DF00BDE4AC /* ClientConfigurationObject.swift */; }; 21489B7C267CBA0E00BDE4AC /* ClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B7B267CBA0E00BDE4AC /* ClientConfiguration.swift */; }; @@ -366,7 +367,8 @@ 113F04B20ECC35FC59A81A6C /* Pods-FlowCryptTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlowCryptTests.release.xcconfig"; path = "Target Support Files/Pods-FlowCryptTests/Pods-FlowCryptTests.release.xcconfig"; sourceTree = ""; }; 11C1375F41411882DC4C9431 /* Pods-FlowCryptUIApplication.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlowCryptUIApplication.release.xcconfig"; path = "Target Support Files/Pods-FlowCryptUIApplication/Pods-FlowCryptUIApplication.release.xcconfig"; sourceTree = ""; }; 211392A4266511E6009202EC /* PubLookup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PubLookup.swift; sourceTree = ""; }; - 2133D51526A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRulesPersmissionsService.swift; sourceTree = ""; }; + 2133D51526A0571F00CC686F /* ClientConfigurationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationService.swift; sourceTree = ""; }; + 2133D51726A1E45300CC686F /* DecryptedPrivateKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecryptedPrivateKey.swift; sourceTree = ""; }; 21489B6A267B7BD800BDE4AC /* FilesManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesManagerTests.swift; sourceTree = ""; }; 21489B6D267B7D5000BDE4AC /* FileMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMock.swift; sourceTree = ""; }; 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationProvider.swift; sourceTree = ""; }; @@ -793,7 +795,7 @@ 21489B81267CC3BC00BDE4AC /* Organisational Rules Service */ = { isa = PBXGroup; children = ( - 2133D51526A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift */, + 2133D51526A0571F00CC686F /* ClientConfigurationService.swift */, 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */, 21489B7F267CC39E00BDE4AC /* OrganisationalRulesService.swift */, 21489B82267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift */, @@ -1565,6 +1567,7 @@ D212D35C24C1AACF00035991 /* PrvKeyInfo.swift */, D2E26F6B24F25B1F00612AF1 /* KeyAlgo.swift */, 9FC7EAB2266A404D00F3BF5D /* PassPhraseObject.swift */, + 2133D51726A1E45300CC686F /* DecryptedPrivateKey.swift */, ); path = Models; sourceTree = ""; @@ -2464,7 +2467,7 @@ D2F6D147243506DA00DB4065 /* MailSettingsCredentials.swift in Sources */, 9F9361A52573CE260009912F /* MessageProvider.swift in Sources */, 32DCA2BB910FA1B19BA8B328 /* Imap.swift in Sources */, - 2133D51626A0571F00CC686F /* OrganisationalRulesPersmissionsService.swift in Sources */, + 2133D51626A0571F00CC686F /* ClientConfigurationService.swift in Sources */, D274724424FD1932006BA6EF /* FolderObject.swift in Sources */, 9FE1B3802563F85400D6D086 /* MessagesListProvider.swift in Sources */, 32DCA1B95DDC04D671F662F8 /* URLSessionExtension.swift in Sources */, @@ -2531,6 +2534,7 @@ 9F9362192573D10E0009912F /* Imap+Message.swift in Sources */, 32DCA9C61ABB3234649B374E /* CoreHost.swift in Sources */, 9F41FA28253B75F4003B970D /* BackupSelectKeyViewController.swift in Sources */, + 2133D51826A1E45400CC686F /* DecryptedPrivateKey.swift in Sources */, 21489B83267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift in Sources */, D2F6D1402435008500DB4065 /* SessionCredentialsProvider.swift in Sources */, 9F9ABC8723AC1EAA00D560E3 /* MessageContext.swift in Sources */, diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index 0446cb758..4b4a648b5 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -23,12 +23,12 @@ final class SetupInitialViewController: TableNodeViewController { } private enum State { - case idle, checkingPermissions, searching, noKeyBackups, error(Error) + case idle, checkingClientConfigurationIntegrity, checkingEKMKeys, searching, noKeyBackups, error(Error) var numberOfRows: Int { switch self { // title - case .idle, .checkingPermissions: + case .idle, .checkingClientConfigurationIntegrity, .checkingEKMKeys: return 1 // title, loading case .searching: @@ -54,7 +54,8 @@ final class SetupInitialViewController: TableNodeViewController { private let router: GlobalRouterType private let decorator: SetupViewDecorator private let organisationalRules: OrganisationalRules - private let organisationalRulesPersmissionsService: OrganisationalRulesPersmissionsServiceType + private let organisationalRulesService: OrganisationalRulesServiceType + private let clientConfigurationService: ClientConfigurationServiceType private lazy var logger = Logger.nested(in: Self.self, with: .setup) @@ -64,14 +65,15 @@ final class SetupInitialViewController: TableNodeViewController { router: GlobalRouterType = GlobalRouter(), decorator: SetupViewDecorator = SetupViewDecorator(), organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService(), - organisationalRulesPermissionsService: OrganisationalRulesPersmissionsServiceType = OrganisationalRulesPersmissionsService() + clientConfigurationService: ClientConfigurationServiceType = ClientConfigurationService() ) { self.user = user self.backupService = backupService self.router = router self.decorator = decorator self.organisationalRules = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() - self.organisationalRulesPersmissionsService = organisationalRulesPermissionsService + self.organisationalRulesService = organisationalRulesService + self.clientConfigurationService = clientConfigurationService super.init(node: TableNode()) } @@ -89,7 +91,7 @@ final class SetupInitialViewController: TableNodeViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setNeedsStatusBarAppearanceUpdate() - state = .checkingPermissions + state = .checkingClientConfigurationIntegrity } } @@ -102,8 +104,10 @@ extension SetupInitialViewController { switch state { case .searching: searchBackups() - case .checkingPermissions: - checkForPermessions() + case .checkingClientConfigurationIntegrity: + checkClientConfigurationIntegrity() + case .checkingEKMKeys: + checkEKMKeys() case .error, .idle, .noKeyBackups: break } @@ -137,17 +141,25 @@ extension SetupInitialViewController { state = .error(error) } - private func checkForPermessions() { - organisationalRulesPersmissionsService.checkForUsingKeyManager() - .then { [weak self] errorMessage in - guard let errorMessage = errorMessage else { - self?.state = .searching - return - } + private func checkClientConfigurationIntegrity() { + guard let integrityErrorMessage = clientConfigurationService.checkForUsingKeyManager() else { + state = .checkingEKMKeys + return + } + showAlert(message: integrityErrorMessage) { [weak self] in + self?.router.signOut() + } + } - self?.showAlert(message: errorMessage) { - self?.router.signOut() + private func checkEKMKeys() { + organisationalRulesService.getEmailKeyManagerPrivateKeys() + .then { [weak self] result in + if result.keys.isNotEmpty { + self?.showToast( + "organisational_rules_ekm_private_keys_message".localizeWithArguments(result.keys.count, result.urlString ?? "") + ) } + self?.state = .searching } } } @@ -163,7 +175,7 @@ extension SetupInitialViewController: ASTableDelegate, ASTableDataSource { guard let self = self else { return ASCellNode() } switch self.state { - case .idle, .checkingPermissions: + case .idle, .checkingClientConfigurationIntegrity, .checkingEKMKeys: return ASCellNode() case .searching: return self.searchStateNode(for: indexPath) diff --git a/FlowCrypt/Core/Models/DecryptedPrivateKey.swift b/FlowCrypt/Core/Models/DecryptedPrivateKey.swift new file mode 100644 index 000000000..1ebe68ef3 --- /dev/null +++ b/FlowCrypt/Core/Models/DecryptedPrivateKey.swift @@ -0,0 +1,19 @@ +// +// DecryptedPrivateKey.swift +// FlowCrypt +// +// Created by Yevhen Kyivskyi on 16.07.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Foundation + +struct DecryptedPrivateKeysContainer: Decodable { + + let privateKeys: [DecryptedPrivateKey] +} + +struct DecryptedPrivateKey: Decodable { + + let decryptedPrivateKey: String +} diff --git a/FlowCrypt/Functionality/Services/GoogleUserService.swift b/FlowCrypt/Functionality/Services/GoogleUserService.swift index cc9ef413a..b1db5ba6d 100644 --- a/FlowCrypt/Functionality/Services/GoogleUserService.swift +++ b/FlowCrypt/Functionality/Services/GoogleUserService.swift @@ -48,6 +48,12 @@ final class GoogleUserService: NSObject, GoogleUserServiceType { .accessToken } + var idToken: String? { + authorization?.authState + .lastTokenResponse? + .idToken + } + var authorization: GTMAppAuthFetcherAuthorization? { getAuthorizationForCurrentUser() } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift new file mode 100644 index 000000000..602593cd3 --- /dev/null +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift @@ -0,0 +1,46 @@ +// +// OrgRulesSignInPersmissionsService.swift +// FlowCrypt +// +// Created by Yevhen Kyivskyi on 15.07.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Promises + +protocol ClientConfigurationServiceType { + func checkForUsingKeyManager() -> String? +} + +class ClientConfigurationService: ClientConfigurationServiceType { + + private let organisationalRulesService: OrganisationalRulesServiceType + + init(organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService()) { + self.organisationalRulesService = organisationalRulesService + } + + /// - Returns: Error message if not using key manager, returns nil if using key manager + func checkForUsingKeyManager() -> String? { + let organisationalRules = self.organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() + if organisationalRules.isUsingKeyManager { + return nil + } + if !organisationalRules.mustAutoImportOrAutogenPrvWithKeyManager { + return "organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized + } + if organisationalRules.mustAutogenPassPhraseQuietly { + return "organisational_rules_autogen_passphrase_quitely_error".localized + } + if !organisationalRules.forbidStoringPassPhrase { + return "organisational_rules_forbid_storing_passphrase_error".localized + } + if organisationalRules.mustSubmitAttester { + return "organisational_rules_must_submit_attester_error".localized + } + if !organisationalRules.canCreateKeys { + return "organisational_rules_can_create_keys_error".localized + } + return nil + } +} diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift deleted file mode 100644 index dc6bec3fa..000000000 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesPersmissionsService.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// OrgRulesSignInPersmissionsService.swift -// FlowCrypt -// -// Created by Yevhen Kyivskyi on 15.07.2021. -// Copyright © 2021 FlowCrypt Limited. All rights reserved. -// - -import Promises - -protocol OrganisationalRulesPersmissionsServiceType { - func checkForUsingKeyManager() -> Promise -} - -class OrganisationalRulesPersmissionsService: OrganisationalRulesPersmissionsServiceType { - - private let organisationalRulesService: OrganisationalRulesServiceType - - init(organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService()) { - self.organisationalRulesService = organisationalRulesService - } - - /// - Returns: Error message if not using key manager - func checkForUsingKeyManager() -> Promise { - Promise { resolve, _ in - let organisationalRules = self.organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() - if organisationalRules.isUsingKeyManager { - resolve(nil) - } - if !organisationalRules.mustAutoImportOrAutogenPrvWithKeyManager { - resolve("organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized) - } - if organisationalRules.mustAutogenPassPhraseQuietly { - resolve("organisational_rules_autogen_passphrase_quitely_error".localized) - } - if !organisationalRules.forbidStoringPassPhrase { - resolve("organisational_rules_forbid_storing_passphrase_error".localized) - } - if organisationalRules.mustSubmitAttester { - resolve("organisational_rules_must_submit_attester_error".localized) - } - if !organisationalRules.canCreateKeys { - resolve("organisational_rules_can_create_keys_error".localized) - } - } - } -} diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift index 231f195c0..03b790652 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift @@ -16,11 +16,13 @@ protocol OrganisationalRulesServiceType { func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules - func getEmailKeyManagerPrivateKeys() -> Promise + func getEmailKeyManagerPrivateKeys() -> Promise } final class OrganisationalRulesService { + typealias GetEKMKeysResult = (keys: [DecryptedPrivateKey], urlString: String?) + private let enterpriseServerApi: EnterpriseServerApiType private let clientConfigurationProvider: ClientConfigurationProviderType @@ -70,18 +72,18 @@ extension OrganisationalRulesService: OrganisationalRulesServiceType { } } - func getEmailKeyManagerPrivateKeys() -> Promise { - Promise { [weak self] resolve, _ in - guard let self = self else { return } + func getEmailKeyManagerPrivateKeys() -> Promise { + Promise { [weak self] resolve, _ in + guard let self = self else { throw AppErr.nilSelf } let organisationalRules = self.getSavedOrganisationalRulesForCurrentUser() guard let keyManagerUrlString = organisationalRules.keyManagerUrlString else { - resolve(()) + resolve(([], nil)) return } - let urlString = "\(keyManagerUrlString.addTrailingSlashIfNeeded)v1/keys/private" + let urlString = "\(keyManagerUrlString)v1/keys/private" let headers = [ URLHeader( - value: "Bearer \(DataService.shared.token ?? "")", + value: "Bearer \(GoogleUserService().idToken ?? "")", httpHeaderField: "Authorization" )] let request = URLRequest.urlRequest( @@ -90,9 +92,9 @@ extension OrganisationalRulesService: OrganisationalRulesServiceType { body: nil, headers: headers ) - - let _ = try? awaitPromise(URLSession.shared.call(request)) - resolve(()) + let response = try awaitPromise(URLSession.shared.call(request)) + let container = try JSONDecoder().decode(DecryptedPrivateKeysContainer.self, from: response.data) + resolve((container.privateKeys, urlString)) } } diff --git a/FlowCrypt/Models/OrganisationalRule.swift b/FlowCrypt/Models/OrganisationalRule.swift index 32111ad51..cd3565078 100644 --- a/FlowCrypt/Models/OrganisationalRule.swift +++ b/FlowCrypt/Models/OrganisationalRule.swift @@ -6,6 +6,7 @@ // Copyright © 2021 FlowCrypt Limited. All rights reserved. // +import FlowCryptCommon import Foundation /// Organisational rules, set domain-wide, and delivered from FlowCrypt Backend @@ -127,6 +128,6 @@ class OrganisationalRules { } var keyManagerUrlString: String? { - clientConfiguration.keyManagerUrl + clientConfiguration.keyManagerUrl?.addTrailingSlashIfNeeded } } diff --git a/FlowCrypt/Resources/en.lproj/Localizable.strings b/FlowCrypt/Resources/en.lproj/Localizable.strings index dad5e0ea6..10af62f2f 100644 --- a/FlowCrypt/Resources/en.lproj/Localizable.strings +++ b/FlowCrypt/Resources/en.lproj/Localizable.strings @@ -209,4 +209,5 @@ "organisational_rules_forbid_storing_passphrase_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + missing FORBID_STORING_PASS_PHRASE) is not supported on this platform"; "organisational_rules_must_submit_attester_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + ENFORCE_ATTESTER_SUBMIT) is not supported on this platform"; "organisational_rules_can_create_keys_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + missing NO_PRV_CREATE) is not supported on this platform"; +"organisational_rules_ekm_private_keys_message" = "Ignoring %d keys returned by EKM %@ (not implemented)"; From 9fa55e92aca77c8cfa79f431266924458c713bf1 Mon Sep 17 00:00:00 2001 From: ykyivskyi-gd Date: Fri, 16 Jul 2021 19:09:17 +0300 Subject: [PATCH 3/8] Removed Promises import in ClientConfigService --- .../ClientConfigurationService.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift index 602593cd3..7b73bb7b8 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift @@ -6,8 +6,6 @@ // Copyright © 2021 FlowCrypt Limited. All rights reserved. // -import Promises - protocol ClientConfigurationServiceType { func checkForUsingKeyManager() -> String? } From 69e682ec80f07467c8eced5a47086697ae39f10d Mon Sep 17 00:00:00 2001 From: ykyivskyi-gd Date: Sat, 17 Jul 2021 15:38:37 +0300 Subject: [PATCH 4/8] Fixed PR comments; --- FlowCrypt.xcodeproj/project.pbxproj | 4 ++ .../Setup/SetupInitialViewController.swift | 21 ++++--- .../Core/Models/DecryptedPrivateKey.swift | 4 +- .../Services/EmailKeyManagerApi.swift | 55 +++++++++++++++++++ .../OrganisationalRulesService.swift | 30 ---------- 5 files changed, 75 insertions(+), 39 deletions(-) create mode 100644 FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index 2346a5144..4793c73b7 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 21489B7C267CBA0E00BDE4AC /* ClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B7B267CBA0E00BDE4AC /* ClientConfiguration.swift */; }; 21489B80267CC39E00BDE4AC /* OrganisationalRulesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B7F267CC39E00BDE4AC /* OrganisationalRulesService.swift */; }; 21489B83267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B82267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift */; }; + 214A023A26A3029700C24066 /* EmailKeyManagerApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214A023926A3029700C24066 /* EmailKeyManagerApi.swift */; }; 215002A32690B1DD00980DDD /* client_configuraion_with_unknown_flag.json in Resources */ = {isa = PBXBuildFile; fileRef = 215002A22690B1DD00980DDD /* client_configuraion_with_unknown_flag.json */; }; 215897E8267A553300423694 /* FilesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 215897E7267A553200423694 /* FilesManager.swift */; }; 2196A2202684B9BE001B9E00 /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2196A21F2684B9BE001B9E00 /* URLExtension.swift */; }; @@ -376,6 +377,7 @@ 21489B7B267CBA0E00BDE4AC /* ClientConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfiguration.swift; sourceTree = ""; }; 21489B7F267CC39E00BDE4AC /* OrganisationalRulesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRulesService.swift; sourceTree = ""; }; 21489B82267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRulesServiceError.swift; sourceTree = ""; }; + 214A023926A3029700C24066 /* EmailKeyManagerApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailKeyManagerApi.swift; sourceTree = ""; }; 215002A22690B1DD00980DDD /* client_configuraion_with_unknown_flag.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion_with_unknown_flag.json; sourceTree = ""; }; 215897E7267A553200423694 /* FilesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesManager.swift; sourceTree = ""; }; 2196A21F2684B9BE001B9E00 /* URLExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = ""; }; @@ -997,6 +999,7 @@ 32DCAC9C0512037018F434A1 /* BackendApi.swift */, 21EFF61E265A5C6700AB0B71 /* WKDURLsApi.swift */, 21C7DF08266C0D8F00C44800 /* EnterpriseServerApi.swift */, + 214A023926A3029700C24066 /* EmailKeyManagerApi.swift */, D274724024F97C5C006BA6EF /* CacheService.swift */, C132B9CA1EC2DE6400763715 /* GeneralConstants.swift */, 9FB22CFD25715DDF0026EE64 /* Key Services */, @@ -2471,6 +2474,7 @@ D274724424FD1932006BA6EF /* FolderObject.swift in Sources */, 9FE1B3802563F85400D6D086 /* MessagesListProvider.swift in Sources */, 32DCA1B95DDC04D671F662F8 /* URLSessionExtension.swift in Sources */, + 214A023A26A3029700C24066 /* EmailKeyManagerApi.swift in Sources */, D2E26F7424F2705B00612AF1 /* ContactDetailDecorator.swift in Sources */, 21C7DF0526697DA500C44800 /* PromiseKitExtension.swift in Sources */, 9F7E8F19269C538E0021C07F /* NavigationChildController.swift in Sources */, diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index 4b4a648b5..993d210fc 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -54,7 +54,7 @@ final class SetupInitialViewController: TableNodeViewController { private let router: GlobalRouterType private let decorator: SetupViewDecorator private let organisationalRules: OrganisationalRules - private let organisationalRulesService: OrganisationalRulesServiceType + private let emailKeyManagerApi: EmailKeyManagerApiType private let clientConfigurationService: ClientConfigurationServiceType private lazy var logger = Logger.nested(in: Self.self, with: .setup) @@ -65,6 +65,7 @@ final class SetupInitialViewController: TableNodeViewController { router: GlobalRouterType = GlobalRouter(), decorator: SetupViewDecorator = SetupViewDecorator(), organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService(), + emailKeyManagerApi: EmailKeyManagerApiType = EmailKeyManagerApi(), clientConfigurationService: ClientConfigurationServiceType = ClientConfigurationService() ) { self.user = user @@ -72,7 +73,7 @@ final class SetupInitialViewController: TableNodeViewController { self.router = router self.decorator = decorator self.organisationalRules = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() - self.organisationalRulesService = organisationalRulesService + self.emailKeyManagerApi = emailKeyManagerApi self.clientConfigurationService = clientConfigurationService super.init(node: TableNode()) @@ -152,14 +153,18 @@ extension SetupInitialViewController { } private func checkEKMKeys() { - organisationalRulesService.getEmailKeyManagerPrivateKeys() + emailKeyManagerApi.getPrivateKeys() .then { [weak self] result in - if result.keys.isNotEmpty { - self?.showToast( - "organisational_rules_ekm_private_keys_message".localizeWithArguments(result.keys.count, result.urlString ?? "") - ) - } + let urlString = self?.emailKeyManagerApi.getPrivateKeysUrlString() ?? "" + self?.showToast( + "organisational_rules_ekm_private_keys_message".localizeWithArguments(result.privateKeys.count, urlString) + ) + self?.state = .searching + }.catch { [weak self] error in + self?.showAlert(message: error.localizedDescription, onOk: { + self?.state = .checkingClientConfigurationIntegrity + }) } } } diff --git a/FlowCrypt/Core/Models/DecryptedPrivateKey.swift b/FlowCrypt/Core/Models/DecryptedPrivateKey.swift index 1ebe68ef3..0eba131f6 100644 --- a/FlowCrypt/Core/Models/DecryptedPrivateKey.swift +++ b/FlowCrypt/Core/Models/DecryptedPrivateKey.swift @@ -8,9 +8,11 @@ import Foundation -struct DecryptedPrivateKeysContainer: Decodable { +struct DecryptedPrivateKeysResponse: Decodable { let privateKeys: [DecryptedPrivateKey] + + static let empty = DecryptedPrivateKeysResponse(privateKeys: []) } struct DecryptedPrivateKey: Decodable { diff --git a/FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift b/FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift new file mode 100644 index 000000000..07db6bd1b --- /dev/null +++ b/FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift @@ -0,0 +1,55 @@ +// +// EmailKeyManagerApi.swift +// FlowCrypt +// +// Created by Yevhen Kyivskyi on 17.07.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Promises + +protocol EmailKeyManagerApiType { + + func getPrivateKeysUrlString() -> String? + func getPrivateKeys() -> Promise +} + +class EmailKeyManagerApi: EmailKeyManagerApiType { + + private let organisationalRulesService: OrganisationalRulesServiceType + + init(organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService()) { + self.organisationalRulesService = organisationalRulesService + } + + func getPrivateKeysUrlString() -> String? { + guard let keyManagerUrlString = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser().keyManagerUrlString else { + return nil + } + return "\(keyManagerUrlString)v1/keys/private" + } + + func getPrivateKeys() -> Promise { + Promise { [weak self] resolve, _ in + guard let self = self else { throw AppErr.nilSelf } + guard let urlString = self.getPrivateKeysUrlString() else { + resolve(.empty) + return + } + let headers = [ + URLHeader( + value: "Bearer \(GoogleUserService().idToken ?? "")", + httpHeaderField: "Authorization" + )] + let request = URLRequest.urlRequest( + with: urlString, + method: .get, + body: nil, + headers: headers + ) + let response = try awaitPromise(URLSession.shared.call(request)) + let decryptedPrivateKeysResponse = try JSONDecoder().decode(DecryptedPrivateKeysResponse.self, from: response.data) + resolve(decryptedPrivateKeysResponse) + } + } +} diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift index 03b790652..6bbfbd263 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift @@ -15,14 +15,10 @@ protocol OrganisationalRulesServiceType { func fetchOrganisationalRules(for email: String) -> Promise func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules - - func getEmailKeyManagerPrivateKeys() -> Promise } final class OrganisationalRulesService { - typealias GetEKMKeysResult = (keys: [DecryptedPrivateKey], urlString: String?) - private let enterpriseServerApi: EnterpriseServerApiType private let clientConfigurationProvider: ClientConfigurationProviderType @@ -72,32 +68,6 @@ extension OrganisationalRulesService: OrganisationalRulesServiceType { } } - func getEmailKeyManagerPrivateKeys() -> Promise { - Promise { [weak self] resolve, _ in - guard let self = self else { throw AppErr.nilSelf } - let organisationalRules = self.getSavedOrganisationalRulesForCurrentUser() - guard let keyManagerUrlString = organisationalRules.keyManagerUrlString else { - resolve(([], nil)) - return - } - let urlString = "\(keyManagerUrlString)v1/keys/private" - let headers = [ - URLHeader( - value: "Bearer \(GoogleUserService().idToken ?? "")", - httpHeaderField: "Authorization" - )] - let request = URLRequest.urlRequest( - with: urlString, - method: .get, - body: nil, - headers: headers - ) - let response = try awaitPromise(URLSession.shared.call(request)) - let container = try JSONDecoder().decode(DecryptedPrivateKeysContainer.self, from: response.data) - resolve((container.privateKeys, urlString)) - } - } - func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules { guard let configuration = self.clientConfigurationProvider.fetch() else { assertionFailure("There should not be a user without OrganisationalRules") From f4bfd9142c7b2e4b978d4877a47971c5b4a309a9 Mon Sep 17 00:00:00 2001 From: ykyivskyi-gd Date: Mon, 19 Jul 2021 23:04:36 +0300 Subject: [PATCH 5/8] Added error handling for EmailKeyManagerApi; --- .../Setup/SetupInitialViewController.swift | 10 ++++++-- .../Functionality/Services/AttesterApi.swift | 2 +- .../Services/EmailKeyManagerApi.swift | 25 ++++++++++++++++--- .../Resources/en.lproj/Localizable.strings | 2 ++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index 993d210fc..0996ca46b 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -155,13 +155,19 @@ extension SetupInitialViewController { private func checkEKMKeys() { emailKeyManagerApi.getPrivateKeys() .then { [weak self] result in - let urlString = self?.emailKeyManagerApi.getPrivateKeysUrlString() ?? "" + guard let urlString = self?.emailKeyManagerApi.getPrivateKeysUrlString() else { + fatalError("Private keys URL can not be nil at this point") + } self?.showToast( "organisational_rules_ekm_private_keys_message".localizeWithArguments(result.privateKeys.count, urlString) ) self?.state = .searching - }.catch { [weak self] error in + } + .catch { [weak self] error in + if case .noPrivateKeysUrlString = error as? EmailKeyManagerApiError { + return + } self?.showAlert(message: error.localizedDescription, onOk: { self?.state = .checkingClientConfigurationIntegrity }) diff --git a/FlowCrypt/Functionality/Services/AttesterApi.swift b/FlowCrypt/Functionality/Services/AttesterApi.swift index aed3cbac0..3a0ab9e02 100644 --- a/FlowCrypt/Functionality/Services/AttesterApi.swift +++ b/FlowCrypt/Functionality/Services/AttesterApi.swift @@ -70,7 +70,7 @@ extension AttesterApi { if let value = token { httpMethod = .post - headers = [URLHeader(value: "Authorization", httpHeaderField: "Bearer \(value)")] + headers = [URLHeader(value: "Bearer \(value)", httpHeaderField: "Authorization")] } else { httpMethod = .put headers = [] diff --git a/FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift b/FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift index 07db6bd1b..62ad54b4b 100644 --- a/FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift +++ b/FlowCrypt/Functionality/Services/EmailKeyManagerApi.swift @@ -14,6 +14,19 @@ protocol EmailKeyManagerApiType { func getPrivateKeys() -> Promise } +enum EmailKeyManagerApiError: Error { + case noGoogleIdToken + case noPrivateKeysUrlString +} +extension EmailKeyManagerApiError: LocalizedError { + var errorDescription: String? { + switch self { + case .noGoogleIdToken: return "emai_keymanager_api_no_google_id_token_error_description".localized + case .noPrivateKeysUrlString: return "" + } + } +} + class EmailKeyManagerApi: EmailKeyManagerApiType { private let organisationalRulesService: OrganisationalRulesServiceType @@ -30,15 +43,21 @@ class EmailKeyManagerApi: EmailKeyManagerApiType { } func getPrivateKeys() -> Promise { - Promise { [weak self] resolve, _ in + Promise { [weak self] resolve, reject in guard let self = self else { throw AppErr.nilSelf } guard let urlString = self.getPrivateKeysUrlString() else { - resolve(.empty) + reject(EmailKeyManagerApiError.noPrivateKeysUrlString) return } + + guard let idToken = GoogleUserService().idToken else { + reject(EmailKeyManagerApiError.noGoogleIdToken) + return + } + let headers = [ URLHeader( - value: "Bearer \(GoogleUserService().idToken ?? "")", + value: "Bearer \(idToken)", httpHeaderField: "Authorization" )] let request = URLRequest.urlRequest( diff --git a/FlowCrypt/Resources/en.lproj/Localizable.strings b/FlowCrypt/Resources/en.lproj/Localizable.strings index 10af62f2f..ac45a9037 100644 --- a/FlowCrypt/Resources/en.lproj/Localizable.strings +++ b/FlowCrypt/Resources/en.lproj/Localizable.strings @@ -211,3 +211,5 @@ "organisational_rules_can_create_keys_error" = "Combination of rules (PRV_AUTOIMPORT_OR_AUTOGEN + missing NO_PRV_CREATE) is not supported on this platform"; "organisational_rules_ekm_private_keys_message" = "Ignoring %d keys returned by EKM %@ (not implemented)"; +// Email key manager api error +"emai_keymanager_api_no_google_id_token_error_description" = "There is no Google ID token were found while getting client configuration"; From 424635967c6ee13bbb6953b2c537fdb7582dcc98 Mon Sep 17 00:00:00 2001 From: ykyivskyi-gd Date: Thu, 22 Jul 2021 22:48:33 +0300 Subject: [PATCH 6/8] Fixed checking client configuration integrity; --- FlowCrypt.xcodeproj/project.pbxproj | 4 +++ .../Setup/SetupInitialViewController.swift | 15 +++++++---- .../ClientConfigurationService.swift | 26 +++++++++---------- .../ClientConfigurationServiceResults.swift | 17 ++++++++++++ 4 files changed, 44 insertions(+), 18 deletions(-) create mode 100644 FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index c28070e21..89a7abfc6 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 215002A32690B1DD00980DDD /* client_configuraion_with_unknown_flag.json in Resources */ = {isa = PBXBuildFile; fileRef = 215002A22690B1DD00980DDD /* client_configuraion_with_unknown_flag.json */; }; 215897E8267A553300423694 /* FilesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 215897E7267A553200423694 /* FilesManager.swift */; }; 2196A2202684B9BE001B9E00 /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2196A21F2684B9BE001B9E00 /* URLExtension.swift */; }; + 21B15C9426AA00A400D8522B /* ClientConfigurationServiceResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21B15C9326AA00A400D8522B /* ClientConfigurationServiceResults.swift */; }; 21C7DEFC26669A3700C44800 /* CalendarExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21C7DEFB26669A3700C44800 /* CalendarExtension.swift */; }; 21C7DEFE26669CE100C44800 /* DateFormattingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56BD3723438C7000A7371A /* DateFormattingExtensions.swift */; }; 21C7DF0526697DA500C44800 /* PromiseKitExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21C7DF0426697DA500C44800 /* PromiseKitExtension.swift */; }; @@ -383,6 +384,7 @@ 215002A22690B1DD00980DDD /* client_configuraion_with_unknown_flag.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion_with_unknown_flag.json; sourceTree = ""; }; 215897E7267A553200423694 /* FilesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesManager.swift; sourceTree = ""; }; 2196A21F2684B9BE001B9E00 /* URLExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = ""; }; + 21B15C9326AA00A400D8522B /* ClientConfigurationServiceResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationServiceResults.swift; sourceTree = ""; }; 21C7DEFB26669A3700C44800 /* CalendarExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarExtension.swift; sourceTree = ""; }; 21C7DF0426697DA500C44800 /* PromiseKitExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PromiseKitExtension.swift; sourceTree = ""; }; 21C7DF08266C0D8F00C44800 /* EnterpriseServerApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterpriseServerApi.swift; sourceTree = ""; }; @@ -805,6 +807,7 @@ 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */, 21489B7F267CC39E00BDE4AC /* OrganisationalRulesService.swift */, 21489B82267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift */, + 21B15C9326AA00A400D8522B /* ClientConfigurationServiceResults.swift */, ); path = "Organisational Rules Service"; sourceTree = ""; @@ -2496,6 +2499,7 @@ 32DCA2BB910FA1B19BA8B328 /* Imap.swift in Sources */, 2133D51626A0571F00CC686F /* ClientConfigurationService.swift in Sources */, D274724424FD1932006BA6EF /* FolderObject.swift in Sources */, + 21B15C9426AA00A400D8522B /* ClientConfigurationServiceResults.swift in Sources */, 9FE1B3802563F85400D6D086 /* MessagesListProvider.swift in Sources */, 32DCA1B95DDC04D671F662F8 /* URLSessionExtension.swift in Sources */, 214A023A26A3029700C24066 /* EmailKeyManagerApi.swift in Sources */, diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index 0996ca46b..1c285718c 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -143,12 +143,17 @@ extension SetupInitialViewController { } private func checkClientConfigurationIntegrity() { - guard let integrityErrorMessage = clientConfigurationService.checkForUsingKeyManager() else { + let checkForUsingKeyManagerResult = clientConfigurationService.checkForUsingKeyManager() + + switch checkForUsingKeyManagerResult { + case .useKeyManager: state = .checkingEKMKeys - return - } - showAlert(message: integrityErrorMessage) { [weak self] in - self?.router.signOut() + case .skip: + state = .searching + case .error(let message): + showAlert(message: message) { [weak self] in + self?.router.signOut() + } } } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift index 7b73bb7b8..cce4a50bc 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift @@ -7,7 +7,7 @@ // protocol ClientConfigurationServiceType { - func checkForUsingKeyManager() -> String? + func checkForUsingKeyManager() -> ClientConfigurationService.CheckForUsingEKMResult } class ClientConfigurationService: ClientConfigurationServiceType { @@ -17,28 +17,28 @@ class ClientConfigurationService: ClientConfigurationServiceType { init(organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService()) { self.organisationalRulesService = organisationalRulesService } - + /// There are in fact three states: + /// EKM is in use because organisationalRules.isUsingKeyManager == true and other OrgRules are consistent with it (result: no error, use EKM) + /// EKM is in use because organisationalRules.isUsingKeyManager == true and other OrgRules are NOT consistent with it (result: error) + /// EKM is not in use because organisationalRules.isUsingKeyManager == false (result: normal login flow) /// - Returns: Error message if not using key manager, returns nil if using key manager - func checkForUsingKeyManager() -> String? { + func checkForUsingKeyManager() -> CheckForUsingEKMResult { let organisationalRules = self.organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() - if organisationalRules.isUsingKeyManager { - return nil + if !organisationalRules.isUsingKeyManager { + return .skip } if !organisationalRules.mustAutoImportOrAutogenPrvWithKeyManager { - return "organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized + return .error(message: "organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized) } if organisationalRules.mustAutogenPassPhraseQuietly { - return "organisational_rules_autogen_passphrase_quitely_error".localized + return .error(message: "organisational_rules_autogen_passphrase_quitely_error".localized) } if !organisationalRules.forbidStoringPassPhrase { - return "organisational_rules_forbid_storing_passphrase_error".localized + return .error(message: "organisational_rules_forbid_storing_passphrase_error".localized) } if organisationalRules.mustSubmitAttester { - return "organisational_rules_must_submit_attester_error".localized - } - if !organisationalRules.canCreateKeys { - return "organisational_rules_can_create_keys_error".localized + return .error(message: "organisational_rules_must_submit_attester_error".localized) } - return nil + return .useKeyManager } } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift new file mode 100644 index 000000000..94c3bb1e5 --- /dev/null +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift @@ -0,0 +1,17 @@ +// +// ClientConfigurationServiceResults.swift +// FlowCrypt +// +// Created by Yevhen Kyivskyi on 22.07.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Foundation + +extension ClientConfigurationService { + enum CheckForUsingEKMResult { + case useKeyManager + case error(message: String) + case skip + } +} From df2aedb762d8240732c2758fec928a36ccd79ad2 Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 23 Jul 2021 20:09:59 +0800 Subject: [PATCH 7/8] rename methods and states, add comment --- .../Setup/SetupInitialViewController.swift | 67 +++++++++---------- .../NavigationChildController.swift | 2 +- .../ClientConfigurationService.swift | 29 ++++---- .../ClientConfigurationServiceResults.swift | 6 +- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index 1c285718c..a6197c83b 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -23,19 +23,19 @@ final class SetupInitialViewController: TableNodeViewController { } private enum State { - case idle, checkingClientConfigurationIntegrity, checkingEKMKeys, searching, noKeyBackups, error(Error) + case idle, decidingIfEKMshouldBeUsed, fetchingKeysFromEKM, searchingKeyBackupsInInbox, noKeyBackupsInInbox, error(Error) var numberOfRows: Int { switch self { // title - case .idle, .checkingClientConfigurationIntegrity, .checkingEKMKeys: + case .idle, .decidingIfEKMshouldBeUsed, .fetchingKeysFromEKM: return 1 // title, loading - case .searching: + case .searchingKeyBackupsInInbox: return 2 case .error: return 3 - case .noKeyBackups: + case .noKeyBackupsInInbox: return Parts.allCases.count } } @@ -92,7 +92,7 @@ final class SetupInitialViewController: TableNodeViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setNeedsStatusBarAppearanceUpdate() - state = .checkingClientConfigurationIntegrity + state = .decidingIfEKMshouldBeUsed } } @@ -103,19 +103,19 @@ extension SetupInitialViewController { logger.logInfo("Changed to new state \(state)") switch state { - case .searching: - searchBackups() - case .checkingClientConfigurationIntegrity: - checkClientConfigurationIntegrity() - case .checkingEKMKeys: - checkEKMKeys() - case .error, .idle, .noKeyBackups: + case .searchingKeyBackupsInInbox: + searchKeyBackupsInInbox() + case .decidingIfEKMshouldBeUsed: + decideIfEKMshouldBeUsed() + case .fetchingKeysFromEKM: + fetchKeysFromEKM() + case .error, .idle, .noKeyBackupsInInbox: break } node.reloadData() } - private func searchBackups() { + private func searchKeyBackupsInInbox() { if !organisationalRules.canBackupKeys { logger.logInfo("Skipping backups searching because canBackupKeys == false") proceedToSetupWith(keys: []) @@ -142,22 +142,20 @@ extension SetupInitialViewController { state = .error(error) } - private func checkClientConfigurationIntegrity() { - let checkForUsingKeyManagerResult = clientConfigurationService.checkForUsingKeyManager() - - switch checkForUsingKeyManagerResult { - case .useKeyManager: - state = .checkingEKMKeys - case .skip: - state = .searching - case .error(let message): - showAlert(message: message) { [weak self] in - self?.router.signOut() - } + private func decideIfEKMshouldBeUsed() { + switch clientConfigurationService.checkShouldUseEKM() { + case .usesEKM: + state = .fetchingKeysFromEKM + case .doesNotUseEKM: + state = .searchingKeyBackupsInInbox + case .inconsistentClientConfiguration(let message): + showAlert(message: message) { [weak self] in + self?.router.signOut() + } } } - private func checkEKMKeys() { + private func fetchKeysFromEKM() { emailKeyManagerApi.getPrivateKeys() .then { [weak self] result in guard let urlString = self?.emailKeyManagerApi.getPrivateKeysUrlString() else { @@ -166,15 +164,16 @@ extension SetupInitialViewController { self?.showToast( "organisational_rules_ekm_private_keys_message".localizeWithArguments(result.privateKeys.count, urlString) ) - - self?.state = .searching + // todo - this is temporary, until we finish EKM integration + // instead we should use the keys from EKM for setup + self?.state = .searchingKeyBackupsInInbox } .catch { [weak self] error in if case .noPrivateKeysUrlString = error as? EmailKeyManagerApiError { return } self?.showAlert(message: error.localizedDescription, onOk: { - self?.state = .checkingClientConfigurationIntegrity + self?.state = .decidingIfEKMshouldBeUsed }) } } @@ -191,13 +190,13 @@ extension SetupInitialViewController: ASTableDelegate, ASTableDataSource { guard let self = self else { return ASCellNode() } switch self.state { - case .idle, .checkingClientConfigurationIntegrity, .checkingEKMKeys: + case .idle, .decidingIfEKMshouldBeUsed, .fetchingKeysFromEKM: return ASCellNode() - case .searching: + case .searchingKeyBackupsInInbox: return self.searchStateNode(for: indexPath) case .error(let error): return self.errorStateNode(for: indexPath, error: error) - case .noKeyBackups: + case .noKeyBackupsInInbox: return self.noKeysStateNode(for: indexPath) } } @@ -292,7 +291,7 @@ extension SetupInitialViewController { ) case 2: return ButtonCellNode(input: .retry) { [weak self] in - self?.state = .searching + self?.state = .searchingKeyBackupsInInbox } default: return ASCellNode() @@ -317,7 +316,7 @@ extension SetupInitialViewController { if keys.isEmpty { logger.logInfo("No key backups found in inbox") - state = .noKeyBackups + state = .noKeyBackupsInInbox } else { logger.logInfo("\(keys.count) key backups found in inbox") let viewController = SetupBackupsViewController(fetchedEncryptedKeys: keys, user: user) diff --git a/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift b/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift index 3cdbef01c..aff315b70 100644 --- a/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift +++ b/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift @@ -16,5 +16,5 @@ protocol NavigationChildController { extension NavigationChildController where Self: UIViewController { var shouldShowBackButton: Bool { true } - func handleBackButtonTap() { } + func handleBackButtonTap() {} } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift index cce4a50bc..68808cef6 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift @@ -7,7 +7,7 @@ // protocol ClientConfigurationServiceType { - func checkForUsingKeyManager() -> ClientConfigurationService.CheckForUsingEKMResult + func checkShouldUseEKM() -> ClientConfigurationService.CheckForUsingEKMResult } class ClientConfigurationService: ClientConfigurationServiceType { @@ -17,28 +17,31 @@ class ClientConfigurationService: ClientConfigurationServiceType { init(organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService()) { self.organisationalRulesService = organisationalRulesService } - /// There are in fact three states: - /// EKM is in use because organisationalRules.isUsingKeyManager == true and other OrgRules are consistent with it (result: no error, use EKM) - /// EKM is in use because organisationalRules.isUsingKeyManager == true and other OrgRules are NOT consistent with it (result: error) - /// EKM is not in use because organisationalRules.isUsingKeyManager == false (result: normal login flow) - /// - Returns: Error message if not using key manager, returns nil if using key manager - func checkForUsingKeyManager() -> CheckForUsingEKMResult { + + /** + * This method checks if the user is set up for using EKM, and if other client configuration is consistent with it. + * There are three possible outcomes: + * 1) EKM is in use because organisationalRules.isUsingKeyManager == true and other OrgRules are consistent with it (result: no error, use EKM) + * 2) EKM is in use because organisationalRules.isUsingKeyManager == true and other OrgRules are NOT consistent with it (result: error) + * 3) EKM is not in use because organisationalRules.isUsingKeyManager == false (result: normal login flow) + */ + func checkShouldUseEKM() -> CheckForUsingEKMResult { let organisationalRules = self.organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() if !organisationalRules.isUsingKeyManager { - return .skip + return .doesNotUseEKM } if !organisationalRules.mustAutoImportOrAutogenPrvWithKeyManager { - return .error(message: "organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized) + return .inconsistentClientConfiguration(message: "organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized) } if organisationalRules.mustAutogenPassPhraseQuietly { - return .error(message: "organisational_rules_autogen_passphrase_quitely_error".localized) + return .inconsistentClientConfiguration(message: "organisational_rules_autogen_passphrase_quitely_error".localized) } if !organisationalRules.forbidStoringPassPhrase { - return .error(message: "organisational_rules_forbid_storing_passphrase_error".localized) + return .inconsistentClientConfiguration(message: "organisational_rules_forbid_storing_passphrase_error".localized) } if organisationalRules.mustSubmitAttester { - return .error(message: "organisational_rules_must_submit_attester_error".localized) + return .inconsistentClientConfiguration(message: "organisational_rules_must_submit_attester_error".localized) } - return .useKeyManager + return .usesEKM } } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift index 94c3bb1e5..c6db0461b 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift @@ -10,8 +10,8 @@ import Foundation extension ClientConfigurationService { enum CheckForUsingEKMResult { - case useKeyManager - case error(message: String) - case skip + case usesEKM + case inconsistentClientConfiguration(message: String) + case doesNotUseEKM } } From 7380a28ba08e4b07b322de68acbe34f4bd68d282 Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 23 Jul 2021 20:17:21 +0800 Subject: [PATCH 8/8] align switch statements --- .../Setup/SetupInitialViewController.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index a6197c83b..d8ff44735 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -144,14 +144,14 @@ extension SetupInitialViewController { private func decideIfEKMshouldBeUsed() { switch clientConfigurationService.checkShouldUseEKM() { - case .usesEKM: - state = .fetchingKeysFromEKM - case .doesNotUseEKM: - state = .searchingKeyBackupsInInbox - case .inconsistentClientConfiguration(let message): - showAlert(message: message) { [weak self] in - self?.router.signOut() - } + case .usesEKM: + state = .fetchingKeysFromEKM + case .doesNotUseEKM: + state = .searchingKeyBackupsInInbox + case .inconsistentClientConfiguration(let message): + showAlert(message: message) { [weak self] in + self?.router.signOut() + } } }