diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index a7ee8de1a..a32ba4123 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -77,6 +77,7 @@ 9F0C3C2623194E0A00299985 /* FolderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0C3C2523194E0A00299985 /* FolderViewModel.swift */; }; 9F17976D2368EEBD002BF770 /* SetupViewDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F17976C2368EEBD002BF770 /* SetupViewDecorator.swift */; }; 9F1B4A342624E49300420472 /* KeyAlgoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E26F6924F25AB800612AF1 /* KeyAlgoObject.swift */; }; + 9F1F6D4F26EBBE2B009BC98A /* ClientConfigurationServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1F6D4E26EBBE2A009BC98A /* ClientConfigurationServiceTest.swift */; }; 9F228BA623C673AD005D2CB6 /* Springboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F228BA523C673AD005D2CB6 /* Springboard.swift */; }; 9F228BA923C67587005D2CB6 /* UserCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F228BA823C67587005D2CB6 /* UserCredentials.swift */; }; 9F228BAA23C67729005D2CB6 /* DataExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DCAEFF16F5D91A35791730 /* DataExtensions.swift */; }; @@ -112,6 +113,11 @@ 9F5C2A8B257E6C4900DE9B4B /* ImapError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5C2A8A257E6C4900DE9B4B /* ImapError.swift */; }; 9F5C2A92257E94DF00DE9B4B /* Imap+MessageOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5C2A91257E94DF00DE9B4B /* Imap+MessageOperations.swift */; }; 9F5C2A99257E94E900DE9B4B /* Gmail+MessageOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5C2A98257E94E900DE9B4B /* Gmail+MessageOperations.swift */; }; + 9F5F501D26F90AE100294FA2 /* OrganisationalRulesServiceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5F501C26F90AE100294FA2 /* OrganisationalRulesServiceMock.swift */; }; + 9F5F503526F90E5F00294FA2 /* OrganisationalRulesServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5F503426F90E5F00294FA2 /* OrganisationalRulesServiceTests.swift */; }; + 9F5F503C26FA6C5E00294FA2 /* CurrentUserEmailMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5F503B26FA6C5E00294FA2 /* CurrentUserEmailMock.swift */; }; + 9F5F504326FA6C7500294FA2 /* EnterpriseServerApiMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5F504226FA6C7500294FA2 /* EnterpriseServerApiMock.swift */; }; + 9F5F504A26FA6C8F00294FA2 /* ClientConfigurationProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5F504926FA6C8F00294FA2 /* ClientConfigurationProviderMock.swift */; }; 9F6EE1552597399D0059BA51 /* BackupProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6EE1542597399D0059BA51 /* BackupProvider.swift */; }; 9F6EE17B2598F9FA0059BA51 /* Gmail+Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6EE17A2598F9FA0059BA51 /* Gmail+Backup.swift */; }; 9F6F3BEE26ADF5DE005BD9C6 /* ComposeMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6F3BEC26ADF5DE005BD9C6 /* ComposeMessageService.swift */; }; @@ -138,6 +144,7 @@ 9F9362062573D0C80009912F /* Gmail+MessagesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9362052573D0C80009912F /* Gmail+MessagesList.swift */; }; 9F9362192573D10E0009912F /* Imap+Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9362182573D10E0009912F /* Imap+Message.swift */; }; 9F93623F2573D16F0009912F /* Gmail+Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F93623E2573D16F0009912F /* Gmail+Message.swift */; }; + 9F9500AF26F4BAE300E8C78B /* OrganisationalRulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9500AE26F4BAE300E8C78B /* OrganisationalRulesTests.swift */; }; 9F953E09238310D500AEB98B /* KeyMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F953E08238310D500AEB98B /* KeyMethods.swift */; }; 9F976490267E11880058419D /* ImapHelperTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3EF32923B15C9500FA0CEF /* ImapHelperTest.swift */; }; 9F9764C5267E14AB0058419D /* GeneralConstantsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A9CA44242622F800E1D898 /* GeneralConstantsTest.swift */; }; @@ -484,6 +491,7 @@ 9F17976C2368EEBD002BF770 /* SetupViewDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupViewDecorator.swift; sourceTree = ""; }; 9F1797702368EEE8002BF770 /* ButtonNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonNode.swift; sourceTree = ""; }; 9F1C90ED26F236BE0046E7D7 /* FlowCryptEnterprise.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FlowCryptEnterprise.entitlements; sourceTree = ""; }; + 9F1F6D4E26EBBE2A009BC98A /* ClientConfigurationServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationServiceTest.swift; sourceTree = ""; }; 9F228BA523C673AD005D2CB6 /* Springboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Springboard.swift; sourceTree = ""; }; 9F228BA823C67587005D2CB6 /* UserCredentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCredentials.swift; sourceTree = ""; }; 9F23EA4D237216FA0017DFED /* TextViewCellNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewCellNode.swift; sourceTree = ""; }; @@ -531,6 +539,11 @@ 9F5C2A8A257E6C4900DE9B4B /* ImapError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImapError.swift; sourceTree = ""; }; 9F5C2A91257E94DF00DE9B4B /* Imap+MessageOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Imap+MessageOperations.swift"; sourceTree = ""; }; 9F5C2A98257E94E900DE9B4B /* Gmail+MessageOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gmail+MessageOperations.swift"; sourceTree = ""; }; + 9F5F501C26F90AE100294FA2 /* OrganisationalRulesServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRulesServiceMock.swift; sourceTree = ""; }; + 9F5F503426F90E5F00294FA2 /* OrganisationalRulesServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRulesServiceTests.swift; sourceTree = ""; }; + 9F5F503B26FA6C5E00294FA2 /* CurrentUserEmailMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentUserEmailMock.swift; sourceTree = ""; }; + 9F5F504226FA6C7500294FA2 /* EnterpriseServerApiMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterpriseServerApiMock.swift; sourceTree = ""; }; + 9F5F504926FA6C8F00294FA2 /* ClientConfigurationProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationProviderMock.swift; sourceTree = ""; }; 9F696292236091DD003712E1 /* SignInImageNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInImageNode.swift; sourceTree = ""; }; 9F696294236091F4003712E1 /* SignInDescriptionNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInDescriptionNode.swift; sourceTree = ""; }; 9F6EE1542597399D0059BA51 /* BackupProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupProvider.swift; sourceTree = ""; }; @@ -570,6 +583,7 @@ 9F9362052573D0C80009912F /* Gmail+MessagesList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Gmail+MessagesList.swift"; sourceTree = ""; }; 9F9362182573D10E0009912F /* Imap+Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Imap+Message.swift"; sourceTree = ""; }; 9F93623E2573D16F0009912F /* Gmail+Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Gmail+Message.swift"; sourceTree = ""; }; + 9F9500AE26F4BAE300E8C78B /* OrganisationalRulesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRulesTests.swift; sourceTree = ""; }; 9F953E08238310D500AEB98B /* KeyMethods.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyMethods.swift; sourceTree = ""; }; 9F95A3F42360778E00C80B64 /* LinkButtonNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkButtonNode.swift; sourceTree = ""; }; 9F95A3F623607C0900C80B64 /* SigninButtonNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigninButtonNode.swift; sourceTree = ""; }; @@ -1150,6 +1164,7 @@ 9F4163F3266574CF00106194 /* Services */ = { isa = PBXGroup; children = ( + 9F5F500C26F90AC800294FA2 /* Organisational Rules Service */, 9FC7EBB6266EBDF000F3BF5D /* PassPhraseStorageTests */, 9F6F3C3426ADFA27005BD9C6 /* ComposeMessageServiceTests.swift */, ); @@ -1248,6 +1263,28 @@ path = "MessageOperations Provider"; sourceTree = ""; }; + 9F5F500C26F90AC800294FA2 /* Organisational Rules Service */ = { + isa = PBXGroup; + children = ( + 9F9500AE26F4BAE300E8C78B /* OrganisationalRulesTests.swift */, + 9F1F6D4E26EBBE2A009BC98A /* ClientConfigurationServiceTest.swift */, + 9F5F503426F90E5F00294FA2 /* OrganisationalRulesServiceTests.swift */, + 9F5F505026FA6DD700294FA2 /* Mocks */, + ); + path = "Organisational Rules Service"; + sourceTree = ""; + }; + 9F5F505026FA6DD700294FA2 /* Mocks */ = { + isa = PBXGroup; + children = ( + 9F5F504926FA6C8F00294FA2 /* ClientConfigurationProviderMock.swift */, + 9F5F504226FA6C7500294FA2 /* EnterpriseServerApiMock.swift */, + 9F5F503B26FA6C5E00294FA2 /* CurrentUserEmailMock.swift */, + 9F5F501C26F90AE100294FA2 /* OrganisationalRulesServiceMock.swift */, + ); + path = Mocks; + sourceTree = ""; + }; 9F6EE156259739A40059BA51 /* Backup Provider */ = { isa = PBXGroup; children = ( @@ -2441,14 +2478,18 @@ 9F6F3C3526ADFA27005BD9C6 /* ComposeMessageServiceTests.swift in Sources */, 9FC41090268100B6004C0A69 /* CoreTypesTest.swift in Sources */, 9F976584267E194F0058419D /* TestData.swift in Sources */, + 9F1F6D4F26EBBE2B009BC98A /* ClientConfigurationServiceTest.swift in Sources */, 9F6F3C6A26ADFBEB005BD9C6 /* MessageGatewayMock.swift in Sources */, 9F7E903926A1AD7A0021C07F /* KeyDetailsTests.swift in Sources */, 9FC41183268118B1004C0A69 /* EmailProviderMock.swift in Sources */, 9F976490267E11880058419D /* ImapHelperTest.swift in Sources */, + 9F5F501D26F90AE100294FA2 /* OrganisationalRulesServiceMock.swift in Sources */, + 9F5F503C26FA6C5E00294FA2 /* CurrentUserEmailMock.swift in Sources */, 9FC4116526811861004C0A69 /* BackupServiceMock.swift in Sources */, 9FC413182683C492004C0A69 /* InMemoryPassPhraseStorageTest.swift in Sources */, 9F9764C5267E14AB0058419D /* GeneralConstantsTest.swift in Sources */, 9F976507267E165D0058419D /* ZBase32EncodingTests.swift in Sources */, + 9F5F504A26FA6C8F00294FA2 /* ClientConfigurationProviderMock.swift in Sources */, 9F2F207326AEECFB0044E144 /* PromiseTestExtension.swift in Sources */, 9FC4117D268118AE004C0A69 /* PassPhraseStorageMock.swift in Sources */, 9F97650E267E16620058419D /* WKDURLsConstructorTests.swift in Sources */, @@ -2458,10 +2499,14 @@ 9FC4116B2681186D004C0A69 /* KeyMethodsTest.swift in Sources */, 9F97653D267E17C90058419D /* LocalStorageTests.swift in Sources */, 9F9764F4267E15CC0058419D /* ExtensionTests.swift in Sources */, + 9F5F503526F90E5F00294FA2 /* OrganisationalRulesServiceTests.swift in Sources */, 9F2F206826AEEAA60044E144 /* CombineTestExtension.swift in Sources */, + 9F9500AF26F4BAE300E8C78B /* OrganisationalRulesTests.swift in Sources */, 9FC413442683C912004C0A69 /* GmailServiceTest.swift in Sources */, 9F976556267E186D0058419D /* ClientConfigurationTests.swift in Sources */, 9F7E8EC6269877E70021C07F /* KeyInfoTests.swift in Sources */, + 9F5F504326FA6C7500294FA2 /* EnterpriseServerApiMock.swift in Sources */, + 9F976556267E186D0058419D /* ClientConfigurationTests.swift in Sources */, 9FC41171268118A7004C0A69 /* PassPhraseStorageTests.swift in Sources */, 9F6F3C7626ADFC37005BD9C6 /* KeyStorageMock.swift in Sources */, ); diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index beb337c44..6fd8bd00f 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -149,8 +149,8 @@ extension SetupInitialViewController { state = .fetchingKeysFromEKM case .doesNotUseEKM: state = .searchingKeyBackupsInInbox - case .inconsistentClientConfiguration(let message): - showAlert(message: message) { [weak self] in + case .inconsistentClientConfiguration(let error): + showAlert(message: error.description) { [weak self] in self?.router.signOut() } } diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index f0c74ff66..54dda78bd 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -114,10 +114,10 @@ struct AppStartup { switch session { case let .google(email, name, _): guard currentUser.email != email else { - Logger.logInfo("UserId = current user id") + logger.logInfo("UserId = current user id") return userId } - Logger.logInfo("UserId = google user id") + logger.logInfo("UserId = google user id") userId = UserId(email: email, name: name) case let .session(userObject): guard userObject.email != currentUser.email else { diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationProvider.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationProvider.swift index 9f55d6942..a1fc75a86 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationProvider.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationProvider.swift @@ -20,7 +20,7 @@ struct ClientConfigurationProvider: CacheServiceType { let storage: CacheStorage let clientConfigurationCache: CacheService - init(storage: @escaping @autoclosure CacheStorage) { + init(storage: @escaping @autoclosure CacheStorage = DataService.shared.storage) { self.storage = storage self.clientConfigurationCache = CacheService(storage: storage()) } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift index 68808cef6..02c582459 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift @@ -6,6 +6,7 @@ // Copyright © 2021 FlowCrypt Limited. All rights reserved. // +// swiftlint:disable line_length protocol ClientConfigurationServiceType { func checkShouldUseEKM() -> ClientConfigurationService.CheckForUsingEKMResult } @@ -26,21 +27,25 @@ class ClientConfigurationService: ClientConfigurationServiceType { * 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 { + let organisationalRules = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() + + guard organisationalRules.isUsingKeyManager else { return .doesNotUseEKM } + guard organisationalRules.isKeyManagerUrlValid else { + return .inconsistentClientConfiguration(checkError: .urlNotValid) + } if !organisationalRules.mustAutoImportOrAutogenPrvWithKeyManager { - return .inconsistentClientConfiguration(message: "organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized) + return .inconsistentClientConfiguration(checkError: .autoImportOrAutogenPrvWithKeyManager) } if organisationalRules.mustAutogenPassPhraseQuietly { - return .inconsistentClientConfiguration(message: "organisational_rules_autogen_passphrase_quitely_error".localized) + return .inconsistentClientConfiguration(checkError: .autogenPassPhraseQuietly) } if !organisationalRules.forbidStoringPassPhrase { - return .inconsistentClientConfiguration(message: "organisational_rules_forbid_storing_passphrase_error".localized) + return .inconsistentClientConfiguration(checkError: .forbidStoringPassPhrase) } if organisationalRules.mustSubmitAttester { - return .inconsistentClientConfiguration(message: "organisational_rules_must_submit_attester_error".localized) + return .inconsistentClientConfiguration(checkError: .mustSubmitAttester) } return .usesEKM } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift index c6db0461b..b6e6b8d9b 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift @@ -8,10 +8,33 @@ import Foundation +enum CheckEKMError: Error, CustomStringConvertible, Equatable { + case urlNotValid + case autoImportOrAutogenPrvWithKeyManager + case autogenPassPhraseQuietly + case forbidStoringPassPhrase + case mustSubmitAttester + + var description: String { + switch self { + case .urlNotValid: + return "organisational_rules_url_not_valid".localized + case .autoImportOrAutogenPrvWithKeyManager: + return "organisational_rules_autoimport_or_autogen_with_private_key_manager_error".localized + case .autogenPassPhraseQuietly: + return "organisational_rules_autogen_passphrase_quitely_error".localized + case .forbidStoringPassPhrase: + return "organisational_rules_forbid_storing_passphrase_error".localized + case .mustSubmitAttester: + return "organisational_rules_must_submit_attester_error".localized + } + } +} + extension ClientConfigurationService { - enum CheckForUsingEKMResult { + enum CheckForUsingEKMResult: Equatable { case usesEKM - case inconsistentClientConfiguration(message: String) + case inconsistentClientConfiguration(checkError: CheckEKMError) case doesNotUseEKM } } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift index 361bf226d..b435c967e 100644 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift +++ b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift @@ -12,8 +12,6 @@ import Promises protocol OrganisationalRulesServiceType { func fetchOrganisationalRulesForCurrentUser() -> Promise - func fetchOrganisationalRules(for email: String) -> Promise - func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules } @@ -21,13 +19,16 @@ final class OrganisationalRulesService { private let enterpriseServerApi: EnterpriseServerApiType private let clientConfigurationProvider: ClientConfigurationProviderType + private let isCurrentUserExist: () -> (String?) init( - storage: @escaping @autoclosure CacheStorage = DataService.shared.storage, - enterpriseServerApi: EnterpriseServerApiType = EnterpriseServerApi() + enterpriseServerApi: EnterpriseServerApiType = EnterpriseServerApi(), + clientConfigurationProvider: ClientConfigurationProviderType = ClientConfigurationProvider(), + isCurrentUserExist: @autoclosure @escaping () -> (String?) = DataService.shared.currentUser?.email ) { self.enterpriseServerApi = enterpriseServerApi - self.clientConfigurationProvider = ClientConfigurationProvider(storage: storage()) + self.clientConfigurationProvider = clientConfigurationProvider + self.isCurrentUserExist = isCurrentUserExist } } @@ -35,15 +36,15 @@ final class OrganisationalRulesService { extension OrganisationalRulesService: OrganisationalRulesServiceType { func fetchOrganisationalRulesForCurrentUser() -> Promise { - guard let currentUser = DataService.shared.currentUser else { + guard let currentUserEmail = isCurrentUserExist() else { return Promise { _, reject in reject(OrganisationalRulesServiceError.noCurrentUser) } } - return fetchOrganisationalRules(for: currentUser.email) + return fetchOrganisationalRules(for: currentUserEmail) } - func fetchOrganisationalRules(for email: String) -> Promise { + private func fetchOrganisationalRules(for email: String) -> Promise { Promise { [weak self] resolve, _ in guard let self = self else { throw AppErr.nilSelf } diff --git a/FlowCrypt/Models/ClientConfiguration.swift b/FlowCrypt/Models/ClientConfiguration.swift index 83bacf2a6..663161c34 100644 --- a/FlowCrypt/Models/ClientConfiguration.swift +++ b/FlowCrypt/Models/ClientConfiguration.swift @@ -37,6 +37,22 @@ struct ClientConfiguration: Codable, Equatable { let disallowAttesterSearchForDomains: [String]? let enforceKeygenAlgo: String? let enforceKeygenExpireMonths: Int? + + init( + flags: [ClientConfigurationFlag]? = nil, + customKeyserverUrl: String? = nil, + keyManagerUrl: String? = nil, + disallowAttesterSearchForDomains: [String]? = nil, + enforceKeygenAlgo: String? = nil, + enforceKeygenExpireMonths: Int? = nil + ) { + self.flags = flags + self.customKeyserverUrl = customKeyserverUrl + self.keyManagerUrl = keyManagerUrl + self.disallowAttesterSearchForDomains = disallowAttesterSearchForDomains + self.enforceKeygenAlgo = enforceKeygenAlgo + self.enforceKeygenExpireMonths = enforceKeygenExpireMonths + } } // MARK: - Empty model diff --git a/FlowCrypt/Models/OrganisationalRule.swift b/FlowCrypt/Models/OrganisationalRule.swift index f67d01eae..d3d3d752d 100644 --- a/FlowCrypt/Models/OrganisationalRule.swift +++ b/FlowCrypt/Models/OrganisationalRule.swift @@ -13,7 +13,7 @@ import Foundation /// These either enforce, alter or forbid various behavior to fit customer needs class OrganisationalRules { - private let clientConfiguration: ClientConfiguration + let clientConfiguration: ClientConfiguration init(clientConfiguration: ClientConfiguration) { self.clientConfiguration = clientConfiguration @@ -43,6 +43,16 @@ class OrganisationalRules { clientConfiguration.keyManagerUrl != nil } + /// Check if key manager url set properly + var isKeyManagerUrlValid: Bool { + // check for empty string + guard let urlString = clientConfiguration.keyManagerUrl, urlString.isNotEmpty else { + return false + } + // check is url can be configured + return URL(string: urlString) != nil + } + /// Enforce a key algo for keygen, eg rsa2048,rsa4096,curve25519 var enforcedKeygenAlgo: String? { clientConfiguration.enforceKeygenAlgo @@ -81,7 +91,11 @@ class OrganisationalRules { /// If a key can be found on FEKM, it will be auto imported /// If not, it will be autogenerated and stored there var mustAutoImportOrAutogenPrvWithKeyManager: Bool { - if !(clientConfiguration.flags ?? []).contains(.privateKeyAutoimportOrAutogen) { + guard let flags = clientConfiguration.flags else { + return false + } + + guard flags.contains(.privateKeyAutoimportOrAutogen) else { return false } diff --git a/FlowCrypt/Resources/en.lproj/Localizable.strings b/FlowCrypt/Resources/en.lproj/Localizable.strings index 83736f1b3..2b54453af 100644 --- a/FlowCrypt/Resources/en.lproj/Localizable.strings +++ b/FlowCrypt/Resources/en.lproj/Localizable.strings @@ -204,6 +204,7 @@ "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_url_not_valid" = "Please check if key manager url set correctly"; "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"; diff --git a/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/ClientConfigurationServiceTest.swift b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/ClientConfigurationServiceTest.swift new file mode 100644 index 000000000..4e9b5c628 --- /dev/null +++ b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/ClientConfigurationServiceTest.swift @@ -0,0 +1,168 @@ +// +// ClientConfigurationServiceTest.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 10.09.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import XCTest +@testable import FlowCrypt + +// check if Email Key Manager should be used test and other client configuration is consistent +class ClientConfigurationServiceTest: XCTestCase { + + var sut: ClientConfigurationService! + var organisationalRulesService = OrganisationalRulesServiceMock() + + override func setUp() { + super.setUp() + + sut = ClientConfigurationService(organisationalRulesService: organisationalRulesService) + } + + func testCheckDoesNotUseEKM() { + // EKM should not be used if keyManagerUrl is nil + organisationalRulesService.clientConfiguration = ClientConfiguration(keyManagerUrl: nil) + XCTAssert(sut.checkShouldUseEKM() == .doesNotUseEKM) + + // EKM should not be used if keyManagerUrl is nil + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [], + keyManagerUrl: nil + ) + XCTAssert(sut.checkShouldUseEKM() == .doesNotUseEKM) + + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [.forbidStoringPassphrase], + keyManagerUrl: nil + ) + XCTAssert(sut.checkShouldUseEKM() == .doesNotUseEKM) + } + + func testShouldUseEKM() { + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .forbidStoringPassphrase + ], + keyManagerUrl: "https://ekm.example.com" + ) + + XCTAssert(sut.checkShouldUseEKM() == .usesEKM) + } + + func testCheckShouldUseEKMShouldFailWithoutValidURL() { + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .forbidStoringPassphrase + ], + keyManagerUrl: "" + ) + + let result = sut.checkShouldUseEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .urlNotValid) + } + + func testCheckShouldUseEKMFailForAutogen() { + // No flags + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: nil, + keyManagerUrl: "https://ekm.example.com" + ) + + var result = sut.checkShouldUseEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .autoImportOrAutogenPrvWithKeyManager) + + // Empty flags + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [], + keyManagerUrl: "https://ekm.example.com" + ) + + result = sut.checkShouldUseEKM() + guard case .inconsistentClientConfiguration(let emptyFlagsError) = result else { + return XCTFail() + } + + XCTAssert(emptyFlagsError == .autoImportOrAutogenPrvWithKeyManager) + } + + func testCheckShouldUseEKMFailForAutoImportOrAutogen() { + // Wrong flags (without privateKeyAutoimportOrAutogen flag) + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [ + .noAttesterSubmit + ], + keyManagerUrl: "https://ekm.example.com" + ) + + let result = sut.checkShouldUseEKM() + guard case .inconsistentClientConfiguration(let wrongFlagError) = result else { + return XCTFail() + } + + XCTAssert(wrongFlagError == .autoImportOrAutogenPrvWithKeyManager) + } + + func testCheckShouldUseEKMFailForAutogenPassPhraseQuietly() { + // sut pass mustAutoImportOrAutogenPrvWithKeyManager check + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .passphraseQuietAutogen + ], + keyManagerUrl: "https://ekm.example.com" + ) + + let result = sut.checkShouldUseEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .autogenPassPhraseQuietly) + } + + func testCheckShouldUseEKMFailForForbidStoringPassPhrase() { + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen + ], + keyManagerUrl: "https://ekm.example.com" + ) + + let result = sut.checkShouldUseEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .forbidStoringPassPhrase) + } + + func testCheckShouldUseEKMFailForMustSubmitAttester() { + organisationalRulesService.clientConfiguration = ClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .forbidStoringPassphrase, + .enforceAttesterSubmit + ], + keyManagerUrl: "https://ekm.example.com" + ) + + let result = sut.checkShouldUseEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .mustSubmitAttester) + } +} diff --git a/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/ClientConfigurationProviderMock.swift b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/ClientConfigurationProviderMock.swift new file mode 100644 index 000000000..9ac9c1ba3 --- /dev/null +++ b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/ClientConfigurationProviderMock.swift @@ -0,0 +1,41 @@ +// +// ClientConfigurationProviderMock.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 21.09.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Foundation +@testable import FlowCrypt + +class ClientConfigurationProviderMock: ClientConfigurationProviderType { + var fetchInvoked = false + var fetchCount = 0 + var fetchCall: () -> (ClientConfiguration?) = { + nil + } + func fetch() -> ClientConfiguration? { + fetchInvoked = true + fetchCount += 1 + return fetchCall() + } + + var removeClientConfigurationInvoked = false + var removeClientConfigurationCount = 0 + func removeClientConfiguration() { + removeClientConfigurationInvoked = true + removeClientConfigurationCount += 1 + } + + var saveInvoked = false + var saveCount = 0 + var saveCall: (ClientConfiguration) -> (Void) = { clientConfiguration in + + } + func save(clientConfiguration: ClientConfiguration) { + saveInvoked = true + saveCount += 1 + saveCall(clientConfiguration) + } +} diff --git a/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/CurrentUserEmailMock.swift b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/CurrentUserEmailMock.swift new file mode 100644 index 000000000..52b2309c2 --- /dev/null +++ b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/CurrentUserEmailMock.swift @@ -0,0 +1,18 @@ +// +// CurrentUserEmailMock.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 21.09.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Foundation + +class CurrentUserEmailMock { + var currentUserEmailCall: () -> (String?) = { + nil + } + func currentUserEmail() -> String? { + currentUserEmailCall() + } +} diff --git a/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/EnterpriseServerApiMock.swift b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/EnterpriseServerApiMock.swift new file mode 100644 index 000000000..a2f89689a --- /dev/null +++ b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/EnterpriseServerApiMock.swift @@ -0,0 +1,57 @@ +// +// EnterpriseServerApiMock.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 21.09.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Foundation +import Promises +@testable import FlowCrypt + +class EnterpriseServerApiMock: EnterpriseServerApiType { + var getActiveFesUrlInvoked = false + var getActiveFesUrlInvokedCount = 0 + var getActiveFesUrlCall: (String) -> (Result) = { email in + .failure(OrganisationalRulesServiceError.getActiveFesUrlCall) + } + func getActiveFesUrl(for email: String) -> Promise { + getActiveFesUrlInvoked = true + getActiveFesUrlInvokedCount += 1 + return Promise.resolveAfter(with: getActiveFesUrlCall(email)) + } + + var getActiveFesUrlForCurrentUserInvoked = false + var getActiveFesUrlForCurrentUserCount = 0 + var getActiveFesUrlForCurrentUserCall: () -> (Result) = { + .failure(OrganisationalRulesServiceError.getActiveFesUrlForCurrentUserCall) + } + func getActiveFesUrlForCurrentUser() -> Promise { + getActiveFesUrlForCurrentUserInvoked = true + getActiveFesUrlForCurrentUserCount += 1 + return Promise.resolveAfter(with: getActiveFesUrlForCurrentUserCall()) + } + + var getClientConfigurationInvoked = false + var getClientConfigurationCount = 0 + var getClientConfigurationCall: (String) -> (Result) = { email in + .failure(OrganisationalRulesServiceError.getClientConfigurationCall) + } + func getClientConfiguration(for email: String) -> Promise { + getClientConfigurationInvoked = true + getClientConfigurationCount += 1 + return Promise.resolveAfter(with: getClientConfigurationCall(email)) + } + + var getClientConfigurationForCurrentUserInvoked = false + var getClientConfigurationForCurrentUserCount = 0 + var getClientConfigurationForCurrentUserCall: () -> (Result) = { + .failure(OrganisationalRulesServiceError.getClientConfigurationForCurrentUserCall) + } + func getClientConfigurationForCurrentUser() -> Promise { + getClientConfigurationForCurrentUserInvoked = true + getClientConfigurationForCurrentUserCount += 1 + return Promise.resolveAfter(with: getClientConfigurationForCurrentUserCall()) + } +} diff --git a/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/OrganisationalRulesServiceMock.swift b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/OrganisationalRulesServiceMock.swift new file mode 100644 index 000000000..5edf84094 --- /dev/null +++ b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/Mocks/OrganisationalRulesServiceMock.swift @@ -0,0 +1,35 @@ +// +// OrganisationalRulesServiceMock.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 20.09.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Foundation +import Promises +@testable import FlowCrypt + +class OrganisationalRulesServiceMock: OrganisationalRulesServiceType { + + var fetchOrganisationalRulesForCurrentUserResult: Result = .failure(MockError.some) + func fetchOrganisationalRulesForCurrentUser() -> Promise { + .resolveAfter(timeout: 1, with: fetchOrganisationalRulesForCurrentUserResult) + } + + var fetchOrganisationalRulesForEmail: (String) -> (Result) = { email in + return .failure(MockError.some) + } + func fetchOrganisationalRules(for email: String) -> Promise { + .resolveAfter(timeout: 1, with: fetchOrganisationalRulesForEmail(email)) + } + + var clientConfiguration: ClientConfiguration! + + var getSavedOrganisationalRulesForCurrentUserResult: OrganisationalRules { + OrganisationalRules(clientConfiguration: clientConfiguration) + } + func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules { + getSavedOrganisationalRulesForCurrentUserResult + } +} diff --git a/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/OrganisationalRulesServiceTests.swift b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/OrganisationalRulesServiceTests.swift new file mode 100644 index 000000000..2e970adcb --- /dev/null +++ b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/OrganisationalRulesServiceTests.swift @@ -0,0 +1,182 @@ +// +// OrganisationalRulesServiceTests.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 20.09.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import XCTest +import Promises +@testable import FlowCrypt + +class OrganisationalRulesServiceTests: XCTestCase { + + var sut: OrganisationalRulesService! + var enterpriseServerApi: EnterpriseServerApiMock! + var clientConfigurationProvider: ClientConfigurationProviderMock! + var isCurrentUserExistMock: CurrentUserEmailMock! + + override func setUp() { + super.setUp() + enterpriseServerApi = EnterpriseServerApiMock() + clientConfigurationProvider = ClientConfigurationProviderMock() + isCurrentUserExistMock = CurrentUserEmailMock() + + sut = OrganisationalRulesService( + enterpriseServerApi: enterpriseServerApi, + clientConfigurationProvider: clientConfigurationProvider, + isCurrentUserExist: self.isCurrentUserExistMock.currentUserEmail() + ) + + DispatchQueue.promises = .global() + } + + func testGetSavedOrganisationalRulesForCurrentUser() { + let expectedConfiguration = ClientConfiguration(keyManagerUrl: "https://ekm.example.com") + clientConfigurationProvider.fetchCall = { + expectedConfiguration + } + + let organisationalRules = sut.getSavedOrganisationalRulesForCurrentUser() + XCTAssert(clientConfigurationProvider.fetchCount == 1) + XCTAssert(clientConfigurationProvider.fetchInvoked == true) + XCTAssert(organisationalRules.clientConfiguration == expectedConfiguration) + } + + func testFetchOrganisationalRulesForCurrentUserNil() { + let expectation = XCTestExpectation(description: "Promise should resolve with error if current user = nil") + isCurrentUserExistMock.currentUserEmailCall = { + nil + } + sut.fetchOrganisationalRulesForCurrentUser() + .then(on: .main) { _ -> Promise in + XCTFail() + let result: Result = .failure(.some) + return Promise.resolveAfter(with: result) + } + .catch(on: .main) { error in + expectation.fulfill() + } + + wait(for: [expectation], timeout: 1) + } + + func testFetchOrganisationalRulesForCurrentUser() { + let fetchOrganisationalRulesExpectation = XCTestExpectation( + description: "fetchOrganisationalRules for test email should be called" + ) + let getClientConfigurationInvokedExpectation = XCTestExpectation( + description: "getClientConfiguration should be called" + ) + let getClientConfigurationCountExpectation = XCTestExpectation( + description: "getClientConfiguration should be called" + ) + let getClientConfigurationCallExpectation = XCTestExpectation( + description: "getClientConfiguration should be called for test email" + ) + let clientConfigurationProviderSaveCall = XCTestExpectation( + description: "clientConfigurationProvider save method should be called for config" + ) + let clientConfigurationProviderSaveCountCall = XCTestExpectation( + description: "clientConfigurationProvider save method should be called for config" + ) + + let expectations: [XCTestExpectation] = [ + fetchOrganisationalRulesExpectation, + getClientConfigurationInvokedExpectation, + getClientConfigurationCountExpectation, + getClientConfigurationCallExpectation, + clientConfigurationProviderSaveCall, + clientConfigurationProviderSaveCountCall + ] + + let expectedClientConfiguration = ClientConfiguration(keyManagerUrl: "https://ekm.example.com") + + // (String) -> (Result) + self.enterpriseServerApi.getClientConfigurationCall = { email in + if email == "example@flowcrypt.test" { + getClientConfigurationCallExpectation.fulfill() + } + return Result.success(expectedClientConfiguration) + } + + // (ClientConfiguration) -> (Void) + self.clientConfigurationProvider.saveCall = { clientConfiguration in + if clientConfiguration.keyManagerUrl == expectedClientConfiguration.keyManagerUrl { + clientConfigurationProviderSaveCall.fulfill() + } + } + + isCurrentUserExistMock.currentUserEmailCall = { + "example@flowcrypt.test" + } + + sut.fetchOrganisationalRulesForCurrentUser() + .then(on: .main) { orgRules -> Promise in + fetchOrganisationalRulesExpectation.fulfill() + + // test calls for enterpriseServerApi + if self.enterpriseServerApi.getClientConfigurationInvoked { + getClientConfigurationInvokedExpectation.fulfill() + } + if self.enterpriseServerApi.getClientConfigurationCount == 1 { + getClientConfigurationCountExpectation.fulfill() + } + if self.clientConfigurationProvider.saveCount == 1 { + clientConfigurationProviderSaveCountCall.fulfill() + } + + let result: Result = .success(orgRules) + return Promise.resolveAfter(with: result) + } + .catch(on: .main) { error in + XCTFail() + } + + wait(for: expectations, timeout: 1) + } + + func testInCaseGetClientConfigurationReturnsError() { + let fetchOrganisationalRulesForCurrentUserExpectation = XCTestExpectation() + + let expectations = [ + fetchOrganisationalRulesForCurrentUserExpectation + ] + + let expectedClientConfiguration = ClientConfiguration(keyManagerUrl: "https://ekm.example.com") + + self.enterpriseServerApi.getClientConfigurationCall = { email in + .failure(MockError.some) + } + + isCurrentUserExistMock.currentUserEmailCall = { + "example@flowcrypt.test" + } + + clientConfigurationProvider.fetchCall = { + expectedClientConfiguration + } + + sut.fetchOrganisationalRulesForCurrentUser() + .then(on: .main) { organisationalRules -> Promise in + if organisationalRules.clientConfiguration == expectedClientConfiguration { + fetchOrganisationalRulesForCurrentUserExpectation.fulfill() + } + let result: Result = .success(organisationalRules) + return Promise.resolveAfter(with: result) + } + .recover { error -> Promise in + let result: Result = .success(OrganisationalRules(clientConfiguration: expectedClientConfiguration)) + return Promise.resolveAfter(with: result) + } + wait(for: expectations, timeout: 1) + } +} + +enum OrganisationalRulesServiceError: Error { + case getActiveFesUrlCall + case getActiveFesUrlForCurrentUserCall + case getClientConfigurationCall + case getClientConfigurationForCurrentUserCall +} diff --git a/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/OrganisationalRulesTests.swift b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/OrganisationalRulesTests.swift new file mode 100644 index 000000000..f1b60f89d --- /dev/null +++ b/FlowCryptAppTests/Functionallity/Services/Organisational Rules Service/OrganisationalRulesTests.swift @@ -0,0 +1,109 @@ +// +// OrganisationalRulesTests.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 17.09.2021. +// Copyright © 2021 FlowCrypt Limited. All rights reserved. +// + +import Foundation +import XCTest +@testable import FlowCrypt + +class OrganisationalRulesTests: XCTestCase { + var sut: OrganisationalRules! { + .init(clientConfiguration: clientConfiguration) + } + var clientConfiguration: ClientConfiguration! + + func testIsUsingKeyManagerURL() { + clientConfiguration = ClientConfiguration(keyManagerUrl: "https://ekm.example.com") + XCTAssertTrue(sut.isUsingKeyManager) + + clientConfiguration = ClientConfiguration(keyManagerUrl: nil) + XCTAssertFalse(sut.isKeyManagerUrlValid) + } + + func testIsUsingValidKeyManagerURL() { + // valid url check in + clientConfiguration = ClientConfiguration(keyManagerUrl: "") + XCTAssertFalse(sut.isKeyManagerUrlValid) + + clientConfiguration = ClientConfiguration(keyManagerUrl: "not a url string") + XCTAssertFalse(sut.isKeyManagerUrlValid) + } + + func testMustAutoImportOrAutogenPrvWithKeyManager() { + clientConfiguration = ClientConfiguration( + flags: [.privateKeyAutoimportOrAutogen], + keyManagerUrl: "https://ekm.example.com" + ) + XCTAssertTrue(sut.mustAutoImportOrAutogenPrvWithKeyManager) + + clientConfiguration = ClientConfiguration( + flags: [], + keyManagerUrl: "https://ekm.example.com" + ) + XCTAssertFalse(sut.mustAutoImportOrAutogenPrvWithKeyManager) + + clientConfiguration = ClientConfiguration( + flags: nil, + keyManagerUrl: "https://ekm.example.com" + ) + XCTAssertFalse(sut.mustAutoImportOrAutogenPrvWithKeyManager) + + clientConfiguration = ClientConfiguration( + flags: [.defaultRememberPassphrase, .hideArmorMeta, .enforceAttesterSubmit], + keyManagerUrl: "https://ekm.example.com" + ) + XCTAssertFalse(sut.mustAutoImportOrAutogenPrvWithKeyManager) + } + + func testMustAutogenPassPhraseQuietly() { + clientConfiguration = ClientConfiguration( + flags: [.passphraseQuietAutogen] + ) + XCTAssertTrue(sut.mustAutogenPassPhraseQuietly) + + clientConfiguration = ClientConfiguration(flags: []) + XCTAssertFalse(sut.mustAutogenPassPhraseQuietly) + + clientConfiguration = ClientConfiguration(flags: [.privateKeyAutoimportOrAutogen]) + XCTAssertFalse(sut.mustAutogenPassPhraseQuietly) + + clientConfiguration = ClientConfiguration(flags: nil) + XCTAssertFalse(sut.mustAutogenPassPhraseQuietly) + } + + func testForbidStoringPassPhrase() { + clientConfiguration = ClientConfiguration( + flags: [.forbidStoringPassphrase] + ) + XCTAssertTrue(sut.forbidStoringPassPhrase) + + clientConfiguration = ClientConfiguration(flags: []) + XCTAssertFalse(sut.forbidStoringPassPhrase) + + clientConfiguration = ClientConfiguration(flags: [.hideArmorMeta]) + XCTAssertFalse(sut.forbidStoringPassPhrase) + + clientConfiguration = ClientConfiguration(flags: nil) + XCTAssertFalse(sut.forbidStoringPassPhrase) + } + + func testMustSubmitAttester() { + clientConfiguration = ClientConfiguration( + flags: [.enforceAttesterSubmit] + ) + XCTAssertTrue(sut.mustSubmitAttester) + + clientConfiguration = ClientConfiguration(flags: []) + XCTAssertFalse(sut.mustSubmitAttester) + + clientConfiguration = ClientConfiguration(flags: [.hideArmorMeta]) + XCTAssertFalse(sut.mustSubmitAttester) + + clientConfiguration = ClientConfiguration(flags: nil) + XCTAssertFalse(sut.mustSubmitAttester) + } +} diff --git a/FlowCryptAppTests/PromiseTestExtension.swift b/FlowCryptAppTests/PromiseTestExtension.swift index f4a7dce81..976e7cb75 100644 --- a/FlowCryptAppTests/PromiseTestExtension.swift +++ b/FlowCryptAppTests/PromiseTestExtension.swift @@ -10,7 +10,7 @@ import Foundation import Promises extension Promise { - static func resolveAfter(timeout: TimeInterval = 5, with result: Result) -> Promise { + static func resolveAfter(timeout: TimeInterval = 0.2, with result: Result) -> Promise { Promise { resolve, reject in DispatchQueue.main.asyncAfter(deadline: .now() + timeout) { switch result {