diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index 851431226..6d4254147 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -11,13 +11,11 @@ 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 /* 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 */; }; + 21489B78267CB42400BDE4AC /* LocalClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B77267CB42400BDE4AC /* LocalClientConfiguration.swift */; }; 21489B7A267CB4DF00BDE4AC /* ClientConfigurationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B79267CB4DF00BDE4AC /* ClientConfigurationObject.swift */; }; - 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 */; }; + 21489B7C267CBA0E00BDE4AC /* RawClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B7B267CBA0E00BDE4AC /* RawClientConfiguration.swift */; }; + 21489B80267CC39E00BDE4AC /* ClientConfigurationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21489B7F267CC39E00BDE4AC /* ClientConfigurationService.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 */; }; 2155E9EF26E3628C008FB033 /* Refreshable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2155E9EE26E3628C008FB033 /* Refreshable.swift */; }; @@ -27,14 +25,13 @@ 21750D7D26C6AFA6007E6A6F /* SetupEKMKeyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21750D7C26C6AFA6007E6A6F /* SetupEKMKeyViewController.swift */; }; 21750D7F26C6C1E3007E6A6F /* SetupCreatePassphraseAbstractViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21750D7E26C6C1E3007E6A6F /* SetupCreatePassphraseAbstractViewController.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 */; }; 21C7DF09266C0D8F00C44800 /* EnterpriseServerApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21C7DF08266C0D8F00C44800 /* EnterpriseServerApi.swift */; }; 21C7DF0B266C0E3600C44800 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21C7DF0A266C0E3600C44800 /* Configuration.swift */; }; 21CE25E62650070300ADFF4B /* WkdUrlConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21CE25E52650070300ADFF4B /* WkdUrlConstructor.swift */; }; - 21EA3B592656611D00691848 /* OrganisationalRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21EA3B15265647C400691848 /* OrganisationalRule.swift */; }; + 21EA3B592656611D00691848 /* ClientConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21EA3B15265647C400691848 /* ClientConfiguration.swift */; }; 21EFF61F265A5C6700AB0B71 /* WkdApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21EFF61E265A5C6700AB0B71 /* WkdApi.swift */; }; 21F836B62652A26B00B2448C /* DataExntensions+ZBase32Encoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21F836B52652A26B00B2448C /* DataExntensions+ZBase32Encoding.swift */; }; 21FEE26626FDD91A00E3783F /* ComposeMessageAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FEE26526FDD91A00E3783F /* ComposeMessageAttachment.swift */; }; @@ -99,7 +96,6 @@ 9F0C3C1A231819C500299985 /* MessageKindProviderType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0C3C19231819C500299985 /* MessageKindProviderType.swift */; }; 9F0C3C2623194E0A00299985 /* FolderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0C3C2523194E0A00299985 /* FolderViewModel.swift */; }; 9F17976D2368EEBD002BF770 /* SetupViewDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F17976C2368EEBD002BF770 /* SetupViewDecorator.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 */; }; @@ -136,7 +132,7 @@ 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 */; }; + 9F5F503526F90E5F00294FA2 /* ClientConfigurationServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5F503426F90E5F00294FA2 /* ClientConfigurationServiceTests.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 */; }; @@ -166,7 +162,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 */; }; + 9F9500AF26F4BAE300E8C78B /* ClientConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9500AE26F4BAE300E8C78B /* ClientConfigurationTests.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 */; }; @@ -174,7 +170,7 @@ 9F976507267E165D0058419D /* ZBase32EncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21F836CB2652A38700B2448C /* ZBase32EncodingTests.swift */; }; 9F97650E267E16620058419D /* WKDURLsConstructorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21F836D22652A46E00B2448C /* WKDURLsConstructorTests.swift */; }; 9F97653D267E17C90058419D /* LocalStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F003D9D25EA910B00EB38C0 /* LocalStorageTests.swift */; }; - 9F976556267E186D0058419D /* ClientConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21EA3B2226565B5D00691848 /* ClientConfigurationTests.swift */; }; + 9F976556267E186D0058419D /* RawClientConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21EA3B2226565B5D00691848 /* RawClientConfigurationTests.swift */; }; 9F976569267E18F30058419D /* client_configuraion.json in Resources */ = {isa = PBXBuildFile; fileRef = 21EA3B2E26565B7400691848 /* client_configuraion.json */; }; 9F976576267E18F90058419D /* client_configuraion_partly_empty.json in Resources */ = {isa = PBXBuildFile; fileRef = 21EA3B3C26565B9800691848 /* client_configuraion_partly_empty.json */; }; 9F97657D267E18FE0058419D /* client_configuraion_empty.json in Resources */ = {isa = PBXBuildFile; fileRef = 21EA3B3526565B8100691848 /* client_configuraion_empty.json */; }; @@ -286,7 +282,7 @@ D2717752242567EB00BDA9A9 /* KeyTextCellNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADEDCC123A43C6800EC495E /* KeyTextCellNode.swift */; }; D2717753242568A600BDA9A9 /* NavigationBarItemsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD22A19230FD781005067A6 /* NavigationBarItemsView.swift */; }; D2717754242568A600BDA9A9 /* NavigationBarActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD22A1E230FEFC6005067A6 /* NavigationBarActionButton.swift */; }; - D274724124F97C5C006BA6EF /* CacheService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274724024F97C5C006BA6EF /* CacheService.swift */; }; + D274724124F97C5C006BA6EF /* EncryptedCacheService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274724024F97C5C006BA6EF /* EncryptedCacheService.swift */; }; D274724424FD1932006BA6EF /* FolderObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274724324FD1932006BA6EF /* FolderObject.swift */; }; D27B911924EFE79F002DF0A1 /* LocalContactsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27B911824EFE79F002DF0A1 /* LocalContactsProvider.swift */; }; D27B911D24EFE806002DF0A1 /* ContactObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27B911C24EFE806002DF0A1 /* ContactObject.swift */; }; @@ -410,15 +406,13 @@ 0B1FD1088504F12263991E77 /* Pods-FlowCrypt.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlowCrypt.release.xcconfig"; path = "Target Support Files/Pods-FlowCrypt/Pods-FlowCrypt.release.xcconfig"; sourceTree = ""; }; 1F919F817E5651D30BFF9C0B /* Pods-FlowCrypt.enterprise.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlowCrypt.enterprise.xcconfig"; path = "Target Support Files/Pods-FlowCrypt/Pods-FlowCrypt.enterprise.xcconfig"; sourceTree = ""; }; 211392A4266511E6009202EC /* PubLookup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PubLookup.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 = ""; }; + 21489B77267CB42400BDE4AC /* LocalClientConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalClientConfiguration.swift; sourceTree = ""; }; 21489B79267CB4DF00BDE4AC /* ClientConfigurationObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationObject.swift; sourceTree = ""; }; - 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 = ""; }; + 21489B7B267CBA0E00BDE4AC /* RawClientConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawClientConfiguration.swift; sourceTree = ""; }; + 21489B7F267CC39E00BDE4AC /* ClientConfigurationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationService.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 = ""; }; 2155E9EE26E3628C008FB033 /* Refreshable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Refreshable.swift; sourceTree = ""; }; @@ -428,14 +422,13 @@ 21750D7C26C6AFA6007E6A6F /* SetupEKMKeyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupEKMKeyViewController.swift; sourceTree = ""; }; 21750D7E26C6C1E3007E6A6F /* SetupCreatePassphraseAbstractViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupCreatePassphraseAbstractViewController.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 = ""; }; 21C7DF0A266C0E3600C44800 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; 21CE25E52650070300ADFF4B /* WkdUrlConstructor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WkdUrlConstructor.swift; sourceTree = ""; }; - 21EA3B15265647C400691848 /* OrganisationalRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganisationalRule.swift; sourceTree = ""; }; - 21EA3B2226565B5D00691848 /* ClientConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationTests.swift; sourceTree = ""; }; + 21EA3B15265647C400691848 /* ClientConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfiguration.swift; sourceTree = ""; }; + 21EA3B2226565B5D00691848 /* RawClientConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawClientConfigurationTests.swift; sourceTree = ""; }; 21EA3B2E26565B7400691848 /* client_configuraion.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion.json; sourceTree = ""; }; 21EA3B3526565B8100691848 /* client_configuraion_empty.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion_empty.json; sourceTree = ""; }; 21EA3B3C26565B9800691848 /* client_configuraion_partly_empty.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = client_configuraion_partly_empty.json; sourceTree = ""; }; @@ -516,7 +509,6 @@ 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 = ""; }; @@ -564,7 +556,7 @@ 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 = ""; }; + 9F5F503426F90E5F00294FA2 /* ClientConfigurationServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationServiceTests.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 = ""; }; @@ -607,7 +599,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 = ""; }; + 9F9500AE26F4BAE300E8C78B /* ClientConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientConfigurationTests.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 = ""; }; @@ -712,7 +704,7 @@ D26F132624509EB6009175BA /* RecipientEmailsCellNodeInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipientEmailsCellNodeInput.swift; sourceTree = ""; }; D27177482424D73000BDA9A9 /* InboxViewDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxViewDecorator.swift; sourceTree = ""; }; D271774D24255F1100BDA9A9 /* UIColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorExtensions.swift; sourceTree = ""; }; - D274724024F97C5C006BA6EF /* CacheService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheService.swift; sourceTree = ""; }; + D274724024F97C5C006BA6EF /* EncryptedCacheService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedCacheService.swift; sourceTree = ""; }; D274724324FD1932006BA6EF /* FolderObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderObject.swift; sourceTree = ""; }; D27B911824EFE79F002DF0A1 /* LocalContactsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalContactsProvider.swift; sourceTree = ""; }; D27B911C24EFE806002DF0A1 /* ContactObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactObject.swift; sourceTree = ""; }; @@ -834,8 +826,7 @@ 9F1B49E02624E19D00420472 /* Realm Models */, 9F0C3C132316E69300299985 /* User.swift */, 9F9AAFFC2383E216000A00F1 /* Document.swift */, - 21EA3B15265647C400691848 /* OrganisationalRule.swift */, - 21489B7B267CBA0E00BDE4AC /* ClientConfiguration.swift */, + 21489B7B267CBA0E00BDE4AC /* RawClientConfiguration.swift */, ); path = Models; sourceTree = ""; @@ -869,16 +860,14 @@ path = FilesManager; sourceTree = ""; }; - 21489B81267CC3BC00BDE4AC /* Organisational Rules Service */ = { + 21489B81267CC3BC00BDE4AC /* Client Configuration Service */ = { isa = PBXGroup; children = ( - 2133D51526A0571F00CC686F /* ClientConfigurationService.swift */, - 21489B77267CB42400BDE4AC /* ClientConfigurationProvider.swift */, - 21489B7F267CC39E00BDE4AC /* OrganisationalRulesService.swift */, - 21489B82267CC99C00BDE4AC /* OrganisationalRulesServiceError.swift */, - 21B15C9326AA00A400D8522B /* ClientConfigurationServiceResults.swift */, + 21EA3B15265647C400691848 /* ClientConfiguration.swift */, + 21489B7F267CC39E00BDE4AC /* ClientConfigurationService.swift */, + 21489B77267CB42400BDE4AC /* LocalClientConfiguration.swift */, ); - path = "Organisational Rules Service"; + path = "Client Configuration Service"; sourceTree = ""; }; 215897E6267A551300423694 /* FilesManager */ = { @@ -900,7 +889,7 @@ 21EA3B2126565B4100691848 /* Models Parsing */ = { isa = PBXGroup; children = ( - 21EA3B2226565B5D00691848 /* ClientConfigurationTests.swift */, + 21EA3B2226565B5D00691848 /* RawClientConfigurationTests.swift */, 21EA3B2E26565B7400691848 /* client_configuraion.json */, 21EA3B3C26565B9800691848 /* client_configuraion_partly_empty.json */, 21EA3B3526565B8100691848 /* client_configuraion_empty.json */, @@ -1073,13 +1062,13 @@ A3B7C31823F576BA0022D628 /* AppStartup.swift */, 9F0C3C0F2316DD5B00299985 /* GoogleUserService.swift */, 9F31AB9F232C071700CF87EA /* GlobalRouter.swift */, - D274724024F97C5C006BA6EF /* CacheService.swift */, + D274724024F97C5C006BA6EF /* EncryptedCacheService.swift */, C132B9CA1EC2DE6400763715 /* GeneralConstants.swift */, A381F250271C1D1A00A3D13C /* Account Server Services */, 9F6F3BEB26ADF5DE005BD9C6 /* Compose Message Service */, 9F41FA1C25372C2D003B970D /* Backup Services */, D227C0E4250538190070F805 /* Folders Services */, - 21489B81267CC3BC00BDE4AC /* Organisational Rules Service */, + 21489B81267CC3BC00BDE4AC /* Client Configuration Service */, D27B911724EFE787002DF0A1 /* Local Pub Key Services */, 9FB22CFD25715DDF0026EE64 /* Local Private Key Services */, A381F24D271C1C1100A3D13C /* Remote Pub Key Services */, @@ -1180,7 +1169,7 @@ children = ( 9F6F3C3426ADFA27005BD9C6 /* ComposeMessageServiceTests.swift */, 2C2A3B492719EE4D00B7F27B /* Key Services */, - 9F5F500C26F90AC800294FA2 /* Organisational Rules Service */, + 9F5F500C26F90AC800294FA2 /* Client Configuration Service */, 9FC7EBB6266EBDF000F3BF5D /* PassPhraseStorageTests */, ); path = Services; @@ -1278,15 +1267,14 @@ path = "MessageOperations Provider"; sourceTree = ""; }; - 9F5F500C26F90AC800294FA2 /* Organisational Rules Service */ = { + 9F5F500C26F90AC800294FA2 /* Client Configuration Service */ = { isa = PBXGroup; children = ( - 9F9500AE26F4BAE300E8C78B /* OrganisationalRulesTests.swift */, - 9F1F6D4E26EBBE2A009BC98A /* ClientConfigurationServiceTest.swift */, - 9F5F503426F90E5F00294FA2 /* OrganisationalRulesServiceTests.swift */, + 9F9500AE26F4BAE300E8C78B /* ClientConfigurationTests.swift */, + 9F5F503426F90E5F00294FA2 /* ClientConfigurationServiceTests.swift */, 9F5F505026FA6DD700294FA2 /* Mocks */, ); - path = "Organisational Rules Service"; + path = "Client Configuration Service"; sourceTree = ""; }; 9F5F505026FA6DD700294FA2 /* Mocks */ = { @@ -2463,7 +2451,6 @@ 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 */, @@ -2485,12 +2472,12 @@ 9FC4116B2681186D004C0A69 /* KeyMethodsTest.swift in Sources */, 9F97653D267E17C90058419D /* LocalStorageTests.swift in Sources */, 9F9764F4267E15CC0058419D /* ExtensionTests.swift in Sources */, - 9F5F503526F90E5F00294FA2 /* OrganisationalRulesServiceTests.swift in Sources */, + 9F5F503526F90E5F00294FA2 /* ClientConfigurationServiceTests.swift in Sources */, 9F2F206826AEEAA60044E144 /* CombineTestExtension.swift in Sources */, 51775C32270B01C200D7C944 /* PrvKeyInfoTests.swift in Sources */, - 9F9500AF26F4BAE300E8C78B /* OrganisationalRulesTests.swift in Sources */, + 9F9500AF26F4BAE300E8C78B /* ClientConfigurationTests.swift in Sources */, 9FC413442683C912004C0A69 /* GmailServiceTest.swift in Sources */, - 9F976556267E186D0058419D /* ClientConfigurationTests.swift in Sources */, + 9F976556267E186D0058419D /* RawClientConfigurationTests.swift in Sources */, 9F7E8EC6269877E70021C07F /* KeyInfoTests.swift in Sources */, 9F5F504326FA6C7500294FA2 /* EnterpriseServerApiMock.swift in Sources */, 9FC41171268118A7004C0A69 /* PassPhraseStorageTests.swift in Sources */, @@ -2529,7 +2516,7 @@ 51B4AE5327144E590001F33B /* PubKey.swift in Sources */, 21623D1826FA860700A11B9A /* PhotosManager.swift in Sources */, C132B9B41EC2DBD800763715 /* AppDelegate.swift in Sources */, - 21489B7C267CBA0E00BDE4AC /* ClientConfiguration.swift in Sources */, + 21489B7C267CBA0E00BDE4AC /* RawClientConfiguration.swift in Sources */, 9F976592267E19880058419D /* TestData.swift in Sources */, 04B472961ECE29F600B8266F /* SideMenuNavigationController.swift in Sources */, 5A39F441239EF17F001F4607 /* LegalViewControllersProvider.swift in Sources */, @@ -2561,16 +2548,14 @@ D952B71D1ED0CB2500E5C02B /* MessageViewController.swift in Sources */, 5A39F42D239EC321001F4607 /* SettingsViewController.swift in Sources */, 5ADEDCBC23A4329000EC495E /* PublicKeyDetailViewController.swift in Sources */, - 21489B80267CC39E00BDE4AC /* OrganisationalRulesService.swift in Sources */, + 21489B80267CC39E00BDE4AC /* ClientConfigurationService.swift in Sources */, D28655932423B4EE0066F52E /* MyMenuViewDecorator.swift in Sources */, 04B4728D1ECE29D200B8266F /* KeyInfo.swift in Sources */, 9F3EF32F23B172D300FA0CEF /* SearchViewController.swift in Sources */, D2F6D147243506DA00DB4065 /* MailSettingsCredentials.swift in Sources */, 9F9361A52573CE260009912F /* MessageProvider.swift in Sources */, 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 */, @@ -2626,7 +2611,7 @@ 9FC4112E2595EA8B001180A8 /* Gmail+Search.swift in Sources */, 5A948DC5239EF2F4006284D7 /* LegalViewController.swift in Sources */, 5133B6722716321F00C95463 /* ContactKeyDetailDecorator.swift in Sources */, - D274724124F97C5C006BA6EF /* CacheService.swift in Sources */, + D274724124F97C5C006BA6EF /* EncryptedCacheService.swift in Sources */, A3B7C31923F576BA0022D628 /* AppStartup.swift in Sources */, 9F31AB8E23298BCF00CF87EA /* Imap+folders.swift in Sources */, D2891AC224C59EFA008918E3 /* KeyService.swift in Sources */, @@ -2643,7 +2628,6 @@ 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 */, 9F0C3C102316DD5B00299985 /* GoogleUserService.swift in Sources */, @@ -2669,7 +2653,7 @@ 9F6EE1552597399D0059BA51 /* BackupProvider.swift in Sources */, 9FEED1D2230DAD1E00700F8E /* InboxViewModel.swift in Sources */, 32DCAF9DA9EC47798DF8BB73 /* SignInViewController.swift in Sources */, - 21489B78267CB42400BDE4AC /* ClientConfigurationProvider.swift in Sources */, + 21489B78267CB42400BDE4AC /* LocalClientConfiguration.swift in Sources */, 9FF0671C25520D9D00FCC9E6 /* MailProvider.swift in Sources */, 21FEE26626FDD91A00E3783F /* ComposeMessageAttachment.swift in Sources */, 9FE743072347AA54005E2DBB /* MainNavigationController.swift in Sources */, @@ -2692,7 +2676,7 @@ 9FC7EB76266EB67B00F3BF5D /* EncryptedStorageProtocols.swift in Sources */, 32DCACF9C6FC4B9330C9B362 /* Imap+send.swift in Sources */, 32DCAF95A6A329C3136B1C8E /* Imap+msg.swift in Sources */, - 21EA3B592656611D00691848 /* OrganisationalRule.swift in Sources */, + 21EA3B592656611D00691848 /* ClientConfiguration.swift in Sources */, 32DCAD9F3A6B6101B78F0918 /* AttesterApi.swift in Sources */, 32DCA860CF726C3BE61E66BF /* BackendApi.swift in Sources */, 5A39F430239EC396001F4607 /* SettingsViewDecorator.swift in Sources */, diff --git a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift index 1a279827e..c48af0a6a 100644 --- a/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/Settings List/SettingsViewController.swift @@ -32,7 +32,7 @@ final class SettingsViewController: TableNodeViewController { } } - static func filtered(with rules: OrganisationalRules) -> [SettingsMenuItem] { + static func filtered(with rules: ClientConfiguration) -> [SettingsMenuItem] { var cases = SettingsMenuItem.allCases if !rules.canBackupKeys { @@ -45,18 +45,18 @@ final class SettingsViewController: TableNodeViewController { private let decorator: SettingsViewDecoratorType private let currentUser: User? - private let organisationalRules: OrganisationalRules + private let clientConfiguration: ClientConfiguration private let rows: [SettingsMenuItem] init( decorator: SettingsViewDecoratorType = SettingsViewDecorator(), currentUser: User? = DataService.shared.currentUser, - organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService() + clientConfigurationService: ClientConfigurationServiceType = ClientConfigurationService() ) { self.decorator = decorator self.currentUser = currentUser - self.organisationalRules = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() - self.rows = SettingsMenuItem.filtered(with: self.organisationalRules) + self.clientConfiguration = clientConfigurationService.getSavedClientConfigurationForCurrentUser() + self.rows = SettingsMenuItem.filtered(with: self.clientConfiguration) super.init(node: TableNode()) } @@ -121,7 +121,7 @@ extension SettingsViewController { viewController = ContactsListViewController() case .backups: guard let currentUser = currentUser, - organisationalRules.canBackupKeys else { + clientConfiguration.canBackupKeys else { viewController = nil return } diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index 47f456153..eda7551df 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -54,9 +54,8 @@ final class SetupInitialViewController: TableNodeViewController { private let user: UserId private let router: GlobalRouterType private let decorator: SetupViewDecorator - private let organisationalRules: OrganisationalRules + private let clientConfiguration: ClientConfiguration private let emailKeyManagerApi: EmailKeyManagerApiType - private let clientConfigurationService: ClientConfigurationServiceType private lazy var logger = Logger.nested(in: Self.self, with: .setup) @@ -65,17 +64,15 @@ final class SetupInitialViewController: TableNodeViewController { backupService: BackupServiceType = BackupService(), router: GlobalRouterType = GlobalRouter(), decorator: SetupViewDecorator = SetupViewDecorator(), - organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService(), - emailKeyManagerApi: EmailKeyManagerApiType = EmailKeyManagerApi(), - clientConfigurationService: ClientConfigurationServiceType = ClientConfigurationService() + clientConfigurationService: ClientConfigurationServiceType = ClientConfigurationService(), + emailKeyManagerApi: EmailKeyManagerApiType = EmailKeyManagerApi() ) { self.user = user self.backupService = backupService self.router = router self.decorator = decorator - self.organisationalRules = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() + self.clientConfiguration = clientConfigurationService.getSavedClientConfigurationForCurrentUser() self.emailKeyManagerApi = emailKeyManagerApi - self.clientConfigurationService = clientConfigurationService super.init(node: TableNode()) } @@ -117,7 +114,7 @@ extension SetupInitialViewController { } private func searchKeyBackupsInInbox() { - if !organisationalRules.canBackupKeys { + if !clientConfiguration.canBackupKeys { logger.logInfo("Skipping backups searching because canBackupKeys == false") proceedToSetupWith(keys: []) return @@ -144,7 +141,7 @@ extension SetupInitialViewController { } private func decideIfEKMshouldBeUsed() { - switch clientConfigurationService.checkShouldUseEKM() { + switch clientConfiguration.checkUsesEKM() { case .usesEKM: state = .fetchingKeysFromEKM case .doesNotUseEKM: diff --git a/FlowCrypt/Functionality/Error Handling/AppErr.swift b/FlowCrypt/Functionality/Error Handling/AppErr.swift index d075abaf7..75ea46aee 100644 --- a/FlowCrypt/Functionality/Error Handling/AppErr.swift +++ b/FlowCrypt/Functionality/Error Handling/AppErr.swift @@ -19,6 +19,7 @@ enum AppErr: Error { case user(String) /// useful in Promises when you want to cancel execution without showing any error (eg after user clicks cancel button) case silentAbort + case noCurrentUser case general(String) var userMessage: String { @@ -40,6 +41,7 @@ extension AppErr: Equatable { case (.user, .user): return true case (.silentAbort, .silentAbort): return true case (.general, .general): return true + case (.noCurrentUser, .noCurrentUser): return true default: return false } } diff --git a/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift b/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift index c5134fb95..15e877e54 100644 --- a/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift +++ b/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift @@ -13,8 +13,8 @@ protocol EnterpriseServerApiType { func getActiveFesUrl(for email: String) -> Promise func getActiveFesUrlForCurrentUser() -> Promise - func getClientConfiguration(for email: String) -> Promise - func getClientConfigurationForCurrentUser() -> Promise + func getClientConfiguration(for email: String) -> Promise + func getClientConfigurationForCurrentUser() -> Promise } enum EnterpriseServerApiError: Error { @@ -47,9 +47,8 @@ class EnterpriseServerApi: EnterpriseServerApiType { static let serviceNeededValue = "enterprise-server" } - private struct ClientConfigurationContainer: Codable { - let clientConfiguration: ClientConfiguration - + private struct ClientConfigurationResponse: Codable { + let clientConfiguration: RawClientConfiguration private enum CodingKeys: String, CodingKey { case clientConfiguration } @@ -110,8 +109,8 @@ class EnterpriseServerApi: EnterpriseServerApiType { .recoverFromTimeOut(result: nil) } - func getClientConfiguration(for email: String) -> Promise { - Promise { resolve, reject in + func getClientConfiguration(for email: String) -> Promise { + Promise { resolve, reject in guard let userDomain = email.recipientDomain else { reject(EnterpriseServerApiError.emailFormat) return @@ -137,7 +136,7 @@ class EnterpriseServerApi: EnterpriseServerApiType { decoder.keyDecodingStrategy = .convertFromSnakeCase guard let clientConfiguration = (try? decoder.decode( - ClientConfigurationContainer.self, + ClientConfigurationResponse.self, from: safeReponse.data ))?.clientConfiguration else { @@ -148,9 +147,9 @@ class EnterpriseServerApi: EnterpriseServerApiType { } } - func getClientConfigurationForCurrentUser() -> Promise { + func getClientConfigurationForCurrentUser() -> Promise { guard let email = DataService.shared.currentUser?.email else { - return Promise { _, _ in + return Promise { _, _ in fatalError("User has to be set while getting client configuration") } } diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index 9438d8f13..0f4e9e87a 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -98,8 +98,8 @@ struct AppStartup { private func getUserOrgRulesIfNeeded() throws { if DataService.shared.isLoggedIn { - let service = OrganisationalRulesService() - _ = try awaitPromise(service.fetchOrganisationalRulesForCurrentUser()) + let service = ClientConfigurationService() + _ = try awaitPromise(service.fetchClientConfigurationForCurrentUser()) } } diff --git a/FlowCrypt/Models/OrganisationalRule.swift b/FlowCrypt/Functionality/Services/Client Configuration Service/ClientConfiguration.swift similarity index 55% rename from FlowCrypt/Models/OrganisationalRule.swift rename to FlowCrypt/Functionality/Services/Client Configuration Service/ClientConfiguration.swift index d2e247be4..fcd5ef061 100644 --- a/FlowCrypt/Models/OrganisationalRule.swift +++ b/FlowCrypt/Functionality/Services/Client Configuration Service/ClientConfiguration.swift @@ -11,42 +11,42 @@ import Foundation /// Organisational rules, set domain-wide, and delivered from FlowCrypt Backend /// These either enforce, alter or forbid various behavior to fit customer needs -class OrganisationalRules { +class ClientConfiguration { - let clientConfiguration: ClientConfiguration + let raw: RawClientConfiguration - init(clientConfiguration: ClientConfiguration) { - self.clientConfiguration = clientConfiguration + init(raw: RawClientConfiguration) { + self.raw = raw } /// Internal company SKS-like public key server to trust above Attester var customSksPubkeyServer: String? { - clientConfiguration.customKeyserverUrl + raw.customKeyserverUrl } /// an internal org FlowCrypt Email Key Manager instance, can manage both public and private keys /// use this method when using for PRV sync var keyManagerUrlForPrivateKeys: String? { - clientConfiguration.keyManagerUrl + raw.keyManagerUrl } /// an internal org FlowCrypt Email Key Manager instance, can manage both public and private keys /// use this method when using for PUB sync var keyManagerUrlForPublicKeys: String? { - (clientConfiguration.flags ?? []).contains(.noKeyManagerPubLookup) + (raw.flags ?? []).contains(.noKeyManagerPubLookup) ? nil - : clientConfiguration.keyManagerUrl + : raw.keyManagerUrl } /// use when finding out if EKM is in use, to change functionality without actually neededing the EKM var isUsingKeyManager: Bool { - clientConfiguration.keyManagerUrl != nil + raw.keyManagerUrl != nil } /// Check if key manager url set properly var isKeyManagerUrlValid: Bool { // check for empty string - guard let urlString = clientConfiguration.keyManagerUrl, urlString.isNotEmpty else { + guard let urlString = raw.keyManagerUrl, urlString.isNotEmpty else { return false } // check is url can be configured @@ -55,43 +55,43 @@ class OrganisationalRules { /// Enforce a key algo for keygen, eg rsa2048,rsa4096,curve25519 var enforcedKeygenAlgo: String? { - clientConfiguration.enforceKeygenAlgo + raw.enforceKeygenAlgo } /// Some orgs want to have newly generated keys include self-signatures that expire some time in the future. var getEnforcedKeygenExpirationMonths: Int? { - clientConfiguration.enforceKeygenExpireMonths + raw.enforceKeygenExpireMonths } /// Some orgs expect 100% of their private keys to be imported from elsewhere (and forbid keygen in the extension) var canCreateKeys: Bool { - !(clientConfiguration.flags ?? []).contains(.noPrivateKeyCreate) + !(raw.flags ?? []).contains(.noPrivateKeyCreate) } /// Some orgs want to forbid backing up of public keys (such as inbox or other methods) var canBackupKeys: Bool { - !(clientConfiguration.flags ?? []).contains(.noPrivateKeyBackup) + !(raw.flags ?? []).contains(.noPrivateKeyBackup) } /// (normally, during setup, if a public key is submitted to Attester and there is /// a conflicting key already submitted, the issue will be skipped) /// Some orgs want to make sure that their public key gets submitted to attester and conflict errors are NOT ignored: var mustSubmitAttester: Bool { - (clientConfiguration.flags ?? []).contains(.enforceAttesterSubmit) + (raw.flags ?? []).contains(.enforceAttesterSubmit) } /// Normally, during setup, "remember pass phrase" is unchecked /// This option will cause "remember pass phrase" option to be checked by default /// This behavior is also enabled as a byproduct of PASS_PHRASE_QUIET_AUTOGEN var shouldRememberPassphraseByDefault: Bool { - (clientConfiguration.flags ?? []).contains(.defaultRememberPassphrase) || mustAutogenPassPhraseQuietly + (raw.flags ?? []).contains(.defaultRememberPassphrase) || mustAutogenPassPhraseQuietly } /// This is to be used for customers who run their own FlowCrypt Email Key Manager /// 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 { - guard let flags = clientConfiguration.flags else { + guard let flags = raw.flags else { return false } @@ -100,6 +100,7 @@ class OrganisationalRules { } if keyManagerUrlForPrivateKeys == nil { + // todo - should not be a fatal error, since the input comes from external sources fatalError("Wrong org rules config: using PRV_AUTOIMPORT_OR_AUTOGEN without key_manager_url") } return true @@ -110,18 +111,18 @@ class OrganisationalRules { /// The pass phrase will NOT be displayed to user, and it will never be asked of the user /// This creates the smoothest user experience, for organisations that use full-disk-encryption and don't need pass phrase protection var mustAutogenPassPhraseQuietly: Bool { - (clientConfiguration.flags ?? []).contains(.passphraseQuietAutogen) + (raw.flags ?? []).contains(.passphraseQuietAutogen) } /// Some orgs prefer to forbid publishing public keys publicly var canSubmitPubToAttester: Bool { - !(clientConfiguration.flags ?? []).contains(.noAttesterSubmit) + !(raw.flags ?? []).contains(.noAttesterSubmit) } /// Some orgs have a list of email domains where they do NOT want such emails to be looked up on public sources (such as Attester) /// This is because they already have other means to obtain public keys for these domains, such as from their own internal keyserver func canLookupThisRecipientOnAttester(recipient email: String) throws -> Bool { - let disallowedDomains = clientConfiguration.disallowAttesterSearchForDomains ?? [] + let disallowedDomains = raw.disallowAttesterSearchForDomains ?? [] if disallowedDomains.contains("*") { return false @@ -137,19 +138,78 @@ class OrganisationalRules { /// -> enforcing that submitted keys match customer key server /// Until the newer endpoint is ready, this flag will point users in those orgs to the original endpoint var useLegacyAttesterSubmit: Bool { - (clientConfiguration.flags ?? []).contains(.useLegacyAttesterSubmit) + (raw.flags ?? []).contains(.useLegacyAttesterSubmit) } /// With this option, sent messages won't have any comment/version in armor, imported keys get imported without armor var shouldHideArmorMeta: Bool { - (clientConfiguration.flags ?? []).contains(.hideArmorMeta) + (raw.flags ?? []).contains(.hideArmorMeta) } var forbidStoringPassPhrase: Bool { - (clientConfiguration.flags ?? []).contains(.forbidStoringPassphrase) + (raw.flags ?? []).contains(.forbidStoringPassphrase) } var keyManagerUrlString: String? { - clientConfiguration.keyManagerUrl?.addTrailingSlashIfNeeded + raw.keyManagerUrl?.addTrailingSlashIfNeeded + } + + /** + * 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 in use because isUsingKeyManager == true and other client configs are consistent with it (result: no error, use EKM) + * 2) EKM is in use because isUsingKeyManager == true and other client configs are NOT consistent with it (result: error) + * 3) EKM is not in use because isUsingKeyManager == false (result: normal login flow) + */ + func checkUsesEKM() -> CheckUsesEKMResult { + guard isUsingKeyManager else { + return .doesNotUseEKM + } + guard isKeyManagerUrlValid else { + return .inconsistentClientConfiguration(checkError: .urlNotValid) + } + guard mustAutoImportOrAutogenPrvWithKeyManager else { + return .inconsistentClientConfiguration(checkError: .autoImportOrAutogenPrvWithKeyManager) + } + guard !mustAutogenPassPhraseQuietly else { + return .inconsistentClientConfiguration(checkError: .autogenPassPhraseQuietly) + } + guard forbidStoringPassPhrase else { + return .inconsistentClientConfiguration(checkError: .forbidStoringPassPhrase) + } + guard !mustSubmitAttester else { + return .inconsistentClientConfiguration(checkError: .mustSubmitAttester) + } + return .usesEKM + } + + enum CheckUsesEKMResult: Equatable { + case usesEKM + case inconsistentClientConfiguration(checkError: InconsistentClientConfigurationError) + case doesNotUseEKM + } + + enum InconsistentClientConfigurationError: 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 + } + } } + } diff --git a/FlowCrypt/Functionality/Services/Client Configuration Service/ClientConfigurationService.swift b/FlowCrypt/Functionality/Services/Client Configuration Service/ClientConfigurationService.swift new file mode 100644 index 000000000..7b2a7368d --- /dev/null +++ b/FlowCrypt/Functionality/Services/Client Configuration Service/ClientConfigurationService.swift @@ -0,0 +1,68 @@ +// +// OrganisationalRulesService.swift +// FlowCrypt +// +// Created by Yevhen Kyivskyi on 18.06.2021. +// Copyright © 2017-present FlowCrypt a. s. All rights reserved. +// + +import FlowCryptCommon +import Foundation +import Promises + +protocol ClientConfigurationServiceType { + func fetchClientConfigurationForCurrentUser() -> Promise + func getSavedClientConfigurationForCurrentUser() -> ClientConfiguration +} + +final class ClientConfigurationService { + + private let server: EnterpriseServerApiType + private let local: LocalClientConfigurationType + private let getCurrentUserEmail: () -> (String?) + + init( + server: EnterpriseServerApiType = EnterpriseServerApi(), + local: LocalClientConfigurationType = LocalClientConfiguration(), + getCurrentUserEmail: @autoclosure @escaping () -> (String?) = DataService.shared.currentUser?.email + ) { + self.server = server + self.local = local + self.getCurrentUserEmail = getCurrentUserEmail + } +} + +// MARK: - OrganisationalRulesServiceType +extension ClientConfigurationService: ClientConfigurationServiceType { + + func fetchClientConfigurationForCurrentUser() -> Promise { + guard let currentUserEmail = getCurrentUserEmail() else { + return Promise { _, reject in + reject(AppErr.noCurrentUser) + } + } + return Promise { [weak self] resolve, _ in + guard let self = self else { throw AppErr.nilSelf } + let raw = try awaitPromise( + self.server.getClientConfiguration(for: currentUserEmail) + ) + self.local.save(raw: raw) + resolve(ClientConfiguration(raw: raw)) + } + .recover { [weak self] error -> ClientConfiguration in + guard let self = self else { throw AppErr.nilSelf } + guard let raw = self.local.load() else { + throw error + } + return ClientConfiguration(raw: raw) + } + } + + func getSavedClientConfigurationForCurrentUser() -> ClientConfiguration { + guard let raw = self.local.load() else { + fatalError("There should not be a user without OrganisationalRules") + } + + return ClientConfiguration(raw: raw) + } +} diff --git a/FlowCrypt/Functionality/Services/Client Configuration Service/LocalClientConfiguration.swift b/FlowCrypt/Functionality/Services/Client Configuration Service/LocalClientConfiguration.swift new file mode 100644 index 000000000..0e894ef9d --- /dev/null +++ b/FlowCrypt/Functionality/Services/Client Configuration Service/LocalClientConfiguration.swift @@ -0,0 +1,47 @@ +// +// LocalClientConfiguration.swift +// FlowCrypt +// +// Created by Yevhen Kyivskyi on 18.06.2021. +// Copyright © 2017-present FlowCrypt a. s. All rights reserved. +// + +import Foundation +import Promises +import RealmSwift +import IDZSwiftCommonCrypto + +protocol LocalClientConfigurationType { + func load() -> RawClientConfiguration? + func remove() + func save(raw: RawClientConfiguration) +} + +struct LocalClientConfiguration { + let cache: EncryptedCacheService + init(encryptedStorage: EncryptedStorageType = EncryptedStorage()) { + self.cache = EncryptedCacheService(encryptedStorage: encryptedStorage) + } +} + +extension LocalClientConfiguration: LocalClientConfigurationType { + func load() -> RawClientConfiguration? { + // (tom) todo - should we not guard here? +// guard let user = cache.encryptedStorage.activeUser else { +// fatalError("Internal inconsistency, no active user when loading client configuration") +// } + RawClientConfiguration(cache.getAllForActiveUser()?.first) + } + + func remove() { + // (tom) todo - should we not guard here? + cache.removeAllForActiveUser() + } + + func save(raw: RawClientConfiguration) { + guard let user = cache.encryptedStorage.activeUser else { + fatalError("Internal inconsistency, no active user when saving client configuration") + } + cache.save(ClientConfigurationObject(raw, user: user)) + } +} diff --git a/FlowCrypt/Functionality/Services/CacheService.swift b/FlowCrypt/Functionality/Services/EncryptedCacheService.swift similarity index 97% rename from FlowCrypt/Functionality/Services/CacheService.swift rename to FlowCrypt/Functionality/Services/EncryptedCacheService.swift index 7d2d37f12..1aeb5dd7a 100644 --- a/FlowCrypt/Functionality/Services/CacheService.swift +++ b/FlowCrypt/Functionality/Services/EncryptedCacheService.swift @@ -17,7 +17,7 @@ protocol CachedObject: Object { } // MARK: - Cache -final class CacheService { +final class EncryptedCacheService { let encryptedStorage: EncryptedStorageType var realm: Realm { encryptedStorage.storage } diff --git a/FlowCrypt/Functionality/Services/Folders Services/LocalFoldersProvider.swift b/FlowCrypt/Functionality/Services/Folders Services/LocalFoldersProvider.swift index 593ec74f6..398c076dd 100644 --- a/FlowCrypt/Functionality/Services/Folders Services/LocalFoldersProvider.swift +++ b/FlowCrypt/Functionality/Services/Folders Services/LocalFoldersProvider.swift @@ -16,10 +16,10 @@ protocol LocalFoldersProviderType { } struct LocalFoldersProvider: LocalFoldersProviderType { - private let folderCache: CacheService + private let folderCache: EncryptedCacheService init(encryptedStorage: EncryptedStorageType = EncryptedStorage()) { - self.folderCache = CacheService(encryptedStorage: encryptedStorage) + self.folderCache = EncryptedCacheService(encryptedStorage: encryptedStorage) } func fetchFolders() -> [FolderViewModel] { diff --git a/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/GmailService+folders.swift b/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/GmailService+folders.swift index 42e52bbdd..e04451302 100644 --- a/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/GmailService+folders.swift +++ b/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/GmailService+folders.swift @@ -41,7 +41,7 @@ extension GmailService: RemoteFoldersProviderType { return nil } guard identifier.range(of: "CATEGORY_", options: .caseInsensitive) == nil else { - logger.logInfo("Skip category label with \(label.identifier ?? "")") + logger.logDebug("Skip category label with \(label.identifier ?? "")") return nil } return label diff --git a/FlowCrypt/Functionality/Services/Local Pub Key Services/LocalContactsProvider.swift b/FlowCrypt/Functionality/Services/Local Pub Key Services/LocalContactsProvider.swift index f36a367b2..88ddbd2d3 100644 --- a/FlowCrypt/Functionality/Services/Local Pub Key Services/LocalContactsProvider.swift +++ b/FlowCrypt/Functionality/Services/Local Pub Key Services/LocalContactsProvider.swift @@ -19,14 +19,14 @@ protocol LocalContactsProviderType: PublicKeyProvider { } struct LocalContactsProvider { - private let localContactsCache: CacheService + private let localContactsCache: EncryptedCacheService let core: Core init( encryptedStorage: EncryptedStorageType = EncryptedStorage(), core: Core = .shared ) { - self.localContactsCache = CacheService(encryptedStorage: encryptedStorage) + self.localContactsCache = EncryptedCacheService(encryptedStorage: encryptedStorage) self.core = core } } diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationProvider.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationProvider.swift deleted file mode 100644 index 48ffaafb9..000000000 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationProvider.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// ClientConfigurationProvider.swift -// FlowCrypt -// -// Created by Yevhen Kyivskyi on 18.06.2021. -// Copyright © 2017-present FlowCrypt a. s. All rights reserved. -// - -import Foundation -import Promises -import RealmSwift - -protocol ClientConfigurationProviderType { - func fetch() -> ClientConfiguration? - func removeClientConfiguration() - func save(clientConfiguration: ClientConfiguration) -} - -struct ClientConfigurationProvider { - let clientConfigurationCache: CacheService - - init(encryptedStorage: EncryptedStorageType = EncryptedStorage()) { - self.clientConfigurationCache = CacheService(encryptedStorage: encryptedStorage) - } -} - -extension ClientConfigurationProvider: ClientConfigurationProviderType { - func fetch() -> ClientConfiguration? { - ClientConfiguration(clientConfigurationCache.getAllForActiveUser()?.first) - } - - func removeClientConfiguration() { - clientConfigurationCache.removeAllForActiveUser() - } - - func save(clientConfiguration: ClientConfiguration) { - guard let user = clientConfigurationCache.encryptedStorage.activeUser else { - assertionFailure("Internal inconsistency. Missed client configuration") - return - } - clientConfigurationCache.save(ClientConfigurationObject(clientConfiguration, user: user)) - } -} diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift deleted file mode 100644 index 737a89dcf..000000000 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationService.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// OrgRulesSignInPersmissionsService.swift -// FlowCrypt -// -// Created by Yevhen Kyivskyi on 15.07.2021. -// Copyright © 2017-present FlowCrypt a. s. All rights reserved. -// - -// swiftlint:disable line_length -protocol ClientConfigurationServiceType { - func checkShouldUseEKM() -> ClientConfigurationService.CheckForUsingEKMResult -} - -class ClientConfigurationService: ClientConfigurationServiceType { - - private let organisationalRulesService: OrganisationalRulesServiceType - - init(organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService()) { - self.organisationalRulesService = organisationalRulesService - } - - /** - * 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 = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() - - guard organisationalRules.isUsingKeyManager else { - return .doesNotUseEKM - } - guard organisationalRules.isKeyManagerUrlValid else { - return .inconsistentClientConfiguration(checkError: .urlNotValid) - } - if !organisationalRules.mustAutoImportOrAutogenPrvWithKeyManager { - return .inconsistentClientConfiguration(checkError: .autoImportOrAutogenPrvWithKeyManager) - } - if organisationalRules.mustAutogenPassPhraseQuietly { - return .inconsistentClientConfiguration(checkError: .autogenPassPhraseQuietly) - } - if !organisationalRules.forbidStoringPassPhrase { - return .inconsistentClientConfiguration(checkError: .forbidStoringPassPhrase) - } - if organisationalRules.mustSubmitAttester { - 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 deleted file mode 100644 index 1c84439f8..000000000 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceResults.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// ClientConfigurationServiceResults.swift -// FlowCrypt -// -// Created by Yevhen Kyivskyi on 22.07.2021. -// Copyright © 2017-present FlowCrypt a. s. All rights reserved. -// - -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: Equatable { - case usesEKM - 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 deleted file mode 100644 index 8a9bacf6d..000000000 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesService.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// OrganisationalRulesService.swift -// FlowCrypt -// -// Created by Yevhen Kyivskyi on 18.06.2021. -// Copyright © 2017-present FlowCrypt a. s. All rights reserved. -// - -import FlowCryptCommon -import Foundation -import Promises - -protocol OrganisationalRulesServiceType { - func fetchOrganisationalRulesForCurrentUser() -> Promise - func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules -} - -final class OrganisationalRulesService { - - private let enterpriseServerApi: EnterpriseServerApiType - private let clientConfigurationProvider: ClientConfigurationProviderType - private let isCurrentUserExist: () -> (String?) - - init( - enterpriseServerApi: EnterpriseServerApiType = EnterpriseServerApi(), - clientConfigurationProvider: ClientConfigurationProviderType = ClientConfigurationProvider(), - isCurrentUserExist: @autoclosure @escaping () -> (String?) = DataService.shared.currentUser?.email - ) { - self.enterpriseServerApi = enterpriseServerApi - self.clientConfigurationProvider = clientConfigurationProvider - self.isCurrentUserExist = isCurrentUserExist - } -} - -// MARK: - OrganisationalRulesServiceType -extension OrganisationalRulesService: OrganisationalRulesServiceType { - - func fetchOrganisationalRulesForCurrentUser() -> Promise { - guard let currentUserEmail = isCurrentUserExist() else { - return Promise { _, reject in - reject(OrganisationalRulesServiceError.noCurrentUser) - } - } - return fetchOrganisationalRules(for: currentUserEmail) - } - - private func fetchOrganisationalRules(for email: String) -> Promise { - Promise { [weak self] resolve, _ in - guard let self = self else { throw AppErr.nilSelf } - - let clientConfigurationResponse = try awaitPromise( - self.enterpriseServerApi.getClientConfiguration(for: email) - ) - - let organisationalRules = OrganisationalRules( - clientConfiguration: clientConfigurationResponse - ) - - self.clientConfigurationProvider.save(clientConfiguration: clientConfigurationResponse) - - resolve(organisationalRules) - } - .recover { [weak self] error -> OrganisationalRules in - guard let self = self else { throw AppErr.nilSelf } - guard let clientConfig = self.clientConfigurationProvider.fetch() else { - throw error - } - return OrganisationalRules(clientConfiguration: clientConfig) - } - } - - func getSavedOrganisationalRulesForCurrentUser() -> OrganisationalRules { - guard let configuration = self.clientConfigurationProvider.fetch() else { - fatalError("There should not be a user without OrganisationalRules") - } - - return OrganisationalRules(clientConfiguration: configuration) - } -} diff --git a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesServiceError.swift b/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesServiceError.swift deleted file mode 100644 index 94b53d194..000000000 --- a/FlowCrypt/Functionality/Services/Organisational Rules Service/OrganisationalRulesServiceError.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// OrganisationalRulesServiceError.swift -// FlowCrypt -// -// Created by Yevhen Kyivskyi on 18.06.2021. -// Copyright © 2017-present FlowCrypt a. s. All rights reserved. -// - -import Foundation - -enum OrganisationalRulesServiceError: Error { - case noCurrentUser - case parse - case emailFormat -} diff --git a/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift b/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift index 0d8de60f0..a269fb8d0 100644 --- a/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift +++ b/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift @@ -39,19 +39,19 @@ extension EmailKeyManagerApiError: LocalizedError { /// https://flowcrypt.com/docs/technical/enterprise/email-deployment-overview.html class EmailKeyManagerApi: EmailKeyManagerApiType { - private let organisationalRulesService: OrganisationalRulesServiceType + private let clientConfigurationService: ClientConfigurationServiceType private let core: Core init( - organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService(), + clientConfigurationService: ClientConfigurationServiceType = ClientConfigurationService(), core: Core = .shared ) { - self.organisationalRulesService = organisationalRulesService + self.clientConfigurationService = clientConfigurationService self.core = core } func getPrivateKeysUrlString() -> String? { - guard let keyManagerUrlString = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser().keyManagerUrlString else { + guard let keyManagerUrlString = clientConfigurationService.getSavedClientConfigurationForCurrentUser().keyManagerUrlString else { return nil } return "\(keyManagerUrlString)v1/keys/private" diff --git a/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift b/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift index 38940dba6..aa2a7aba5 100644 --- a/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift +++ b/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift @@ -30,14 +30,14 @@ final class AttesterApi: AttesterApiType { } private let core: Core - private let organisationalRules: OrganisationalRules + private let clientConfiguration: ClientConfiguration init( core: Core = .shared, - organisationalRulesService: OrganisationalRulesServiceType = OrganisationalRulesService() + clientConfigurationService: ClientConfigurationServiceType = ClientConfigurationService() ) { self.core = core - self.organisationalRules = organisationalRulesService.getSavedOrganisationalRulesForCurrentUser() + self.clientConfiguration = clientConfigurationService.getSavedClientConfigurationForCurrentUser() } private func urlPub(emailOrLongid: String) -> String { @@ -53,7 +53,7 @@ extension AttesterApi { Promise { [weak self] () -> [KeyDetails] in guard let self = self else { throw AppErr.nilSelf } - if !(try self.organisationalRules.canLookupThisRecipientOnAttester(recipient: email)) { + if !(try self.clientConfiguration.canLookupThisRecipientOnAttester(recipient: email)) { return [] } diff --git a/FlowCrypt/Models/ClientConfiguration.swift b/FlowCrypt/Models/RawClientConfiguration.swift similarity index 94% rename from FlowCrypt/Models/ClientConfiguration.swift rename to FlowCrypt/Models/RawClientConfiguration.swift index f043bb93e..c22ee7629 100644 --- a/FlowCrypt/Models/ClientConfiguration.swift +++ b/FlowCrypt/Models/RawClientConfiguration.swift @@ -29,7 +29,7 @@ enum ClientConfigurationFlag: String, Codable { } } -struct ClientConfiguration: Codable, Equatable { +struct RawClientConfiguration: Codable, Equatable { let flags: [ClientConfigurationFlag]? let customKeyserverUrl: String? @@ -56,9 +56,9 @@ struct ClientConfiguration: Codable, Equatable { } // MARK: - Empty model -extension ClientConfiguration { - static var empty: ClientConfiguration { - return ClientConfiguration( +extension RawClientConfiguration { + static var empty: RawClientConfiguration { + return RawClientConfiguration( flags: [], customKeyserverUrl: nil, keyManagerUrl: nil, @@ -70,7 +70,7 @@ extension ClientConfiguration { } // MARK: - Map from realm model -extension ClientConfiguration { +extension RawClientConfiguration { init?(_ object: ClientConfigurationObject?) { guard let unwrappedObject = object else { return nil diff --git a/FlowCrypt/Models/Realm Models/ClientConfigurationObject.swift b/FlowCrypt/Models/Realm Models/ClientConfigurationObject.swift index 75d436ae0..d4ea0a24d 100644 --- a/FlowCrypt/Models/Realm Models/ClientConfigurationObject.swift +++ b/FlowCrypt/Models/Realm Models/ClientConfigurationObject.swift @@ -45,7 +45,7 @@ final class ClientConfigurationObject: Object { } convenience init( - _ clientConfiguration: ClientConfiguration, + _ clientConfiguration: RawClientConfiguration, user: UserObject ) { self.init( diff --git a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/OrganisationalRulesServiceTests.swift b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/ClientConfigurationServiceTests.swift similarity index 64% rename from FlowCryptAppTests/Functionality/Services/Organisational Rules Service/OrganisationalRulesServiceTests.swift rename to FlowCryptAppTests/Functionality/Services/Client Configuration Service/ClientConfigurationServiceTests.swift index 21b5b2cda..5ec74116c 100644 --- a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/OrganisationalRulesServiceTests.swift +++ b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/ClientConfigurationServiceTests.swift @@ -1,5 +1,5 @@ // -// OrganisationalRulesServiceTests.swift +// ClientConfigurationServiceTests.swift // FlowCryptAppTests // // Created by Anton Kharchevskyi on 20.09.2021. @@ -10,38 +10,38 @@ import XCTest import Promises @testable import FlowCrypt -class OrganisationalRulesServiceTests: XCTestCase { +class ClientConfigurationServiceTests: XCTestCase { - var sut: OrganisationalRulesService! + var sut: ClientConfigurationService! var enterpriseServerApi: EnterpriseServerApiMock! - var clientConfigurationProvider: ClientConfigurationProviderMock! + var localClientConfigurationProvider: LocalClientConfigurationMock! var isCurrentUserExistMock: CurrentUserEmailMock! override func setUp() { super.setUp() enterpriseServerApi = EnterpriseServerApiMock() - clientConfigurationProvider = ClientConfigurationProviderMock() + localClientConfigurationProvider = LocalClientConfigurationMock() isCurrentUserExistMock = CurrentUserEmailMock() - sut = OrganisationalRulesService( - enterpriseServerApi: enterpriseServerApi, - clientConfigurationProvider: clientConfigurationProvider, - isCurrentUserExist: self.isCurrentUserExistMock.currentUserEmail() + sut = ClientConfigurationService( + server: enterpriseServerApi, + local: localClientConfigurationProvider, + getCurrentUserEmail: self.isCurrentUserExistMock.currentUserEmail() ) DispatchQueue.promises = .global() } func testGetSavedOrganisationalRulesForCurrentUser() { - let expectedConfiguration = ClientConfiguration(keyManagerUrl: "https://ekm.example.com") - clientConfigurationProvider.fetchCall = { + let expectedConfiguration = RawClientConfiguration(keyManagerUrl: "https://ekm.example.com") + localClientConfigurationProvider.fetchCall = { expectedConfiguration } - let organisationalRules = sut.getSavedOrganisationalRulesForCurrentUser() - XCTAssert(clientConfigurationProvider.fetchCount == 1) - XCTAssert(clientConfigurationProvider.fetchInvoked == true) - XCTAssert(organisationalRules.clientConfiguration == expectedConfiguration) + let clientConfiguration = sut.getSavedClientConfigurationForCurrentUser() + XCTAssert(localClientConfigurationProvider.fetchCount == 1) + XCTAssert(localClientConfigurationProvider.fetchInvoked == true) + XCTAssert(clientConfiguration.raw == expectedConfiguration) } func testFetchOrganisationalRulesForCurrentUserNil() { @@ -49,11 +49,11 @@ class OrganisationalRulesServiceTests: XCTestCase { isCurrentUserExistMock.currentUserEmailCall = { nil } - sut.fetchOrganisationalRulesForCurrentUser() - .then(on: .main) { _ -> Promise in + sut.fetchClientConfigurationForCurrentUser() + .then(on: .main) { _ -> Promise in XCTFail() - let result: Result = .failure(.some) - return Promise.resolveAfter(with: result) + let result: Result = .failure(.some) + return Promise.resolveAfter(with: result) } .catch(on: .main) { error in expectation.fulfill() @@ -91,18 +91,18 @@ class OrganisationalRulesServiceTests: XCTestCase { clientConfigurationProviderSaveCountCall ] - let expectedClientConfiguration = ClientConfiguration(keyManagerUrl: "https://ekm.example.com") + let expectedClientConfiguration = RawClientConfiguration(keyManagerUrl: "https://ekm.example.com") // (String) -> (Result) self.enterpriseServerApi.getClientConfigurationCall = { email in if email == "example@flowcrypt.test" { getClientConfigurationCallExpectation.fulfill() } - return Result.success(expectedClientConfiguration) + return Result.success(expectedClientConfiguration) } // (ClientConfiguration) -> (Void) - self.clientConfigurationProvider.saveCall = { clientConfiguration in + self.localClientConfigurationProvider.saveCall = { clientConfiguration in if clientConfiguration.keyManagerUrl == expectedClientConfiguration.keyManagerUrl { clientConfigurationProviderSaveCall.fulfill() } @@ -112,8 +112,8 @@ class OrganisationalRulesServiceTests: XCTestCase { "example@flowcrypt.test" } - sut.fetchOrganisationalRulesForCurrentUser() - .then(on: .main) { orgRules -> Promise in + sut.fetchClientConfigurationForCurrentUser() + .then(on: .main) { orgRules -> Promise in fetchOrganisationalRulesExpectation.fulfill() // test calls for enterpriseServerApi @@ -123,12 +123,12 @@ class OrganisationalRulesServiceTests: XCTestCase { if self.enterpriseServerApi.getClientConfigurationCount == 1 { getClientConfigurationCountExpectation.fulfill() } - if self.clientConfigurationProvider.saveCount == 1 { + if self.localClientConfigurationProvider.saveCount == 1 { clientConfigurationProviderSaveCountCall.fulfill() } - let result: Result = .success(orgRules) - return Promise.resolveAfter(with: result) + let result: Result = .success(orgRules) + return Promise.resolveAfter(with: result) } .catch(on: .main) { error in XCTFail() @@ -144,7 +144,7 @@ class OrganisationalRulesServiceTests: XCTestCase { fetchOrganisationalRulesForCurrentUserExpectation ] - let expectedClientConfiguration = ClientConfiguration(keyManagerUrl: "https://ekm.example.com") + let expectedClientConfiguration = RawClientConfiguration(keyManagerUrl: "https://ekm.example.com") self.enterpriseServerApi.getClientConfigurationCall = { email in .failure(MockError.some) @@ -154,21 +154,21 @@ class OrganisationalRulesServiceTests: XCTestCase { "example@flowcrypt.test" } - clientConfigurationProvider.fetchCall = { + localClientConfigurationProvider.fetchCall = { expectedClientConfiguration } - sut.fetchOrganisationalRulesForCurrentUser() - .then(on: .main) { organisationalRules -> Promise in - if organisationalRules.clientConfiguration == expectedClientConfiguration { + sut.fetchClientConfigurationForCurrentUser() + .then(on: .main) { clientConfiguration -> Promise in + if clientConfiguration.raw == expectedClientConfiguration { fetchOrganisationalRulesForCurrentUserExpectation.fulfill() } - let result: Result = .success(organisationalRules) - return Promise.resolveAfter(with: result) + let result: Result = .success(clientConfiguration) + return Promise.resolveAfter(with: result) } - .recover { error -> Promise in - let result: Result = .success(OrganisationalRules(clientConfiguration: expectedClientConfiguration)) - return Promise.resolveAfter(with: result) + .recover { error -> Promise in + let result: Result = .success(ClientConfiguration(raw: expectedClientConfiguration)) + return Promise.resolveAfter(with: result) } wait(for: expectations, timeout: 1) } diff --git a/FlowCryptAppTests/Functionality/Services/Client Configuration Service/ClientConfigurationTests.swift b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/ClientConfigurationTests.swift new file mode 100644 index 000000000..4363a0c7d --- /dev/null +++ b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/ClientConfigurationTests.swift @@ -0,0 +1,211 @@ +// +// OrganisationalRulesTests.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 17.09.2021. +// Copyright © 2017-present FlowCrypt a. s. All rights reserved. +// + +import Foundation +import XCTest +@testable import FlowCrypt + +class ClientConfigurationTests: XCTestCase { + + func testIsUsingKeyManagerURL() { + XCTAssertTrue(ClientConfiguration(raw: RawClientConfiguration(keyManagerUrl: "https://ekm.example.com")).isUsingKeyManager) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(keyManagerUrl: nil) ).isKeyManagerUrlValid) + } + + func testIsUsingValidKeyManagerURL() { + // valid url check in + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(keyManagerUrl: "") ).isKeyManagerUrlValid) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(keyManagerUrl: "not a url string")).isKeyManagerUrlValid) + } + + func testMustAutoImportOrAutogenPrvWithKeyManager() { + XCTAssertTrue(ClientConfiguration(raw: RawClientConfiguration( + flags: [.privateKeyAutoimportOrAutogen], + keyManagerUrl: "https://ekm.example.com" + )).mustAutoImportOrAutogenPrvWithKeyManager) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration( + flags: [], + keyManagerUrl: "https://ekm.example.com" + )).mustAutoImportOrAutogenPrvWithKeyManager) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration( + flags: nil, + keyManagerUrl: "https://ekm.example.com" + )).mustAutoImportOrAutogenPrvWithKeyManager) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration( + flags: [.defaultRememberPassphrase, .hideArmorMeta, .enforceAttesterSubmit], + keyManagerUrl: "https://ekm.example.com" + )).mustAutoImportOrAutogenPrvWithKeyManager) + } + + func testMustAutogenPassPhraseQuietly() { + XCTAssertTrue(ClientConfiguration(raw: RawClientConfiguration( + flags: [.passphraseQuietAutogen] + )).mustAutogenPassPhraseQuietly) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: [])).mustAutogenPassPhraseQuietly) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: [.privateKeyAutoimportOrAutogen])).mustAutogenPassPhraseQuietly) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: nil)).mustAutogenPassPhraseQuietly) + } + + func testForbidStoringPassPhrase() { + XCTAssertTrue(ClientConfiguration(raw: RawClientConfiguration( + flags: [.forbidStoringPassphrase] + )).forbidStoringPassPhrase) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: [])).forbidStoringPassPhrase) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: [.hideArmorMeta])).forbidStoringPassPhrase) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: nil)).forbidStoringPassPhrase) + } + + func testMustSubmitAttester() { + XCTAssertTrue(ClientConfiguration(raw: RawClientConfiguration( + flags: [.enforceAttesterSubmit] + )).mustSubmitAttester) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: [])).mustSubmitAttester) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: [.hideArmorMeta])).mustSubmitAttester) + + XCTAssertFalse(ClientConfiguration(raw: RawClientConfiguration(flags: nil)).mustSubmitAttester) + } + + func testCheckDoesNotUseEKM() { + // EKM should not be used if keyManagerUrl is nil + XCTAssert(ClientConfiguration(raw: RawClientConfiguration(keyManagerUrl: nil)).checkUsesEKM() == .doesNotUseEKM) + + // EKM should not be used if keyManagerUrl is nil + XCTAssert(ClientConfiguration(raw: RawClientConfiguration( + flags: [], + keyManagerUrl: nil + )).checkUsesEKM() == .doesNotUseEKM) + + + XCTAssert(ClientConfiguration(raw: RawClientConfiguration( + flags: [.forbidStoringPassphrase], + keyManagerUrl: nil + )).checkUsesEKM() == .doesNotUseEKM) + } + + func testShouldUseEKM() { + XCTAssert(ClientConfiguration(raw: RawClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .forbidStoringPassphrase + ], + keyManagerUrl: "https://ekm.example.com" + )).checkUsesEKM() == .usesEKM) + } + + func testCheckShouldUseEKMShouldFailWithoutValidURL() { + let result = ClientConfiguration(raw: RawClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .forbidStoringPassphrase + ], + keyManagerUrl: "" + )).checkUsesEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + XCTAssert(error == .urlNotValid) + } + + func testCheckShouldUseEKMFailForAutogen() { + // No flags + var result = ClientConfiguration(raw: RawClientConfiguration( + flags: nil, + keyManagerUrl: "https://ekm.example.com" + )).checkUsesEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .autoImportOrAutogenPrvWithKeyManager) + + // Empty flags + result = ClientConfiguration(raw: RawClientConfiguration( + flags: [], + keyManagerUrl: "https://ekm.example.com" + )).checkUsesEKM() + guard case .inconsistentClientConfiguration(let emptyFlagsError) = result else { + return XCTFail() + } + + XCTAssert(emptyFlagsError == .autoImportOrAutogenPrvWithKeyManager) + } + + func testCheckShouldUseEKMFailForAutoImportOrAutogen() { + // Wrong flags (without privateKeyAutoimportOrAutogen flag) + let result = ClientConfiguration(raw: RawClientConfiguration( + flags: [ + .noAttesterSubmit + ], + keyManagerUrl: "https://ekm.example.com" + )).checkUsesEKM() + guard case .inconsistentClientConfiguration(let wrongFlagError) = result else { + return XCTFail() + } + + XCTAssert(wrongFlagError == .autoImportOrAutogenPrvWithKeyManager) + } + + func testCheckShouldUseEKMFailForAutogenPassPhraseQuietly() { + // sut pass mustAutoImportOrAutogenPrvWithKeyManager check + let result = ClientConfiguration(raw: RawClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .passphraseQuietAutogen + ], + keyManagerUrl: "https://ekm.example.com" + )).checkUsesEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .autogenPassPhraseQuietly) + } + + func testCheckShouldUseEKMFailForForbidStoringPassPhrase() { + let result = ClientConfiguration(raw: RawClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen + ], + keyManagerUrl: "https://ekm.example.com" + )).checkUsesEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .forbidStoringPassPhrase) + } + + func testCheckShouldUseEKMFailForMustSubmitAttester() { + let result = ClientConfiguration(raw: RawClientConfiguration( + flags: [ + .privateKeyAutoimportOrAutogen, + .forbidStoringPassphrase, + .enforceAttesterSubmit + ], + keyManagerUrl: "https://ekm.example.com" + )).checkUsesEKM() + guard case .inconsistentClientConfiguration(let error) = result else { + return XCTFail() + } + + XCTAssert(error == .mustSubmitAttester) + } +} diff --git a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/ClientConfigurationProviderMock.swift b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/ClientConfigurationProviderMock.swift similarity index 60% rename from FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/ClientConfigurationProviderMock.swift rename to FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/ClientConfigurationProviderMock.swift index 4d6d6ea04..a75dc2c84 100644 --- a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/ClientConfigurationProviderMock.swift +++ b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/ClientConfigurationProviderMock.swift @@ -1,5 +1,5 @@ // -// ClientConfigurationProviderMock.swift +// LocalClientConfigurationMock.swift // FlowCryptAppTests // // Created by Anton Kharchevskyi on 21.09.2021. @@ -9,13 +9,13 @@ import Foundation @testable import FlowCrypt -class ClientConfigurationProviderMock: ClientConfigurationProviderType { +class LocalClientConfigurationMock: LocalClientConfigurationType { var fetchInvoked = false var fetchCount = 0 - var fetchCall: () -> (ClientConfiguration?) = { + var fetchCall: () -> (RawClientConfiguration?) = { nil } - func fetch() -> ClientConfiguration? { + func load() -> RawClientConfiguration? { fetchInvoked = true fetchCount += 1 return fetchCall() @@ -23,19 +23,19 @@ class ClientConfigurationProviderMock: ClientConfigurationProviderType { var removeClientConfigurationInvoked = false var removeClientConfigurationCount = 0 - func removeClientConfiguration() { + func remove() { removeClientConfigurationInvoked = true removeClientConfigurationCount += 1 } var saveInvoked = false var saveCount = 0 - var saveCall: (ClientConfiguration) -> (Void) = { clientConfiguration in + var saveCall: (RawClientConfiguration) -> (Void) = { clientConfiguration in } - func save(clientConfiguration: ClientConfiguration) { + func save(raw: RawClientConfiguration) { saveInvoked = true saveCount += 1 - saveCall(clientConfiguration) + saveCall(raw) } } diff --git a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/CurrentUserEmailMock.swift b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/CurrentUserEmailMock.swift similarity index 100% rename from FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/CurrentUserEmailMock.swift rename to FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/CurrentUserEmailMock.swift diff --git a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/EnterpriseServerApiMock.swift b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/EnterpriseServerApiMock.swift similarity index 79% rename from FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/EnterpriseServerApiMock.swift rename to FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/EnterpriseServerApiMock.swift index 09c6b34f9..f41393ed9 100644 --- a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/EnterpriseServerApiMock.swift +++ b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/EnterpriseServerApiMock.swift @@ -35,23 +35,23 @@ class EnterpriseServerApiMock: EnterpriseServerApiType { var getClientConfigurationInvoked = false var getClientConfigurationCount = 0 - var getClientConfigurationCall: (String) -> (Result) = { email in + var getClientConfigurationCall: (String) -> (Result) = { email in .failure(OrganisationalRulesServiceError.getClientConfigurationCall) } - func getClientConfiguration(for email: String) -> Promise { + func getClientConfiguration(for email: String) -> Promise { getClientConfigurationInvoked = true getClientConfigurationCount += 1 - return Promise.resolveAfter(with: getClientConfigurationCall(email)) + return Promise.resolveAfter(with: getClientConfigurationCall(email)) } var getClientConfigurationForCurrentUserInvoked = false var getClientConfigurationForCurrentUserCount = 0 - var getClientConfigurationForCurrentUserCall: () -> (Result) = { + var getClientConfigurationForCurrentUserCall: () -> (Result) = { .failure(OrganisationalRulesServiceError.getClientConfigurationForCurrentUserCall) } - func getClientConfigurationForCurrentUser() -> Promise { + func getClientConfigurationForCurrentUser() -> Promise { getClientConfigurationForCurrentUserInvoked = true getClientConfigurationForCurrentUserCount += 1 - return Promise.resolveAfter(with: getClientConfigurationForCurrentUserCall()) + return Promise.resolveAfter(with: getClientConfigurationForCurrentUserCall()) } } diff --git a/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/OrganisationalRulesServiceMock.swift b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/OrganisationalRulesServiceMock.swift new file mode 100644 index 000000000..465d29927 --- /dev/null +++ b/FlowCryptAppTests/Functionality/Services/Client Configuration Service/Mocks/OrganisationalRulesServiceMock.swift @@ -0,0 +1,35 @@ +// +// OrganisationalRulesServiceMock.swift +// FlowCryptAppTests +// +// Created by Anton Kharchevskyi on 20.09.2021. +// Copyright © 2017-present FlowCrypt a. s. All rights reserved. +// + +import Foundation +import Promises +@testable import FlowCrypt + +class OrganisationalRulesServiceMock: ClientConfigurationServiceType { + + var fetchOrganisationalRulesForCurrentUserResult: Result = .failure(MockError.some) + func fetchClientConfigurationForCurrentUser() -> 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: RawClientConfiguration! + + var getSavedOrganisationalRulesForCurrentUserResult: ClientConfiguration { + ClientConfiguration(raw: clientConfiguration) + } + func getSavedClientConfigurationForCurrentUser() -> ClientConfiguration { + getSavedOrganisationalRulesForCurrentUserResult + } +} diff --git a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceTest.swift b/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceTest.swift deleted file mode 100644 index 4e08582b0..000000000 --- a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/ClientConfigurationServiceTest.swift +++ /dev/null @@ -1,168 +0,0 @@ -// -// ClientConfigurationServiceTest.swift -// FlowCryptAppTests -// -// Created by Anton Kharchevskyi on 10.09.2021. -// Copyright © 2017-present FlowCrypt a. s. 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/Functionality/Services/Organisational Rules Service/Mocks/OrganisationalRulesServiceMock.swift b/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/OrganisationalRulesServiceMock.swift deleted file mode 100644 index fbb8039be..000000000 --- a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/Mocks/OrganisationalRulesServiceMock.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// OrganisationalRulesServiceMock.swift -// FlowCryptAppTests -// -// Created by Anton Kharchevskyi on 20.09.2021. -// Copyright © 2017-present FlowCrypt a. s. 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/Functionality/Services/Organisational Rules Service/OrganisationalRulesTests.swift b/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/OrganisationalRulesTests.swift deleted file mode 100644 index f0918737f..000000000 --- a/FlowCryptAppTests/Functionality/Services/Organisational Rules Service/OrganisationalRulesTests.swift +++ /dev/null @@ -1,109 +0,0 @@ -// -// OrganisationalRulesTests.swift -// FlowCryptAppTests -// -// Created by Anton Kharchevskyi on 17.09.2021. -// Copyright © 2017-present FlowCrypt a. s. 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/Models Parsing/ClientConfigurationTests.swift b/FlowCryptAppTests/Models Parsing/RawClientConfigurationTests.swift similarity index 89% rename from FlowCryptAppTests/Models Parsing/ClientConfigurationTests.swift rename to FlowCryptAppTests/Models Parsing/RawClientConfigurationTests.swift index 091ff406e..2587faf5c 100644 --- a/FlowCryptAppTests/Models Parsing/ClientConfigurationTests.swift +++ b/FlowCryptAppTests/Models Parsing/RawClientConfigurationTests.swift @@ -1,5 +1,5 @@ // -// ClientConfigurationTests.swift +// RawClientConfigurationTests.swift // FlowCryptTests // // Created by Yevhen Kyivskyi on 20.05.2021. @@ -9,7 +9,7 @@ import XCTest @testable import FlowCrypt -class ClientConfigurationTests: XCTestCase { +class RawClientConfigurationTests: XCTestCase { override func setUp() { // Put setup code here. This method is called before the invocation of each test method in the class. @@ -26,7 +26,7 @@ class ClientConfigurationTests: XCTestCase { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase - let model = try? decoder.decode(ClientConfiguration.self, from: data) + let model = try? decoder.decode(RawClientConfiguration.self, from: data) XCTAssert(model?.flags != nil) XCTAssert(model?.customKeyserverUrl != nil) @@ -43,7 +43,7 @@ class ClientConfigurationTests: XCTestCase { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase - let model = try? decoder.decode(ClientConfiguration.self, from: data) + let model = try? decoder.decode(RawClientConfiguration.self, from: data) XCTAssert(model?.flags != nil) XCTAssert(model?.enforceKeygenAlgo != nil) @@ -61,7 +61,7 @@ class ClientConfigurationTests: XCTestCase { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase - let model = try? decoder.decode(ClientConfiguration.self, from: data) + let model = try? decoder.decode(RawClientConfiguration.self, from: data) XCTAssert(model != nil) @@ -80,7 +80,7 @@ class ClientConfigurationTests: XCTestCase { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase - let model = try? decoder.decode(ClientConfiguration.self, from: data) + let model = try? decoder.decode(RawClientConfiguration.self, from: data) XCTAssert(model?.flags != nil) XCTAssert(model?.customKeyserverUrl != nil)