From 29689b127ac0ff69082f1c2ce65752841aea19f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 20 Feb 2023 12:13:13 +0100 Subject: [PATCH 01/16] Fix all compilation errors --- DuckDuckGo.xcodeproj/project.pbxproj | 60 +++---- DuckDuckGo/API/APIHeaders.swift | 72 -------- DuckDuckGo/API/APIRequest.swift | 138 -------------- DuckDuckGo/API/ApiRequestError.swift | 23 --- DuckDuckGo/Browser Tab/Model/Tab.swift | 2 +- .../Model/UserContentUpdating.swift | 1 + .../ConfigurationDownloading.swift | 170 ------------------ .../Configuration/ConfigurationManager.swift | 133 +++++++------- ...Storing.swift => ConfigurationStore.swift} | 100 ++++------- .../Content Blocker/ContentBlocking.swift | 6 +- .../ScriptSourceProviding.swift | 3 +- .../Model/FeedbackSender.swift | 5 +- .../Statistics/ATB/StatisticsLoader.swift | 131 +++++++------- DuckDuckGo/Statistics/Pixel.swift | 21 ++- .../AutoconsentMessageProtocolTests.swift | 4 +- .../ConfigurationStorageTests.swift | 10 +- .../ContentBlockingUpdatingTests.swift | 4 +- 17 files changed, 216 insertions(+), 667 deletions(-) delete mode 100644 DuckDuckGo/API/APIHeaders.swift delete mode 100644 DuckDuckGo/API/APIRequest.swift delete mode 100644 DuckDuckGo/API/ApiRequestError.swift delete mode 100644 DuckDuckGo/Configuration/ConfigurationDownloading.swift rename DuckDuckGo/Configuration/{ConfigurationStoring.swift => ConfigurationStore.swift} (66%) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index d9eb346ef1..e99b438200 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -89,7 +89,6 @@ 37054FC92873301700033B6F /* PinnedTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37054FC82873301700033B6F /* PinnedTabView.swift */; }; 37054FCE2876472D00033B6F /* WebViewSnapshotView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37054FCD2876472D00033B6F /* WebViewSnapshotView.swift */; }; 3706FA7B293F65D500E42796 /* FaviconUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA0CC562539EBC90079BC96 /* FaviconUserScript.swift */; }; - 3706FA7D293F65D500E42796 /* ApiRequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E457261460340067D1B9 /* ApiRequestError.swift */; }; 3706FA7E293F65D500E42796 /* LottieAnimationCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AADCBF3926F7C2CE00EF67A8 /* LottieAnimationCache.swift */; }; 3706FA7F293F65D500E42796 /* TabIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D23779287EB8CA00BCE03B /* TabIndex.swift */; }; 3706FA80293F65D500E42796 /* TabLazyLoaderDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534CA2281132CB002621E7 /* TabLazyLoaderDataSource.swift */; }; @@ -169,7 +168,7 @@ 3706FAD3293F65D500E42796 /* DownloadsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87F26D5DA9B0062C350 /* DownloadsViewController.swift */; }; 3706FAD4293F65D500E42796 /* DataExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3AF625D5DBFD00C7D2AA /* DataExtension.swift */; }; 3706FAD5293F65D500E42796 /* (null) in Sources */ = {isa = PBXBuildFile; }; - 3706FAD6293F65D500E42796 /* ConfigurationStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85480FCE25D1AA22009424E3 /* ConfigurationStoring.swift */; }; + 3706FAD6293F65D500E42796 /* ConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85480FCE25D1AA22009424E3 /* ConfigurationStore.swift */; }; 3706FAD7293F65D500E42796 /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3D531A27A2F57E00074EC1 /* Feedback.swift */; }; 3706FAD8293F65D500E42796 /* RequestFilePermissionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99D0526FE1979001E4761 /* RequestFilePermissionViewController.swift */; }; 3706FAD9293F65D500E42796 /* FirefoxFaviconsReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A63E7289DB58E00378EF7 /* FirefoxFaviconsReader.swift */; }; @@ -326,7 +325,6 @@ 3706FB7A293F65D500E42796 /* FileDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856C98DE257014BD00A22F1F /* FileDownloadManager.swift */; }; 3706FB7B293F65D500E42796 /* BookmarkImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CF626FE191E001E4761 /* BookmarkImport.swift */; }; 3706FB7C293F65D500E42796 /* KeySetDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68503A6279141CD00893A05 /* KeySetDictionary.swift */; }; - 3706FB7D293F65D500E42796 /* ConfigurationDownloading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85480FBA25D181CB009424E3 /* ConfigurationDownloading.swift */; }; 3706FB7E293F65D500E42796 /* FireCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEEC6A827088ADB008445F7 /* FireCoordinator.swift */; }; 3706FB7F293F65D500E42796 /* GeolocationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B655369A268442EE00085A79 /* GeolocationProvider.swift */; }; 3706FB80293F65D500E42796 /* NSAlert+ActiveDownloadsTermination.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B23B26E87D900031CB7F /* NSAlert+ActiveDownloadsTermination.swift */; }; @@ -430,7 +428,6 @@ 3706FBE7293F65D500E42796 /* PasswordManagementItemListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CC1D7A26A05ECF0062F04E /* PasswordManagementItemListModel.swift */; }; 3706FBE8293F65D500E42796 /* SuggestionTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABEE6A824AB4B910043105B /* SuggestionTableCellView.swift */; }; 3706FBE9293F65D500E42796 /* FireViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6820F025503DA9005ED0D5 /* FireViewModel.swift */; }; - 3706FBEB293F65D500E42796 /* APIRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E459261460350067D1B9 /* APIRequest.swift */; }; 3706FBEC293F65D500E42796 /* EditableTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE65473271FCD40008D1D63 /* EditableTextView.swift */; }; 3706FBED293F65D500E42796 /* TabCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9FF95C24A1FA1C0039E328 /* TabCollection.swift */; }; 3706FBEE293F65D500E42796 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B688B4D9273E6D3B0087BEAF /* MainView.swift */; }; @@ -568,7 +565,6 @@ 3706FC77293F65D500E42796 /* PageObserverUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 853014D525E671A000FB8205 /* PageObserverUserScript.swift */; }; 3706FC78293F65D500E42796 /* SecureVaultErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */; }; 3706FC79293F65D500E42796 /* NSImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B139AFC26B60BD800894F82 /* NSImageExtensions.swift */; }; - 3706FC7A293F65D500E42796 /* APIHeaders.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E458261460340067D1B9 /* APIHeaders.swift */; }; 3706FC7B293F65D500E42796 /* PasswordManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85625995269C953C00EE44BC /* PasswordManagementViewController.swift */; }; 3706FC7C293F65D500E42796 /* ImportedBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CFA26FE191E001E4761 /* ImportedBookmarks.swift */; }; 3706FC7D293F65D500E42796 /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6EF9B2250785D5004754E6 /* NSMenuExtension.swift */; }; @@ -1220,8 +1216,7 @@ 85378DA2274E7F25007C5CBF /* EmailManagerRequestDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85378DA1274E7F25007C5CBF /* EmailManagerRequestDelegate.swift */; }; 8546DE6225C03056000CA5E1 /* UserAgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8546DE6125C03056000CA5E1 /* UserAgentTests.swift */; }; 85480F8A25CDC360009424E3 /* MainMenu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 85480F8925CDC360009424E3 /* MainMenu.storyboard */; }; - 85480FBB25D181CB009424E3 /* ConfigurationDownloading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85480FBA25D181CB009424E3 /* ConfigurationDownloading.swift */; }; - 85480FCF25D1AA22009424E3 /* ConfigurationStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85480FCE25D1AA22009424E3 /* ConfigurationStoring.swift */; }; + 85480FCF25D1AA22009424E3 /* ConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85480FCE25D1AA22009424E3 /* ConfigurationStore.swift */; }; 85589E7F27BBB8630038AD11 /* AddEditFavoriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E7927BBB8620038AD11 /* AddEditFavoriteViewController.swift */; }; 85589E8027BBB8630038AD11 /* AddEditFavoriteWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E7A27BBB8620038AD11 /* AddEditFavoriteWindow.swift */; }; 85589E8127BBB8630038AD11 /* HomePage.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 85589E7B27BBB8630038AD11 /* HomePage.storyboard */; }; @@ -1624,9 +1619,6 @@ B6A924D92664C72E001A28CA /* WebKitDownloadTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */; }; B6A924DE2664CA09001A28CA /* LegacyWebKitDownloadDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A924DD2664CA08001A28CA /* LegacyWebKitDownloadDelegate.swift */; }; B6A9E45326142B070067D1B9 /* Pixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E45226142B070067D1B9 /* Pixel.swift */; }; - B6A9E45A261460350067D1B9 /* ApiRequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E457261460340067D1B9 /* ApiRequestError.swift */; }; - B6A9E45B261460350067D1B9 /* APIHeaders.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E458261460340067D1B9 /* APIHeaders.swift */; }; - B6A9E45C261460350067D1B9 /* APIRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E459261460350067D1B9 /* APIRequest.swift */; }; B6A9E4612614608B0067D1B9 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E4602614608B0067D1B9 /* AppVersion.swift */; }; B6A9E46B2614618A0067D1B9 /* OperatingSystemVersionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E46A2614618A0067D1B9 /* OperatingSystemVersionExtension.swift */; }; B6A9E47026146A250067D1B9 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E46F26146A250067D1B9 /* DateExtension.swift */; }; @@ -1703,6 +1695,8 @@ B6FA893F269C424500588ECD /* PrivacyDashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA893E269C424500588ECD /* PrivacyDashboardViewController.swift */; }; B6FA8941269C425400588ECD /* PrivacyDashboardPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */; }; CB6BCDF927C6BEFF00CC76DC /* PrivacyFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */; }; + CB7E2B8B29A24CBF00997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8A29A24CBF00997A73 /* Configuration */; }; + CB7E2B8D29A24D3800997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8C29A24D3800997A73 /* Configuration */; }; EA0BA3A9272217E6002A0B6C /* ClickToLoadUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */; }; EA18D1CA272F0DC8006DC101 /* social_images in Resources */ = {isa = PBXBuildFile; fileRef = EA18D1C9272F0DC8006DC101 /* social_images */; }; EA1E52B52798CF98002EC53C /* ClickToLoadModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1E52B42798CF98002EC53C /* ClickToLoadModelTests.swift */; }; @@ -2158,8 +2152,7 @@ 85378DA1274E7F25007C5CBF /* EmailManagerRequestDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailManagerRequestDelegate.swift; sourceTree = ""; }; 8546DE6125C03056000CA5E1 /* UserAgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentTests.swift; sourceTree = ""; }; 85480F8925CDC360009424E3 /* MainMenu.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainMenu.storyboard; sourceTree = ""; }; - 85480FBA25D181CB009424E3 /* ConfigurationDownloading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationDownloading.swift; sourceTree = ""; }; - 85480FCE25D1AA22009424E3 /* ConfigurationStoring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationStoring.swift; sourceTree = ""; }; + 85480FCE25D1AA22009424E3 /* ConfigurationStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationStore.swift; sourceTree = ""; }; 8553FF51257523760029327F /* URLSuggestedFilenameTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSuggestedFilenameTests.swift; sourceTree = ""; }; 85589E7927BBB8620038AD11 /* AddEditFavoriteViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddEditFavoriteViewController.swift; sourceTree = ""; }; 85589E7A27BBB8620038AD11 /* AddEditFavoriteWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddEditFavoriteWindow.swift; sourceTree = ""; }; @@ -2576,9 +2569,6 @@ B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebKitDownloadTask.swift; sourceTree = ""; }; B6A924DD2664CA08001A28CA /* LegacyWebKitDownloadDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyWebKitDownloadDelegate.swift; sourceTree = ""; }; B6A9E45226142B070067D1B9 /* Pixel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pixel.swift; sourceTree = ""; }; - B6A9E457261460340067D1B9 /* ApiRequestError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiRequestError.swift; sourceTree = ""; }; - B6A9E458261460340067D1B9 /* APIHeaders.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIHeaders.swift; sourceTree = ""; }; - B6A9E459261460350067D1B9 /* APIRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIRequest.swift; sourceTree = ""; }; B6A9E4602614608B0067D1B9 /* AppVersion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = ""; }; B6A9E46A2614618A0067D1B9 /* OperatingSystemVersionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatingSystemVersionExtension.swift; sourceTree = ""; }; B6A9E46F26146A250067D1B9 /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = ""; }; @@ -2644,6 +2634,7 @@ B6FA893C269C423100588ECD /* PrivacyDashboard.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PrivacyDashboard.storyboard; sourceTree = ""; }; B6FA893E269C424500588ECD /* PrivacyDashboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardViewController.swift; sourceTree = ""; }; B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardPopover.swift; sourceTree = ""; }; + CB5E2CF629A1A5680062D13E /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyFeatures.swift; sourceTree = ""; }; EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClickToLoadUserScript.swift; sourceTree = ""; }; EA18D1C9272F0DC8006DC101 /* social_images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = social_images; sourceTree = ""; }; @@ -2681,6 +2672,7 @@ 3706FCAE293F65D500E42796 /* Lottie in Frameworks */, 3706FCAF293F65D500E42796 /* PrivacyDashboard in Frameworks */, 3706FCB0293F65D500E42796 /* Common in Frameworks */, + CB7E2B8D29A24D3800997A73 /* Configuration in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2725,6 +2717,7 @@ 1E950E432912A10D0051A99B /* UserScript in Frameworks */, 4B82E9B325B69E3E00656FE7 /* TrackerRadarKit in Frameworks */, 1D02633328D898E1005CBB41 /* OpenSSL in Frameworks */, + CB7E2B8B29A24CBF00997A73 /* Configuration in Frameworks */, AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */, 85FF55C825F82E4F00E2AB99 /* Lottie in Frameworks */, 1E950E412912A10D0051A99B /* PrivacyDashboard in Frameworks */, @@ -3966,9 +3959,8 @@ 85D33F1025C82E93002B91A6 /* Configuration */ = { isa = PBXGroup; children = ( - 85480FBA25D181CB009424E3 /* ConfigurationDownloading.swift */, 85D33F1125C82EB3002B91A6 /* ConfigurationManager.swift */, - 85480FCE25D1AA22009424E3 /* ConfigurationStoring.swift */, + 85480FCE25D1AA22009424E3 /* ConfigurationStore.swift */, ); path = Configuration; sourceTree = ""; @@ -4117,6 +4109,7 @@ AA585D75248FD31100E9A3E2 = { isa = PBXGroup; children = ( + CB5E2CF629A1A5680062D13E /* BrowserServicesKit */, 378E279C2970217400FCADA2 /* Plugins */, 378B5886295CF2A4002C0CC0 /* Configuration */, AA68C3D62490F821001B8783 /* README.md */, @@ -4149,7 +4142,6 @@ EEAEA3F4294D05CF00D04DF3 /* JSAlert */, B31055BB27A1BA0E001AC618 /* Autoconsent */, 7B1E819A27C8874900FF0E60 /* Autofill */, - B6A9E47526146A440067D1B9 /* API */, AA4D700525545EDE00C3411E /* App Delegate */, AAC5E4C025D6A6A9007F5990 /* Bookmarks */, 4BFD356E283ADE8B00CE9234 /* Bookmarks Bar */, @@ -5378,16 +5370,6 @@ path = Statistics; sourceTree = ""; }; - B6A9E47526146A440067D1B9 /* API */ = { - isa = PBXGroup; - children = ( - B6A9E458261460340067D1B9 /* APIHeaders.swift */, - B6A9E459261460350067D1B9 /* APIRequest.swift */, - B6A9E457261460340067D1B9 /* ApiRequestError.swift */, - ); - path = API; - sourceTree = ""; - }; B6AE74322609AFBB005B9B1A /* Progress */ = { isa = PBXGroup; children = ( @@ -5535,6 +5517,7 @@ 3706FA77293F65D500E42796 /* PrivacyDashboard */, 3706FA78293F65D500E42796 /* UserScript */, 37A5E2EF298AA1B20047046B /* Persistence */, + CB7E2B8C29A24D3800997A73 /* Configuration */, ); productName = DuckDuckGo; productReference = 3706FD05293F65D500E42796 /* DuckDuckGo App Store.app */; @@ -5648,6 +5631,7 @@ 1E950E402912A10D0051A99B /* PrivacyDashboard */, 1E950E422912A10D0051A99B /* UserScript */, 98A50963294B691800D10880 /* Persistence */, + CB7E2B8A29A24CBF00997A73 /* Configuration */, ); productName = DuckDuckGo; productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */; @@ -6102,7 +6086,6 @@ buildActionMask = 2147483647; files = ( 3706FA7B293F65D500E42796 /* FaviconUserScript.swift in Sources */, - 3706FA7D293F65D500E42796 /* ApiRequestError.swift in Sources */, 3706FA7E293F65D500E42796 /* LottieAnimationCache.swift in Sources */, 3706FA7F293F65D500E42796 /* TabIndex.swift in Sources */, 3706FA80293F65D500E42796 /* TabLazyLoaderDataSource.swift in Sources */, @@ -6187,7 +6170,7 @@ 3706FAD3293F65D500E42796 /* DownloadsViewController.swift in Sources */, 3706FAD4293F65D500E42796 /* DataExtension.swift in Sources */, 3706FAD5293F65D500E42796 /* (null) in Sources */, - 3706FAD6293F65D500E42796 /* ConfigurationStoring.swift in Sources */, + 3706FAD6293F65D500E42796 /* ConfigurationStore.swift in Sources */, 3706FAD7293F65D500E42796 /* Feedback.swift in Sources */, 3707C722294B5D2900682A9F /* WKWebViewExtension.swift in Sources */, 3706FAD8293F65D500E42796 /* RequestFilePermissionViewController.swift in Sources */, @@ -6366,7 +6349,6 @@ 3706FB7A293F65D500E42796 /* FileDownloadManager.swift in Sources */, 3706FB7B293F65D500E42796 /* BookmarkImport.swift in Sources */, 3706FB7C293F65D500E42796 /* KeySetDictionary.swift in Sources */, - 3706FB7D293F65D500E42796 /* ConfigurationDownloading.swift in Sources */, 3706FB7E293F65D500E42796 /* FireCoordinator.swift in Sources */, 3706FB7F293F65D500E42796 /* GeolocationProvider.swift in Sources */, 3706FB80293F65D500E42796 /* NSAlert+ActiveDownloadsTermination.swift in Sources */, @@ -6477,7 +6459,6 @@ 3706FBE8293F65D500E42796 /* SuggestionTableCellView.swift in Sources */, 3706FBE9293F65D500E42796 /* FireViewModel.swift in Sources */, 3706FEC6293F6F0600E42796 /* BWKeyStorage.swift in Sources */, - 3706FBEB293F65D500E42796 /* APIRequest.swift in Sources */, 3706FBEC293F65D500E42796 /* EditableTextView.swift in Sources */, 3706FBED293F65D500E42796 /* TabCollection.swift in Sources */, 3707C729294B5D2900682A9F /* WKFrameInfoExtension.swift in Sources */, @@ -6625,7 +6606,6 @@ 3706FC78293F65D500E42796 /* SecureVaultErrorReporter.swift in Sources */, 3706FC79293F65D500E42796 /* NSImageExtensions.swift in Sources */, 3706FEBD293F6EFF00E42796 /* BWCommand.swift in Sources */, - 3706FC7A293F65D500E42796 /* APIHeaders.swift in Sources */, 3706FC7B293F65D500E42796 /* PasswordManagementViewController.swift in Sources */, 3706FC7C293F65D500E42796 /* ImportedBookmarks.swift in Sources */, 3706FC7D293F65D500E42796 /* NSMenuExtension.swift in Sources */, @@ -6911,7 +6891,6 @@ files = ( AAA0CC572539EBC90079BC96 /* FaviconUserScript.swift in Sources */, 1D2DC0082901679E008083A1 /* BWResponse.swift in Sources */, - B6A9E45A261460350067D1B9 /* ApiRequestError.swift in Sources */, AADCBF3A26F7C2CE00EF67A8 /* LottieAnimationCache.swift in Sources */, 37D2377A287EB8CA00BCE03B /* TabIndex.swift in Sources */, 37534CA3281132CB002621E7 /* TabLazyLoaderDataSource.swift in Sources */, @@ -6999,7 +6978,7 @@ B69B503B2726A12500758A2B /* Atb.swift in Sources */, B6B1E88026D5DA9B0062C350 /* DownloadsViewController.swift in Sources */, 85AC3AF725D5DBFD00C7D2AA /* DataExtension.swift in Sources */, - 85480FCF25D1AA22009424E3 /* ConfigurationStoring.swift in Sources */, + 85480FCF25D1AA22009424E3 /* ConfigurationStore.swift in Sources */, AA3D531B27A2F57E00074EC1 /* Feedback.swift in Sources */, 4BB99D0626FE1979001E4761 /* RequestFilePermissionViewController.swift in Sources */, 4B0A63E8289DB58E00378EF7 /* FirefoxFaviconsReader.swift in Sources */, @@ -7174,7 +7153,6 @@ 856C98DF257014BD00A22F1F /* FileDownloadManager.swift in Sources */, 4BB99CFF26FE191E001E4761 /* BookmarkImport.swift in Sources */, B68503A7279141CD00893A05 /* KeySetDictionary.swift in Sources */, - 85480FBB25D181CB009424E3 /* ConfigurationDownloading.swift in Sources */, AAEEC6A927088ADB008445F7 /* FireCoordinator.swift in Sources */, B655369B268442EE00085A79 /* GeolocationProvider.swift in Sources */, B6C0B23C26E87D900031CB7F /* NSAlert+ActiveDownloadsTermination.swift in Sources */, @@ -7289,7 +7267,6 @@ AABEE6A924AB4B910043105B /* SuggestionTableCellView.swift in Sources */, AA6820F125503DA9005ED0D5 /* FireViewModel.swift in Sources */, AAA0CC6A253CC43C0079BC96 /* WKUserContentControllerExtension.swift in Sources */, - B6A9E45C261460350067D1B9 /* APIRequest.swift in Sources */, 4BE65479271FCD41008D1D63 /* EditableTextView.swift in Sources */, AA9FF95D24A1FA1C0039E328 /* TabCollection.swift in Sources */, B688B4DA273E6D3B0087BEAF /* MainView.swift in Sources */, @@ -7437,7 +7414,6 @@ 853014D625E671A000FB8205 /* PageObserverUserScript.swift in Sources */, B642738227B65BAC0005DFD1 /* SecureVaultErrorReporter.swift in Sources */, 4B139AFD26B60BD800894F82 /* NSImageExtensions.swift in Sources */, - B6A9E45B261460350067D1B9 /* APIHeaders.swift in Sources */, 85625996269C953C00EE44BC /* PasswordManagementViewController.swift in Sources */, 4BB99D0226FE191E001E4761 /* ImportedBookmarks.swift in Sources */, AA6EF9B3250785D5004754E6 /* NSMenuExtension.swift in Sources */, @@ -8287,6 +8263,14 @@ package = B6DA44152616C13800DD1EC2 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; productName = OHHTTPStubsSwift; }; + CB7E2B8A29A24CBF00997A73 /* Configuration */ = { + isa = XCSwiftPackageProductDependency; + productName = Configuration; + }; + CB7E2B8C29A24D3800997A73 /* Configuration */ = { + isa = XCSwiftPackageProductDependency; + productName = Configuration; + }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ diff --git a/DuckDuckGo/API/APIHeaders.swift b/DuckDuckGo/API/APIHeaders.swift deleted file mode 100644 index 274066a79b..0000000000 --- a/DuckDuckGo/API/APIHeaders.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// APIHeaders.swift -// -// Copyright © 2018 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -typealias HTTPHeaders = [String: String] - -final class APIHeaders { - - enum Name { - static let acceptEncoding = "Accept-Encoding" - static let acceptLanguage = "Accept-Language" - static let userAgent = "User-Agent" - static let etag = "ETag" - static let ifNoneMatch = "If-None-Match" - static let moreInfo = "X-DuckDuckGo-MoreInfo" - } - - private let appVersion: AppVersion - - init(appVersion: AppVersion = AppVersion.shared) { - self.appVersion = appVersion - } - - var defaultHeaders: HTTPHeaders { - let acceptEncoding = "gzip;q=1.0, compress;q=0.5" - let languages = Locale.preferredLanguages.prefix(6) - let acceptLanguage = languages.enumerated().map { index, language in - let q = 1.0 - (Double(index) * 0.1) - return "\(language);q=\(q)" - }.joined(separator: ", ") - - return [ - Name.acceptEncoding: acceptEncoding, - Name.acceptLanguage: acceptLanguage, - Name.userAgent: userAgent - ] - } - - var userAgent: String { - let osVersion = ProcessInfo.processInfo.operatingSystemVersion - return "ddg_mac/\(appVersion.versionNumber) (\(appVersion.identifier); macOS \(osVersion))" - } - - func defaultHeaders(with etag: String?) -> HTTPHeaders { - guard let etag = etag else { - return defaultHeaders - } - - return defaultHeaders.merging([Name.ifNoneMatch: etag]) { (_, new) in new } - } - - func addHeaders(to request: inout URLRequest) { - request.addValue(Name.userAgent, forHTTPHeaderField: userAgent) - } - -} diff --git a/DuckDuckGo/API/APIRequest.swift b/DuckDuckGo/API/APIRequest.swift deleted file mode 100644 index 2698db5457..0000000000 --- a/DuckDuckGo/API/APIRequest.swift +++ /dev/null @@ -1,138 +0,0 @@ -// -// APIRequest.swift -// -// Copyright © 2017 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation -import os.log - -typealias APIRequestCompletion = (APIRequest.Response?, Error?) -> Void - -enum APIRequest { - - private static var defaultCallbackQueue: OperationQueue = { - let queue = OperationQueue() - queue.name = "APIRequest default callback queue" - queue.qualityOfService = .userInitiated - queue.maxConcurrentOperationCount = 1 - return queue - }() - - private static let defaultCallbackSession = URLSession(configuration: .default, delegate: nil, delegateQueue: defaultCallbackQueue) - private static let defaultCallbackEphemeralSession = URLSession(configuration: .ephemeral, delegate: nil, delegateQueue: defaultCallbackQueue) - - private static let mainThreadCallbackSession = URLSession(configuration: .default, delegate: nil, delegateQueue: OperationQueue.main) - private static let mainThreadCallbackEphemeralSession = URLSession(configuration: .ephemeral, delegate: nil, delegateQueue: OperationQueue.main) - - struct Response { - - var data: Data? - var etag: String? - var urlResponse: URLResponse? - - } - - enum HTTPMethod: String { - case get = "GET" - case head = "HEAD" - case post = "POST" - case put = "PUT" - case delete = "DELETE" - case connect = "CONNECT" - case options = "OPTIONS" - case trace = "TRACE" - case patch = "PATCH" - } - - @discardableResult - static func request(url: URL, - method: HTTPMethod = .get, - parameters: [String: String]? = nil, - allowedQueryReservedCharacters: CharacterSet? = nil, - headers: HTTPHeaders = APIHeaders().defaultHeaders, - timeoutInterval: TimeInterval = 60.0, - useEphemeralURLSession: Bool = true, // URL requests must opt into using shared storage - callBackOnMainThread: Bool = false, - completion: @escaping APIRequestCompletion) -> URLSessionDataTask { - - let urlRequest = urlRequestFor( - url: url, - method: method, - parameters: parameters, - allowedQueryReservedCharacters: allowedQueryReservedCharacters, - headers: headers, - timeoutInterval: timeoutInterval - ) - let session = session(useMainThreadCallbackQueue: callBackOnMainThread, ephemeral: useEphemeralURLSession) - - let task = session.dataTask(with: urlRequest) { (data, response, error) in - - let httpResponse = response as? HTTPURLResponse - - if let error = error { - completion(nil, error) - } else if let error = httpResponse?.validateStatusCode(statusCode: 200..<300) { - completion(nil, error) - } else { - var etag = httpResponse?.headerValue(for: APIHeaders.Name.etag) - - // Handle weak etags - etag = etag?.dropping(prefix: "W/") - completion(Response(data: data, etag: etag, urlResponse: response), nil) - } - } - task.resume() - return task - } - - static func urlRequestFor(url: URL, - method: HTTPMethod = .get, - parameters: [String: String]? = nil, - allowedQueryReservedCharacters: CharacterSet? = nil, - headers: HTTPHeaders = APIHeaders().defaultHeaders, - timeoutInterval: TimeInterval = 60.0) -> URLRequest { - let url = url.appendingParameters(parameters ?? [:], allowedReservedCharacters: allowedQueryReservedCharacters) - var urlRequest = URLRequest(url: url, timeoutInterval: timeoutInterval) - urlRequest.allHTTPHeaderFields = headers - urlRequest.httpMethod = method.rawValue - return urlRequest - } - - private static func session(useMainThreadCallbackQueue: Bool, ephemeral: Bool) -> URLSession { - if useMainThreadCallbackQueue { - return ephemeral ? mainThreadCallbackEphemeralSession : mainThreadCallbackSession - } else { - return ephemeral ? defaultCallbackEphemeralSession : defaultCallbackSession - } - } - -} - -extension HTTPURLResponse { - - enum HTTPURLResponseError: Error { - case invalidStatusCode - } - - func validateStatusCode(statusCode acceptedStatusCodes: S) -> Error? where S.Iterator.Element == Int { - return acceptedStatusCodes.contains(statusCode) ? nil : HTTPURLResponseError.invalidStatusCode - } - - fileprivate func headerValue(for name: String) -> String? { - let lname = name.lowercased() - return allHeaderFields.filter { ($0.key as? String)?.lowercased() == lname }.first?.value as? String - } -} diff --git a/DuckDuckGo/API/ApiRequestError.swift b/DuckDuckGo/API/ApiRequestError.swift deleted file mode 100644 index 3119b591ee..0000000000 --- a/DuckDuckGo/API/ApiRequestError.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// ApiRequestError.swift -// -// Copyright © 2017 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -enum ApiRequestError: Error { - case noData -} diff --git a/DuckDuckGo/Browser Tab/Model/Tab.swift b/DuckDuckGo/Browser Tab/Model/Tab.swift index 38c5eef327..32875da70c 100644 --- a/DuckDuckGo/Browser Tab/Model/Tab.swift +++ b/DuckDuckGo/Browser Tab/Model/Tab.swift @@ -1392,7 +1392,7 @@ extension Tab: WKNavigationDelegate { decidePolicyFor navigationResponse: WKNavigationResponse) async -> WKNavigationResponsePolicy { userEnteredUrl = false // subsequent requests will be navigations - let isSuccessfulResponse = (navigationResponse.response as? HTTPURLResponse)?.validateStatusCode(statusCode: 200..<300) == nil + let isSuccessfulResponse = (navigationResponse.response as? HTTPURLResponse)?.isSuccessfulResponse ?? false internalUserDecider?.markUserAsInternalIfNeeded(forUrl: webView.url, response: navigationResponse.response as? HTTPURLResponse) diff --git a/DuckDuckGo/Browser Tab/Model/UserContentUpdating.swift b/DuckDuckGo/Browser Tab/Model/UserContentUpdating.swift index 2611d91507..88624991d4 100644 --- a/DuckDuckGo/Browser Tab/Model/UserContentUpdating.swift +++ b/DuckDuckGo/Browser Tab/Model/UserContentUpdating.swift @@ -21,6 +21,7 @@ import Combine import Common import BrowserServicesKit import UserScript +import Configuration final class UserContentUpdating { diff --git a/DuckDuckGo/Configuration/ConfigurationDownloading.swift b/DuckDuckGo/Configuration/ConfigurationDownloading.swift deleted file mode 100644 index e5ad1822a7..0000000000 --- a/DuckDuckGo/Configuration/ConfigurationDownloading.swift +++ /dev/null @@ -1,170 +0,0 @@ -// -// ConfigurationDownloading.swift -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation -import Combine -import BrowserServicesKit - -protocol ConfigurationDownloading { - - func refreshDataThenUpdate(for locations: [ConfigurationLocation], _ updater: @escaping () throws -> Void) - -> AnyPublisher<[ConfigurationDownloadMeta?], Swift.Error> - func cancelAll() - -} - -struct ConfigurationDownloadMeta { - - var etag: String - var data: Data - -} - -enum ConfigurationLocation: String, CaseIterable { - - case bloomFilterSpec = "https://staticcdn.duckduckgo.com/https/https-mobile-v2-bloom-spec.json" - case bloomFilterBinary = "https://staticcdn.duckduckgo.com/https/https-mobile-v2-bloom.bin" - case bloomFilterExcludedDomains = "https://staticcdn.duckduckgo.com/https/https-mobile-v2-false-positives.json" - case surrogates = "https://duckduckgo.com/contentblocking.js?l=surrogates" - case trackerRadar = "https://staticcdn.duckduckgo.com/trackerblocking/v3/apple-tds.json" - case privacyConfiguration = "https://staticcdn.duckduckgo.com/trackerblocking/config/v2/macos-config.json" - // In archived repo, to be refactored shortly (https://staticcdn.duckduckgo.com/useragents/social_ctp_configuration.json) - case FBConfig = "https://staticcdn.duckduckgo.com/useragents/" - -} - -final class DefaultConfigurationDownloader: ConfigurationDownloading { - - enum Error: Swift.Error { - - case urlSessionError(error: Swift.Error) - case noEtagInResponse - case invalidResponse - case savingData - case savingEtag - - } - - struct Constants { - static let ifNoneMatchField = "If-None-Match" - static let etagField = "Etag" - static let notModifiedResponseCode = 304 - static let successResponseCode = 200 - } - - let storage: ConfigurationStoring - let dataTaskProvider: DataTaskProviding - - private var cancellables = Set() - private let deliveryQueue: DispatchQueue - - init(storage: ConfigurationStoring = DefaultConfigurationStorage.shared, - dataTaskProvider: DataTaskProviding = SharedURLSessionDataTaskProvider(), - deliveryQueue: DispatchQueue) { - self.storage = storage - self.dataTaskProvider = dataTaskProvider - self.deliveryQueue = deliveryQueue - } - - func download(_ config: ConfigurationLocation, embeddedEtag: String?) -> AnyPublisher { - - let url = URL(string: config.rawValue)! - - return Future { promise in - var request = URLRequest.defaultRequest(with: url) - request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData - - let storedEtag = self.storage.loadEtag(for: config) - - if let embeddedEtag = embeddedEtag, storedEtag == nil { - request.addValue(embeddedEtag, forHTTPHeaderField: Constants.ifNoneMatchField) - } else if self.storage.loadData(for: config) != nil, let etag = storedEtag { - request.addValue(etag, forHTTPHeaderField: Constants.ifNoneMatchField) - } - - self.dataTaskProvider.dataTaskPublisher(for: request) - .tryMap { result -> ConfigurationDownloadMeta? in - guard let response = result.response as? HTTPURLResponse else { - throw Error.invalidResponse - } - - if response.statusCode == Constants.notModifiedResponseCode { - return nil - } - - guard let etag = response.value(forHTTPHeaderField: Constants.etagField) else { - throw Error.noEtagInResponse - } - - try self.storage.saveData(result.data, for: config) - try self.storage.saveEtag(etag, for: config) - - return ConfigurationDownloadMeta(etag: etag, data: result.data) - } - .sink(receiveCompletion: { completion in - - if case .failure(let error) = completion { - promise(.failure(error)) - } - - }) { value in - - promise(.success((value))) - - }.store(in: &self.cancellables) - - }.eraseToAnyPublisher() - - } - - func cancelAll() { - - let cancellables = self.cancellables - self.cancellables.removeAll() - cancellables.forEach { $0.cancel() } - - } - - func embeddedEtag(for config: ConfigurationLocation) -> String? { - switch config { - case .trackerRadar: return AppTrackerDataSetProvider.Constants.embeddedDataETag - case .privacyConfiguration: return AppPrivacyConfigurationDataProvider.Constants.embeddedDataSHA - default: return nil - } - } - - func refreshDataThenUpdate(for locations: [ConfigurationLocation], _ updater: @escaping () throws -> Void) - -> AnyPublisher<[ConfigurationDownloadMeta?], Swift.Error> { - - Publishers.MergeMany( - locations.map { - download($0, embeddedEtag: embeddedEtag(for: $0)) - } - ) - .receive(on: self.deliveryQueue) - .collect() - .tryMap { result -> [ConfigurationDownloadMeta?] in - if !result.compactMap({$0}).isEmpty { - try updater() - } - return result - }.eraseToAnyPublisher() - - } - -} diff --git a/DuckDuckGo/Configuration/ConfigurationManager.swift b/DuckDuckGo/Configuration/ConfigurationManager.swift index 63f84ff1ff..a2f6cf97d6 100644 --- a/DuckDuckGo/Configuration/ConfigurationManager.swift +++ b/DuckDuckGo/Configuration/ConfigurationManager.swift @@ -20,27 +20,32 @@ import Foundation import Combine import os import BrowserServicesKit +import Configuration final class ConfigurationManager { enum Error: Swift.Error { + case timeout case bloomFilterSpecNotFound case bloomFilterBinaryNotFound case bloomFilterPersistenceFailed case bloomFilterExclusionsNotFound case bloomFilterExclusionsPersistenceFailed + } - struct Constants { + enum Constants { + static let downloadTimeoutSeconds = 60.0 * 5 #if DEBUG - static let refreshPeriodSeconds = 60.0 * 2 // 2 minutes when in debug mode + static let refreshPeriodSeconds = 60.0 * 2 // 2 minutes #else static let refreshPeriodSeconds = 60.0 * 30 // 30 minutes #endif static let retryDelaySeconds = 60.0 * 60 * 1 // 1 hour delay before checking again if something went wrong last time - static let refreshCheckIntervalSeconds = 60.0 // Check if we need a refresh every minute + static let refreshCheckIntervalSeconds = 60.0 // check if we need a refresh every minute + } static let shared = ConfigurationManager() @@ -54,13 +59,6 @@ final class ConfigurationManager { private var refreshCancellable: AnyCancellable? private var lastRefreshCheckTime: Date = Date() - private let configDownloader: ConfigurationDownloading - - /// Use the shared instance if subscribing to events. Only use the constructor for testing. - init(configDownloader: ConfigurationDownloading = DefaultConfigurationDownloader(deliveryQueue: ConfigurationManager.queue)) { - self.configDownloader = configDownloader - } - func start() { os_log("Starting configuration refresh timer", log: .config, type: .debug) timerCancellable = Timer.publish(every: Constants.refreshCheckIntervalSeconds, on: .main, in: .default) @@ -70,7 +68,9 @@ final class ConfigurationManager { self.lastRefreshCheckTime = Date() self.refreshIfNeeded() }) - refreshNow() + Task { + await refreshNow() + } } func log() { @@ -78,64 +78,58 @@ final class ConfigurationManager { os_log("last refresh check %{public}s", log: .config, type: .default, String(describing: lastRefreshCheckTime)) } - private func refreshNow() { - - refreshCancellable = - - Publishers.MergeMany( - - configDownloader.refreshDataThenUpdate(for: [ - .trackerRadar, - .surrogates, - .privacyConfiguration - ], self.updateTrackerBlockingDependencies), - - configDownloader.refreshDataThenUpdate(for: [ - .bloomFilterBinary, - .bloomFilterSpec - ], self.updateBloomFilter), - - configDownloader.refreshDataThenUpdate(for: [ - .bloomFilterExcludedDomains - ], self.updateBloomFilterExclusions) - - ) - .collect() - .timeout(.seconds(Constants.downloadTimeoutSeconds), scheduler: Self.queue, options: nil, customError: { Error.timeout }) - .sink { [self] completion in - - if case .failure(let error) = completion { - os_log("Failed to complete configuration update %s", log: .config, type: .error, error.localizedDescription) - Pixel.fire(.debug(event: .configurationFetchError, error: error)) - - tryAgainSoon() - } else { - tryAgainLater() - } - - refreshCancellable = nil - configDownloader.cancelAll() - - DefaultConfigurationStorage.shared.log() - log() - - } receiveValue: { _ in - // no-op - if you want to do something more globally if any of the files were downloaded, this is the place + private func refreshNow() async { + + let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared) + do { + try await fetcher.fetch([.trackerRadar, .surrogates, .privacyConfiguration]) { + try self.updateTrackerBlockingDependencies() + self.tryAgainLater() } - + } catch { + handleRefreshError(error) + } + + do { + try await fetcher.fetch([.bloomFilterBinary, .bloomFilterSpec]) { + try self.updateBloomFilter() + self.tryAgainLater() + } + } catch { + handleRefreshError(error) + } + + do { + try await fetcher.fetch([.bloomFilterExcludedDomains]) { + try self.updateBloomFilterExclusions() + self.tryAgainLater() + } + } catch { + handleRefreshError(error) + } + + ConfigurationStore.shared.log() + log() + + } + + private func handleRefreshError(_ error: Swift.Error) { + os_log("Failed to complete configuration update %s", log: .config, type: .error, error.localizedDescription) + Pixel.fire(.debug(event: .configurationFetchError, error: error)) + tryAgainSoon() } public func refreshIfNeeded() { - guard self.isReadyToRefresh(), refreshCancellable == nil else { + guard isReadyToRefresh, refreshCancellable == nil else { os_log("Configuration refresh is not needed at this time", log: .config, type: .debug) return } - refreshNow() + Task { + await refreshNow() + } } - private func isReadyToRefresh() -> Bool { - return Date().timeIntervalSince(lastUpdateTime) > Constants.refreshPeriodSeconds - } + private var isReadyToRefresh: Bool { Date().timeIntervalSince(lastUpdateTime) > Constants.refreshPeriodSeconds } private func tryAgainLater() { lastUpdateTime = Date() @@ -147,21 +141,19 @@ final class ConfigurationManager { } private func updateTrackerBlockingDependencies() throws { - - let tdsEtag = DefaultConfigurationStorage.shared.loadEtag(for: .trackerRadar) - let tdsData = DefaultConfigurationStorage.shared.loadData(for: .trackerRadar) + let tdsEtag = ConfigurationStore.shared.loadEtag(for: .trackerRadar) + let tdsData = ConfigurationStore.shared.loadData(for: .trackerRadar) ContentBlocking.shared.trackerDataManager.reload(etag: tdsEtag, data: tdsData) - let configEtag = DefaultConfigurationStorage.shared.loadEtag(for: .privacyConfiguration) - let configData = DefaultConfigurationStorage.shared.loadData(for: .privacyConfiguration) - _=ContentBlocking.shared.privacyConfigurationManager.reload(etag: configEtag, data: configData) + let configEtag = ConfigurationStore.shared.loadEtag(for: .privacyConfiguration) + let configData = ConfigurationStore.shared.loadData(for: .privacyConfiguration) + _ = ContentBlocking.shared.privacyConfigurationManager.reload(etag: configEtag, data: configData) - _=ContentBlocking.shared.contentBlockingManager.scheduleCompilation() + _ = ContentBlocking.shared.contentBlockingManager.scheduleCompilation() } private func updateBloomFilter() throws { - - let configStore = DefaultConfigurationStorage.shared + let configStore = ConfigurationStore.shared guard let specData = configStore.loadData(for: .bloomFilterSpec) else { throw Error.bloomFilterSpecNotFound } @@ -181,8 +173,7 @@ final class ConfigurationManager { } private func updateBloomFilterExclusions() throws { - - let configStore = DefaultConfigurationStorage.shared + let configStore = ConfigurationStore.shared guard let bloomFilterExclusions = configStore.loadData(for: .bloomFilterExcludedDomains) else { throw Error.bloomFilterExclusionsNotFound } diff --git a/DuckDuckGo/Configuration/ConfigurationStoring.swift b/DuckDuckGo/Configuration/ConfigurationStore.swift similarity index 66% rename from DuckDuckGo/Configuration/ConfigurationStoring.swift rename to DuckDuckGo/Configuration/ConfigurationStore.swift index 209a8e3f02..84d571a3a5 100644 --- a/DuckDuckGo/Configuration/ConfigurationStoring.swift +++ b/DuckDuckGo/Configuration/ConfigurationStore.swift @@ -18,20 +18,11 @@ import Foundation import os +import Configuration -protocol ConfigurationStoring { +final class ConfigurationStore: ConfigurationStoring { - func loadData(for: ConfigurationLocation) -> Data? - func loadEtag(for: ConfigurationLocation) -> String? - func saveData(_ data: Data, for: ConfigurationLocation) throws - func saveEtag(_ etag: String, for: ConfigurationLocation) throws - func log() - -} - -final class DefaultConfigurationStorage: ConfigurationStoring { - - private static let fileLocations: [ConfigurationLocation: String] = [ + private static let fileLocations: [Configuration: String] = [ .bloomFilterBinary: "smarterEncryption.bin", .bloomFilterExcludedDomains: "smarterEncryptionExclusions.json", .bloomFilterSpec: "smarterEncryptionSpec.json", @@ -41,7 +32,7 @@ final class DefaultConfigurationStorage: ConfigurationStoring { .FBConfig: "social_ctp_configuration.json" ] - static let shared = DefaultConfigurationStorage() + static let shared = ConfigurationStore() @UserDefaultsWrapper(key: .configStorageTrackerRadarEtag, defaultValue: nil) private var trackerRadarEtag: String? @@ -66,71 +57,52 @@ final class DefaultConfigurationStorage: ConfigurationStoring { private init() { } - func loadEtag(for config: ConfigurationLocation) -> String? { - switch config { - case .bloomFilterSpec: - return bloomFilterSpecEtag - - case .bloomFilterBinary: - return bloomFilterBinaryEtag - - case .bloomFilterExcludedDomains: - return bloomFilterExcludedDomainsEtag - - case .surrogates: - return surrogatesEtag - - case .trackerRadar: - return trackerRadarEtag - - case .privacyConfiguration: - return privacyConfigurationEtag - - case .FBConfig: - return FBConfigEtag + func loadEtag(for configuration: Configuration) -> String? { + switch configuration { + case .bloomFilterSpec: return bloomFilterSpecEtag + case .bloomFilterBinary: return bloomFilterBinaryEtag + case .bloomFilterExcludedDomains: return bloomFilterExcludedDomainsEtag + case .surrogates: return surrogatesEtag + case .trackerRadar: return trackerRadarEtag + case .privacyConfiguration: return privacyConfigurationEtag + case .FBConfig: return FBConfigEtag } } - - func saveEtag(_ etag: String, for config: ConfigurationLocation) throws { - switch config { - case .bloomFilterSpec: - bloomFilterSpecEtag = etag - - case .bloomFilterBinary: - bloomFilterBinaryEtag = etag - - case .bloomFilterExcludedDomains: - bloomFilterExcludedDomainsEtag = etag - - case .surrogates: - surrogatesEtag = etag - - case .trackerRadar: - trackerRadarEtag = etag - - case .privacyConfiguration: - privacyConfigurationEtag = etag - - case .FBConfig: - return FBConfigEtag = etag + + func loadEmbeddedEtag(for configuration: Configuration) -> String? { + switch configuration { + case .trackerRadar: return AppTrackerDataSetProvider.Constants.embeddedDataETag + case .privacyConfiguration: return AppPrivacyConfigurationDataProvider.Constants.embeddedDataSHA + default: return nil + } + } + + func saveEtag(_ etag: String, for configuration: Configuration) throws { + switch configuration { + case .bloomFilterSpec: bloomFilterSpecEtag = etag + case .bloomFilterBinary: bloomFilterBinaryEtag = etag + case .bloomFilterExcludedDomains: bloomFilterExcludedDomainsEtag = etag + case .surrogates: surrogatesEtag = etag + case .trackerRadar: trackerRadarEtag = etag + case .privacyConfiguration: privacyConfigurationEtag = etag + case .FBConfig: FBConfigEtag = etag } } - func loadData(for config: ConfigurationLocation) -> Data? { + func loadData(for config: Configuration) -> Data? { let file = fileUrl(for: config) do { return try Data(contentsOf: file) } catch { #if DEBUG - guard !AppDelegate.isRunningTests else { return nil } + guard !AppDelegate.isRunningTests else { return nil } #endif - Pixel.fire(.debug(event: .trackerDataCouldNotBeLoaded, error: error)) return nil } } - - func saveData(_ data: Data, for config: ConfigurationLocation) throws { + + func saveData(_ data: Data, for config: Configuration) throws { let file = fileUrl(for: config) try data.write(to: file, options: .atomic) } @@ -145,7 +117,7 @@ final class DefaultConfigurationStorage: ConfigurationStoring { os_log("FBConfigEtag %{public}s", log: .config, type: .default, FBConfigEtag ?? "") } - func fileUrl(for config: ConfigurationLocation) -> URL { + func fileUrl(for config: Configuration) -> URL { let fm = FileManager.default let dir = URL.sandboxApplicationSupportURL diff --git a/DuckDuckGo/Content Blocker/ContentBlocking.swift b/DuckDuckGo/Content Blocker/ContentBlocking.swift index 2e6e7e2f26..547b77d6a8 100644 --- a/DuckDuckGo/Content Blocker/ContentBlocking.swift +++ b/DuckDuckGo/Content Blocker/ContentBlocking.swift @@ -59,15 +59,15 @@ final class AppContentBlocking { // keeping whole ContentBlocking state initialization in one place to avoid races between updates publishing and rules storing init() { - let configStorage = DefaultConfigurationStorage.shared + let configStorage = ConfigurationStore.shared privacyConfigurationManager = PrivacyConfigurationManager(fetchedETag: configStorage.loadEtag(for: .privacyConfiguration), fetchedData: configStorage.loadData(for: .privacyConfiguration), embeddedDataProvider: AppPrivacyConfigurationDataProvider(), localProtection: LocalUnprotectedDomains.shared, errorReporting: Self.debugEvents) - trackerDataManager = TrackerDataManager(etag: DefaultConfigurationStorage.shared.loadEtag(for: .trackerRadar), - data: DefaultConfigurationStorage.shared.loadData(for: .trackerRadar), + trackerDataManager = TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerRadar), + data: ConfigurationStore.shared.loadData(for: .trackerRadar), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: Self.debugEvents) diff --git a/DuckDuckGo/Content Blocker/ScriptSourceProviding.swift b/DuckDuckGo/Content Blocker/ScriptSourceProviding.swift index eda8e99dae..4d9d47e3b1 100644 --- a/DuckDuckGo/Content Blocker/ScriptSourceProviding.swift +++ b/DuckDuckGo/Content Blocker/ScriptSourceProviding.swift @@ -20,6 +20,7 @@ import Foundation import Combine import Common import BrowserServicesKit +import Configuration protocol ScriptSourceProviding { @@ -36,7 +37,7 @@ protocol ScriptSourceProviding { // refactor: ScriptSourceProvider to be passed to init methods as `some ScriptSourceProviding`, DefaultScriptSourceProvider to be killed // swiftlint:disable:next identifier_name func DefaultScriptSourceProvider() -> ScriptSourceProviding { - ScriptSourceProvider(configStorage: DefaultConfigurationStorage.shared, privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager, privacySettings: PrivacySecurityPreferences.shared, contentBlockingManager: ContentBlocking.shared.contentBlockingManager, trackerDataManager: ContentBlocking.shared.trackerDataManager, tld: ContentBlocking.shared.tld) + ScriptSourceProvider(configStorage: ConfigurationStore.shared, privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager, privacySettings: PrivacySecurityPreferences.shared, contentBlockingManager: ContentBlocking.shared.contentBlockingManager, trackerDataManager: ContentBlocking.shared.trackerDataManager, tld: ContentBlocking.shared.tld) } struct ScriptSourceProvider: ScriptSourceProviding { diff --git a/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift b/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift index c189c86c7c..6ccce7c8a8 100644 --- a/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift +++ b/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift @@ -18,6 +18,7 @@ import Foundation import os.log +import API final class FeedbackSender { @@ -37,7 +38,9 @@ final class FeedbackSender { "appversion": appVersion ] - APIRequest.request(url: Self.feedbackURL, method: .post, parameters: parameters) { _, error in + let configuration = APIRequest.Configuration(url: Self.feedbackURL, method: .post, queryParameters: parameters) + let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession()) + request.fetch { _, error in if let error = error { os_log("FeedbackSender: Failed to submit feedback %s", type: .error, error.localizedDescription) Pixel.fire(.debug(event: .feedbackReportingFailed, error: error)) diff --git a/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift b/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift index 4b7b6f8402..707df78da2 100644 --- a/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift +++ b/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift @@ -19,6 +19,7 @@ import Foundation import BrowserServicesKit import os.log +import API final class StatisticsLoader { @@ -78,22 +79,22 @@ final class StatisticsLoader { os_log("Requesting install statistics", log: .atb, type: .debug) - APIRequest.request(url: URL.initialAtb) { response, error in - DispatchQueue.main.async { - self.isAppRetentionRequestInProgress = false - if let error = error { - os_log("Initial atb request failed with error %s", type: .error, error.localizedDescription) - completion() - return - } + let configuration = APIRequest.Configuration(url: URL.initialAtb) + let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + request.fetch { response, error in + self.isAppRetentionRequestInProgress = false + if let error = error { + os_log("Initial atb request failed with error %s", type: .error, error.localizedDescription) + completion() + return + } - os_log("Install statistics request succeeded", log: .atb, type: .debug) + os_log("Install statistics request succeeded", log: .atb, type: .debug) - if let data = response?.data, let atb = try? self.parser.convert(fromJsonData: data) { - self.requestExti(atb: atb, completion: completion) - } else { - completion() - } + if let data = response?.data, let atb = try? self.parser.convert(fromJsonData: data) { + self.requestExti(atb: atb, completion: completion) + } else { + completion() } } } @@ -107,25 +108,25 @@ final class StatisticsLoader { os_log("Requesting exti", log: .atb, type: .debug) let installAtb = atb.version + (statisticsStore.variant ?? "") - let url = URL.exti(forAtb: installAtb) - APIRequest.request(url: url) { _, error in - DispatchQueue.main.async { - self.isAppRetentionRequestInProgress = false - if let error = error { - os_log("Exti request failed with error %s", type: .error, error.localizedDescription) - completion() - return - } + + let configuration = APIRequest.Configuration(url: URL.exti(forAtb: installAtb)) + let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + request.fetch { _, error in + self.isAppRetentionRequestInProgress = false + if let error = error { + os_log("Exti request failed with error %s", type: .error, error.localizedDescription) + completion() + return + } - os_log("Exti request succeeded", log: .atb, type: .debug) + os_log("Exti request succeeded", log: .atb, type: .debug) - assert(self.statisticsStore.atb == nil) - assert(self.statisticsStore.installDate == nil) + assert(self.statisticsStore.atb == nil) + assert(self.statisticsStore.installDate == nil) - self.statisticsStore.installDate = Date() - self.statisticsStore.atb = atb.version - completion() - } + self.statisticsStore.installDate = Date() + self.statisticsStore.atb = atb.version + completion() } } @@ -140,25 +141,25 @@ final class StatisticsLoader { } os_log("Requesting search retention ATB", log: .atb, type: .debug) - + let url = URL.searchAtb(atbWithVariant: atbWithVariant, setAtb: searchRetentionAtb, isSignedIntoEmailProtection: emailManager.isSignedIn) - APIRequest.request(url: url) { response, error in - DispatchQueue.main.async { - if let error = error { - os_log("Search atb request failed with error %s", type: .error, error.localizedDescription) - completion() - return - } - - os_log("Search retention ATB request succeeded", log: .atb, type: .debug) - - if let data = response?.data, let atb = try? self.parser.convert(fromJsonData: data) { - self.statisticsStore.searchRetentionAtb = atb.version - self.storeUpdateVersionIfPresent(atb) - } - + let configuration = APIRequest.Configuration(url: url) + let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + request.fetch { (response, error) in + if let error = error { + os_log("Search atb request failed with error %s", type: .error, error.localizedDescription) completion() + return } + + os_log("Search retention ATB request succeeded", log: .atb, type: .debug) + + if let data = response?.data, let atb = try? self.parser.convert(fromJsonData: data) { + self.statisticsStore.searchRetentionAtb = atb.version + self.storeUpdateVersionIfPresent(atb) + } + + completion() } } @@ -178,29 +179,29 @@ final class StatisticsLoader { isAppRetentionRequestInProgress = true let url = URL.appRetentionAtb(atbWithVariant: atbWithVariant, setAtb: appRetentionAtb) - APIRequest.request(url: url) { response, error in - DispatchQueue.main.async { - self.isAppRetentionRequestInProgress = false - - if let error = error { - os_log("App atb request failed with error %s", type: .error, error.localizedDescription) - completion() - return - } - - os_log("App retention ATB request succeeded", log: .atb, type: .debug) - - if let data = response?.data, let atb = try? self.parser.convert(fromJsonData: data) { - self.statisticsStore.appRetentionAtb = atb.version - self.statisticsStore.lastAppRetentionRequestDate = Date() - self.storeUpdateVersionIfPresent(atb) - } - + let configuration = APIRequest.Configuration(url: url) + let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + request.fetch { response, error in + self.isAppRetentionRequestInProgress = false + + if let error = error { + os_log("App atb request failed with error %s", type: .error, error.localizedDescription) completion() + return } + + os_log("App retention ATB request succeeded", log: .atb, type: .debug) + + if let data = response?.data, let atb = try? self.parser.convert(fromJsonData: data) { + self.statisticsStore.appRetentionAtb = atb.version + self.statisticsStore.lastAppRetentionRequestDate = Date() + self.storeUpdateVersionIfPresent(atb) + } + + completion() } } - + func storeUpdateVersionIfPresent(_ atb: Atb) { dispatchPrecondition(condition: .onQueue(.main)) diff --git a/DuckDuckGo/Statistics/Pixel.swift b/DuckDuckGo/Statistics/Pixel.swift index 64846ee92a..208a8f2bad 100644 --- a/DuckDuckGo/Statistics/Pixel.swift +++ b/DuckDuckGo/Statistics/Pixel.swift @@ -18,6 +18,7 @@ import Foundation import os.log +import API final class Pixel { @@ -53,7 +54,7 @@ final class Pixel { #endif var headers = headers - headers[APIHeaders.Name.moreInfo] = "See " + URL.duckDuckGoMorePrivacyInfo.absoluteString + headers[HTTPHeaderField.moreInfo] = "See " + URL.duckDuckGoMorePrivacyInfo.absoluteString guard !dryRun else { let params = params?.filter { key, _ in !["appVersion", "test"].contains(key) } ?? [:] @@ -65,15 +66,13 @@ final class Pixel { } return } - - let url = URL.pixelUrl(forPixelNamed: pixelName) - APIRequest.request( - url: url, - parameters: newParams, - allowedQueryReservedCharacters: allowedQueryReservedCharacters, - headers: headers, - callBackOnMainThread: true - ) { (_, error) in + + let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: pixelName), + queryParameters: newParams, + allowedQueryReservedCharacters: allowedQueryReservedCharacters, + headers: headers) + let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + request.fetch { (_, error) in onComplete(error) } } @@ -101,7 +100,7 @@ final class Pixel { includeAppVersionParameter: includeAppVersionParameter, onComplete: onComplete) } - + } public func pixelAssertionFailure(_ message: @autoclosure () -> String = String(), file: StaticString = #fileID, line: UInt = #line) { diff --git a/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift b/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift index a6f4037cb2..b3cca5cf0e 100644 --- a/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift +++ b/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift @@ -29,8 +29,8 @@ class AutoconsentMessageProtocolTests: XCTestCase { privacyConfigurationManager: MockPrivacyConfigurationManager(), privacySettings: PrivacySecurityPreferences.shared, // todo: mock contentBlockingManager: ContentBlockerRulesManagerMock(), - trackerDataManager: TrackerDataManager(etag: DefaultConfigurationStorage.shared.loadEtag(for: .trackerRadar), - data: DefaultConfigurationStorage.shared.loadData(for: .trackerRadar), + trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerRadar), + data: ConfigurationStore.shared.loadData(for: .trackerRadar), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: nil), diff --git a/Unit Tests/Configuration/ConfigurationStorageTests.swift b/Unit Tests/Configuration/ConfigurationStorageTests.swift index 9f3dfe4ff6..23824ce407 100644 --- a/Unit Tests/Configuration/ConfigurationStorageTests.swift +++ b/Unit Tests/Configuration/ConfigurationStorageTests.swift @@ -26,7 +26,7 @@ final class ConfigurationStorageTests: XCTestCase { super.tearDown() for config in ConfigurationLocation.allCases { - let url = DefaultConfigurationStorage.shared.fileUrl(for: config) + let url = ConfigurationStore.shared.fileUrl(for: config) try? FileManager.default.removeItem(at: url) } @@ -35,16 +35,16 @@ final class ConfigurationStorageTests: XCTestCase { func test_when_data_is_saved_for_config_then_it_can_be_loaded_correctly() { for config in ConfigurationLocation.allCases { let uuid = UUID().uuidString - try? DefaultConfigurationStorage.shared.saveData(uuid.data(using: .utf8)!, for: config) - XCTAssertEqual(uuid, DefaultConfigurationStorage.shared.loadData(for: config)?.utf8String()) + try? ConfigurationStore.shared.saveData(uuid.data(using: .utf8)!, for: config) + XCTAssertEqual(uuid, ConfigurationStore.shared.loadData(for: config)?.utf8String()) } } func test_when_etag_is_saved_for_config_then_it_can_be_loaded_correctly() { for config in ConfigurationLocation.allCases { let etag = UUID().uuidString - try? DefaultConfigurationStorage.shared.saveEtag(etag, for: config) - XCTAssertEqual(etag, DefaultConfigurationStorage.shared.loadEtag(for: config)) + try? ConfigurationStore.shared.saveEtag(etag, for: config) + XCTAssertEqual(etag, ConfigurationStore.shared.loadEtag(for: config)) } } diff --git a/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift b/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift index 4b9446a30b..4182a661ac 100644 --- a/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift +++ b/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift @@ -32,8 +32,8 @@ class ContentBlockingUpdatingTests: XCTestCase { override func setUp() { updating = UserContentUpdating(contentBlockerRulesManager: rulesManager, privacyConfigurationManager: MockPrivacyConfigurationManager(), - trackerDataManager: TrackerDataManager(etag: DefaultConfigurationStorage.shared.loadEtag(for: .trackerRadar), - data: DefaultConfigurationStorage.shared.loadData(for: .trackerRadar), + trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerRadar), + data: ConfigurationStore.shared.loadData(for: .trackerRadar), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: nil), configStorage: ConfigurationDownloaderTests.MockStorage(), From 3f5a4918a060ae7ce4b018d9a1e88af55e54b5e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 20 Feb 2023 17:51:13 +0100 Subject: [PATCH 02/16] Implement AppConfigurationURLProvider --- DuckDuckGo.xcodeproj/project.pbxproj | 6 +++ .../AppConfigurationURLProvider.swift | 37 +++++++++++++++++++ DuckDuckGo/App Delegate/AppDelegate.swift | 2 + 3 files changed, 45 insertions(+) create mode 100644 DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index e99b438200..7e7d3c8f8b 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1694,6 +1694,8 @@ B6FA893D269C423100588ECD /* PrivacyDashboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6FA893C269C423100588ECD /* PrivacyDashboard.storyboard */; }; B6FA893F269C424500588ECD /* PrivacyDashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA893E269C424500588ECD /* PrivacyDashboardViewController.swift */; }; B6FA8941269C425400588ECD /* PrivacyDashboardPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */; }; + CB24F70C29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; + CB24F70D29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; CB6BCDF927C6BEFF00CC76DC /* PrivacyFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */; }; CB7E2B8B29A24CBF00997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8A29A24CBF00997A73 /* Configuration */; }; CB7E2B8D29A24D3800997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8C29A24D3800997A73 /* Configuration */; }; @@ -2634,6 +2636,7 @@ B6FA893C269C423100588ECD /* PrivacyDashboard.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PrivacyDashboard.storyboard; sourceTree = ""; }; B6FA893E269C424500588ECD /* PrivacyDashboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardViewController.swift; sourceTree = ""; }; B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardPopover.swift; sourceTree = ""; }; + CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfigurationURLProvider.swift; sourceTree = ""; }; CB5E2CF629A1A5680062D13E /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyFeatures.swift; sourceTree = ""; }; EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClickToLoadUserScript.swift; sourceTree = ""; }; @@ -4094,6 +4097,7 @@ AAD86E51267A0DFF005C11BE /* UpdateController.swift */, 858A798226A8B75F00A75A42 /* CopyHandler.swift */, 1D36E65A298ACD2900AA485D /* AppIconChanger.swift */, + CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */, ); path = "App Delegate"; sourceTree = ""; @@ -6222,6 +6226,7 @@ 3706FB02293F65D500E42796 /* Onboarding.swift in Sources */, 3706FEB8293F6EFB00E42796 /* ConnectBitwardenView.swift in Sources */, 3706FB03293F65D500E42796 /* PopUpWindow.swift in Sources */, + CB24F70D29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */, 3706FB04293F65D500E42796 /* PersistentAppInterfaceSettings.swift in Sources */, 3706FB05293F65D500E42796 /* Favicons.xcdatamodeld in Sources */, 3706FB06293F65D500E42796 /* HoverButton.swift in Sources */, @@ -7066,6 +7071,7 @@ B6AAAC2D260330580029438D /* PublishedAfter.swift in Sources */, 37054FCE2876472D00033B6F /* WebViewSnapshotView.swift in Sources */, 4BBC16A027C4859400E00A38 /* DeviceAuthenticationService.swift in Sources */, + CB24F70C29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */, 3776582F27F82E62009A6B35 /* AutofillPreferences.swift in Sources */, AAD8078727B3F45600CF7703 /* WebsiteBreakage.swift in Sources */, 1D074B272909A433006E4AC3 /* PasswordManagerCoordinator.swift in Sources */, diff --git a/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift new file mode 100644 index 0000000000..dcf503657a --- /dev/null +++ b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift @@ -0,0 +1,37 @@ +// +// AppConfigurationURLProvider.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Configuration + +struct AppConfigurationURLProvider: ConfigurationURLProvider { + + func url(for configuration: Configuration) -> URL { + switch configuration { + case .bloomFilterBinary: return URL(string: "https://staticcdn.duckduckgo.com/https/https-mobile-v2-bloom.bin")! + case .bloomFilterSpec: return URL(string: "https://staticcdn.duckduckgo.com/https/https-mobile-v2-bloom-spec.json")! + case .bloomFilterExcludedDomains: return URL(string: "https://staticcdn.duckduckgo.com/https/https-mobile-v2-false-positives.json")! + case .privacyConfiguration: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/config/v2/macos-config.json")! // TODO!! + case .surrogates: return URL(string: "https://duckduckgo.com/contentblocking.js?l=surrogates")! + case .trackerRadar: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/v3/apple-tds.json")! + // In archived repo, to be refactored shortly (https://staticcdn.duckduckgo.com/useragents/social_ctp_configuration.json) + case .FBConfig: return URL(string: "https://staticcdn.duckduckgo.com/useragents/")! + } + } + +} diff --git a/DuckDuckGo/App Delegate/AppDelegate.swift b/DuckDuckGo/App Delegate/AppDelegate.swift index a981d6050e..5338dd1007 100644 --- a/DuckDuckGo/App Delegate/AppDelegate.swift +++ b/DuckDuckGo/App Delegate/AppDelegate.swift @@ -21,6 +21,7 @@ import Combine import os.log import BrowserServicesKit import Persistence +import Configuration @NSApplicationMain final class AppDelegate: NSObject, NSApplicationDelegate { @@ -120,6 +121,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { guard !Self.isRunningTests else { return } + Configuration.setUrlProvider(AppConfigurationURLProvider()) HistoryCoordinator.shared.loadHistory() PrivacyFeatures.httpsUpgrade.loadDataAsync() LocalBookmarkManager.shared.loadBookmarks() From 292e7c3e07c4cd5972320ad5bd48deccec2bd1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 20 Feb 2023 18:14:25 +0100 Subject: [PATCH 03/16] Use AppVersion from BSK --- DuckDuckGo.xcodeproj/project.pbxproj | 6 --- .../AppConfigurationURLProvider.swift | 6 +-- DuckDuckGo/App Delegate/AppDelegate.swift | 2 +- DuckDuckGo/Common/AppVersion.swift | 51 ------------------- .../View/FeedbackViewController.swift | 1 + DuckDuckGo/Preferences/Model/AboutModel.swift | 1 + .../Model/DefaultBrowserPreferences.swift | 1 + DuckDuckGo/Statistics/Pixel.swift | 1 + 8 files changed, 8 insertions(+), 61 deletions(-) delete mode 100644 DuckDuckGo/Common/AppVersion.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 7e7d3c8f8b..b51b6b5cf8 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -321,7 +321,6 @@ 3706FB75293F65D500E42796 /* WebsiteBreakageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD8078427B3F3BE00CF7703 /* WebsiteBreakageSender.swift */; }; 3706FB76293F65D500E42796 /* ASN1Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8AC93A26B48ADF00879451 /* ASN1Parser.swift */; }; 3706FB77293F65D500E42796 /* View+Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54B227EE509700F1F7B9 /* View+Cursor.swift */; }; - 3706FB79293F65D500E42796 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E4602614608B0067D1B9 /* AppVersion.swift */; }; 3706FB7A293F65D500E42796 /* FileDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856C98DE257014BD00A22F1F /* FileDownloadManager.swift */; }; 3706FB7B293F65D500E42796 /* BookmarkImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CF626FE191E001E4761 /* BookmarkImport.swift */; }; 3706FB7C293F65D500E42796 /* KeySetDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68503A6279141CD00893A05 /* KeySetDictionary.swift */; }; @@ -1619,7 +1618,6 @@ B6A924D92664C72E001A28CA /* WebKitDownloadTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */; }; B6A924DE2664CA09001A28CA /* LegacyWebKitDownloadDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A924DD2664CA08001A28CA /* LegacyWebKitDownloadDelegate.swift */; }; B6A9E45326142B070067D1B9 /* Pixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E45226142B070067D1B9 /* Pixel.swift */; }; - B6A9E4612614608B0067D1B9 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E4602614608B0067D1B9 /* AppVersion.swift */; }; B6A9E46B2614618A0067D1B9 /* OperatingSystemVersionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E46A2614618A0067D1B9 /* OperatingSystemVersionExtension.swift */; }; B6A9E47026146A250067D1B9 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E46F26146A250067D1B9 /* DateExtension.swift */; }; B6A9E47726146A570067D1B9 /* PixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E47626146A570067D1B9 /* PixelEvent.swift */; }; @@ -2571,7 +2569,6 @@ B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebKitDownloadTask.swift; sourceTree = ""; }; B6A924DD2664CA08001A28CA /* LegacyWebKitDownloadDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyWebKitDownloadDelegate.swift; sourceTree = ""; }; B6A9E45226142B070067D1B9 /* Pixel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pixel.swift; sourceTree = ""; }; - B6A9E4602614608B0067D1B9 /* AppVersion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = ""; }; B6A9E46A2614618A0067D1B9 /* OperatingSystemVersionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatingSystemVersionExtension.swift; sourceTree = ""; }; B6A9E46F26146A250067D1B9 /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = ""; }; B6A9E47626146A570067D1B9 /* PixelEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelEvent.swift; sourceTree = ""; }; @@ -4496,7 +4493,6 @@ AA86491324D831B9001BABEE /* Common */ = { isa = PBXGroup; children = ( - B6A9E4602614608B0067D1B9 /* AppVersion.swift */, 4B67743D255DBEEA00025BD8 /* Database */, AADC60E92493B305008F8EF7 /* Extensions */, 4BA1A691258B06F600F6F690 /* File System */, @@ -6350,7 +6346,6 @@ 3707C72A294B5D2900682A9F /* URLExtension.swift in Sources */, 3706FB76293F65D500E42796 /* ASN1Parser.swift in Sources */, 3706FB77293F65D500E42796 /* View+Cursor.swift in Sources */, - 3706FB79293F65D500E42796 /* AppVersion.swift in Sources */, 3706FB7A293F65D500E42796 /* FileDownloadManager.swift in Sources */, 3706FB7B293F65D500E42796 /* BookmarkImport.swift in Sources */, 3706FB7C293F65D500E42796 /* KeySetDictionary.swift in Sources */, @@ -7155,7 +7150,6 @@ 4B8AC93B26B48ADF00879451 /* ASN1Parser.swift in Sources */, 37CD54B327EE509700F1F7B9 /* View+Cursor.swift in Sources */, B66E9DD22670EB2A00E53BB5 /* _WKDownload+WebKitDownload.swift in Sources */, - B6A9E4612614608B0067D1B9 /* AppVersion.swift in Sources */, 856C98DF257014BD00A22F1F /* FileDownloadManager.swift in Sources */, 4BB99CFF26FE191E001E4761 /* BookmarkImport.swift in Sources */, B68503A7279141CD00893A05 /* KeySetDictionary.swift in Sources */, diff --git a/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift index dcf503657a..c1e9baf41d 100644 --- a/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift +++ b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift @@ -20,18 +20,18 @@ import Foundation import Configuration struct AppConfigurationURLProvider: ConfigurationURLProvider { - + func url(for configuration: Configuration) -> URL { switch configuration { case .bloomFilterBinary: return URL(string: "https://staticcdn.duckduckgo.com/https/https-mobile-v2-bloom.bin")! case .bloomFilterSpec: return URL(string: "https://staticcdn.duckduckgo.com/https/https-mobile-v2-bloom-spec.json")! case .bloomFilterExcludedDomains: return URL(string: "https://staticcdn.duckduckgo.com/https/https-mobile-v2-false-positives.json")! - case .privacyConfiguration: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/config/v2/macos-config.json")! // TODO!! + case .privacyConfiguration: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/config/v2/macos-config.json")! case .surrogates: return URL(string: "https://duckduckgo.com/contentblocking.js?l=surrogates")! case .trackerRadar: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/v3/apple-tds.json")! // In archived repo, to be refactored shortly (https://staticcdn.duckduckgo.com/useragents/social_ctp_configuration.json) case .FBConfig: return URL(string: "https://staticcdn.duckduckgo.com/useragents/")! } } - + } diff --git a/DuckDuckGo/App Delegate/AppDelegate.swift b/DuckDuckGo/App Delegate/AppDelegate.swift index 5338dd1007..8b6e102897 100644 --- a/DuckDuckGo/App Delegate/AppDelegate.swift +++ b/DuckDuckGo/App Delegate/AppDelegate.swift @@ -121,7 +121,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { guard !Self.isRunningTests else { return } - Configuration.setUrlProvider(AppConfigurationURLProvider()) + Configuration.setURLProvider(AppConfigurationURLProvider()) HistoryCoordinator.shared.loadHistory() PrivacyFeatures.httpsUpgrade.loadDataAsync() LocalBookmarkManager.shared.loadBookmarks() diff --git a/DuckDuckGo/Common/AppVersion.swift b/DuckDuckGo/Common/AppVersion.swift deleted file mode 100644 index 56c0a84d84..0000000000 --- a/DuckDuckGo/Common/AppVersion.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// AppVersion.swift -// -// Copyright © 2017 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -struct AppVersion { - - static let shared = AppVersion() - - private let bundle: Bundle - - init(bundle: Bundle = .main) { - self.bundle = bundle - } - - var name: String { - return bundle.object(forInfoDictionaryKey: Bundle.Keys.name) as? String ?? "" - } - - var identifier: String { - return bundle.object(forInfoDictionaryKey: Bundle.Keys.identifier) as? String ?? "" - } - - var majorVersionNumber: String { - return String(versionNumber.split(separator: ".").first ?? "") - } - - var versionNumber: String { - return bundle.object(forInfoDictionaryKey: Bundle.Keys.versionNumber) as? String ?? "" - } - - var buildNumber: String { - return bundle.object(forInfoDictionaryKey: Bundle.Keys.buildNumber) as? String ?? "" - } - -} diff --git a/DuckDuckGo/Feedback and Breakage/View/FeedbackViewController.swift b/DuckDuckGo/Feedback and Breakage/View/FeedbackViewController.swift index c9008bd009..613b7923f5 100644 --- a/DuckDuckGo/Feedback and Breakage/View/FeedbackViewController.swift +++ b/DuckDuckGo/Feedback and Breakage/View/FeedbackViewController.swift @@ -18,6 +18,7 @@ import Cocoa import Combine +import Common final class FeedbackViewController: NSViewController { diff --git a/DuckDuckGo/Preferences/Model/AboutModel.swift b/DuckDuckGo/Preferences/Model/AboutModel.swift index 7a5a70a4e3..c9929a2a97 100644 --- a/DuckDuckGo/Preferences/Model/AboutModel.swift +++ b/DuckDuckGo/Preferences/Model/AboutModel.swift @@ -17,6 +17,7 @@ // import SwiftUI +import Common final class AboutModel: ObservableObject { let appVersion = AppVersion() diff --git a/DuckDuckGo/Preferences/Model/DefaultBrowserPreferences.swift b/DuckDuckGo/Preferences/Model/DefaultBrowserPreferences.swift index 5e59df69e3..b2c2f027ca 100644 --- a/DuckDuckGo/Preferences/Model/DefaultBrowserPreferences.swift +++ b/DuckDuckGo/Preferences/Model/DefaultBrowserPreferences.swift @@ -19,6 +19,7 @@ import Foundation import SwiftUI import Combine +import Common protocol DefaultBrowserProvider { var bundleIdentifier: String { get } diff --git a/DuckDuckGo/Statistics/Pixel.swift b/DuckDuckGo/Statistics/Pixel.swift index 208a8f2bad..9963ec2aa5 100644 --- a/DuckDuckGo/Statistics/Pixel.swift +++ b/DuckDuckGo/Statistics/Pixel.swift @@ -19,6 +19,7 @@ import Foundation import os.log import API +import Common final class Pixel { From 08de47e7157f0927e172c9c4f571da2b29813217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 20 Feb 2023 18:19:05 +0100 Subject: [PATCH 04/16] Set correct user agent --- DuckDuckGo/App Delegate/AppDelegate.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DuckDuckGo/App Delegate/AppDelegate.swift b/DuckDuckGo/App Delegate/AppDelegate.swift index 8b6e102897..1a9ca27d0f 100644 --- a/DuckDuckGo/App Delegate/AppDelegate.swift +++ b/DuckDuckGo/App Delegate/AppDelegate.swift @@ -22,6 +22,7 @@ import os.log import BrowserServicesKit import Persistence import Configuration +import API @NSApplicationMain final class AppDelegate: NSObject, NSApplicationDelegate { @@ -121,6 +122,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { guard !Self.isRunningTests else { return } + APIHeaders.userAgent = UserAgent.duckDuckGoUserAgent() Configuration.setURLProvider(AppConfigurationURLProvider()) HistoryCoordinator.shared.loadHistory() PrivacyFeatures.httpsUpgrade.loadDataAsync() From ce7b8ba85f885469902a72191d94b0c91b0c9660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Tue, 21 Feb 2023 17:29:58 +0100 Subject: [PATCH 05/16] Fix for new API in BSK --- DuckDuckGo/App Delegate/AppDelegate.swift | 3 ++- DuckDuckGo/Configuration/ConfigurationManager.swift | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/App Delegate/AppDelegate.swift b/DuckDuckGo/App Delegate/AppDelegate.swift index 1a9ca27d0f..faf7c37473 100644 --- a/DuckDuckGo/App Delegate/AppDelegate.swift +++ b/DuckDuckGo/App Delegate/AppDelegate.swift @@ -122,8 +122,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { guard !Self.isRunningTests else { return } - APIHeaders.userAgent = UserAgent.duckDuckGoUserAgent() + APIHeaders.setUserAgent(UserAgent.duckDuckGoUserAgent()) Configuration.setURLProvider(AppConfigurationURLProvider()) + HistoryCoordinator.shared.loadHistory() PrivacyFeatures.httpsUpgrade.loadDataAsync() LocalBookmarkManager.shared.loadBookmarks() diff --git a/DuckDuckGo/Configuration/ConfigurationManager.swift b/DuckDuckGo/Configuration/ConfigurationManager.swift index a2f6cf97d6..f0987d5fb7 100644 --- a/DuckDuckGo/Configuration/ConfigurationManager.swift +++ b/DuckDuckGo/Configuration/ConfigurationManager.swift @@ -83,7 +83,7 @@ final class ConfigurationManager { let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared) do { try await fetcher.fetch([.trackerRadar, .surrogates, .privacyConfiguration]) { - try self.updateTrackerBlockingDependencies() + self.updateTrackerBlockingDependencies() self.tryAgainLater() } } catch { @@ -140,7 +140,7 @@ final class ConfigurationManager { lastUpdateTime = Date(timeIntervalSinceNow: Constants.refreshPeriodSeconds - Constants.retryDelaySeconds) } - private func updateTrackerBlockingDependencies() throws { + private func updateTrackerBlockingDependencies() { let tdsEtag = ConfigurationStore.shared.loadEtag(for: .trackerRadar) let tdsData = ConfigurationStore.shared.loadData(for: .trackerRadar) ContentBlocking.shared.trackerDataManager.reload(etag: tdsEtag, data: tdsData) From 8eb836e357751b708eb7b0adfa64a3390e23cf3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Wed, 22 Feb 2023 14:54:38 +0100 Subject: [PATCH 06/16] Update to the newest bsk changes --- .../AppConfigurationURLProvider.swift | 2 +- .../Configuration/ConfigurationManager.swift | 28 +++++++++---------- .../Configuration/ConfigurationStore.swift | 14 +++++----- .../Content Blocker/ContentBlocking.swift | 4 +-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift index c1e9baf41d..93846eda7d 100644 --- a/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift +++ b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift @@ -28,7 +28,7 @@ struct AppConfigurationURLProvider: ConfigurationURLProvider { case .bloomFilterExcludedDomains: return URL(string: "https://staticcdn.duckduckgo.com/https/https-mobile-v2-false-positives.json")! case .privacyConfiguration: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/config/v2/macos-config.json")! case .surrogates: return URL(string: "https://duckduckgo.com/contentblocking.js?l=surrogates")! - case .trackerRadar: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/v3/apple-tds.json")! + case .trackerDataSet: return URL(string: "https://staticcdn.duckduckgo.com/trackerblocking/v3/apple-tds.json")! // In archived repo, to be refactored shortly (https://staticcdn.duckduckgo.com/useragents/social_ctp_configuration.json) case .FBConfig: return URL(string: "https://staticcdn.duckduckgo.com/useragents/")! } diff --git a/DuckDuckGo/Configuration/ConfigurationManager.swift b/DuckDuckGo/Configuration/ConfigurationManager.swift index f0987d5fb7..1808ef4921 100644 --- a/DuckDuckGo/Configuration/ConfigurationManager.swift +++ b/DuckDuckGo/Configuration/ConfigurationManager.swift @@ -25,18 +25,18 @@ import Configuration final class ConfigurationManager { enum Error: Swift.Error { - + case timeout case bloomFilterSpecNotFound case bloomFilterBinaryNotFound case bloomFilterPersistenceFailed case bloomFilterExclusionsNotFound case bloomFilterExclusionsPersistenceFailed - + } enum Constants { - + static let downloadTimeoutSeconds = 60.0 * 5 #if DEBUG static let refreshPeriodSeconds = 60.0 * 2 // 2 minutes @@ -45,7 +45,7 @@ final class ConfigurationManager { #endif static let retryDelaySeconds = 60.0 * 60 * 1 // 1 hour delay before checking again if something went wrong last time static let refreshCheckIntervalSeconds = 60.0 // check if we need a refresh every minute - + } static let shared = ConfigurationManager() @@ -79,17 +79,17 @@ final class ConfigurationManager { } private func refreshNow() async { - + let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared) do { - try await fetcher.fetch([.trackerRadar, .surrogates, .privacyConfiguration]) { + try await fetcher.fetch([.trackerDataSet, .surrogates, .privacyConfiguration]) { self.updateTrackerBlockingDependencies() self.tryAgainLater() } } catch { handleRefreshError(error) } - + do { try await fetcher.fetch([.bloomFilterBinary, .bloomFilterSpec]) { try self.updateBloomFilter() @@ -98,7 +98,7 @@ final class ConfigurationManager { } catch { handleRefreshError(error) } - + do { try await fetcher.fetch([.bloomFilterExcludedDomains]) { try self.updateBloomFilterExclusions() @@ -107,14 +107,14 @@ final class ConfigurationManager { } catch { handleRefreshError(error) } - + ConfigurationStore.shared.log() log() - + } - + private func handleRefreshError(_ error: Swift.Error) { - os_log("Failed to complete configuration update %s", log: .config, type: .error, error.localizedDescription) + os_log("Failed to complete configuration update %@", log: .config, type: .error, error.localizedDescription) Pixel.fire(.debug(event: .configurationFetchError, error: error)) tryAgainSoon() } @@ -141,8 +141,8 @@ final class ConfigurationManager { } private func updateTrackerBlockingDependencies() { - let tdsEtag = ConfigurationStore.shared.loadEtag(for: .trackerRadar) - let tdsData = ConfigurationStore.shared.loadData(for: .trackerRadar) + let tdsEtag = ConfigurationStore.shared.loadEtag(for: .trackerDataSet) + let tdsData = ConfigurationStore.shared.loadData(for: .trackerDataSet) ContentBlocking.shared.trackerDataManager.reload(etag: tdsEtag, data: tdsData) let configEtag = ConfigurationStore.shared.loadEtag(for: .privacyConfiguration) diff --git a/DuckDuckGo/Configuration/ConfigurationStore.swift b/DuckDuckGo/Configuration/ConfigurationStore.swift index 84d571a3a5..acaa7de694 100644 --- a/DuckDuckGo/Configuration/ConfigurationStore.swift +++ b/DuckDuckGo/Configuration/ConfigurationStore.swift @@ -28,7 +28,7 @@ final class ConfigurationStore: ConfigurationStoring { .bloomFilterSpec: "smarterEncryptionSpec.json", .surrogates: "surrogates.txt", .privacyConfiguration: "macos-config.json", - .trackerRadar: "tracker-radar.json", + .trackerDataSet: "tracker-radar.json", .FBConfig: "social_ctp_configuration.json" ] @@ -63,27 +63,27 @@ final class ConfigurationStore: ConfigurationStoring { case .bloomFilterBinary: return bloomFilterBinaryEtag case .bloomFilterExcludedDomains: return bloomFilterExcludedDomainsEtag case .surrogates: return surrogatesEtag - case .trackerRadar: return trackerRadarEtag + case .trackerDataSet: return trackerRadarEtag case .privacyConfiguration: return privacyConfigurationEtag case .FBConfig: return FBConfigEtag } } - + func loadEmbeddedEtag(for configuration: Configuration) -> String? { switch configuration { - case .trackerRadar: return AppTrackerDataSetProvider.Constants.embeddedDataETag + case .trackerDataSet: return AppTrackerDataSetProvider.Constants.embeddedDataETag case .privacyConfiguration: return AppPrivacyConfigurationDataProvider.Constants.embeddedDataSHA default: return nil } } - + func saveEtag(_ etag: String, for configuration: Configuration) throws { switch configuration { case .bloomFilterSpec: bloomFilterSpecEtag = etag case .bloomFilterBinary: bloomFilterBinaryEtag = etag case .bloomFilterExcludedDomains: bloomFilterExcludedDomainsEtag = etag case .surrogates: surrogatesEtag = etag - case .trackerRadar: trackerRadarEtag = etag + case .trackerDataSet: trackerRadarEtag = etag case .privacyConfiguration: privacyConfigurationEtag = etag case .FBConfig: FBConfigEtag = etag } @@ -101,7 +101,7 @@ final class ConfigurationStore: ConfigurationStoring { return nil } } - + func saveData(_ data: Data, for config: Configuration) throws { let file = fileUrl(for: config) try data.write(to: file, options: .atomic) diff --git a/DuckDuckGo/Content Blocker/ContentBlocking.swift b/DuckDuckGo/Content Blocker/ContentBlocking.swift index 547b77d6a8..5848a54e85 100644 --- a/DuckDuckGo/Content Blocker/ContentBlocking.swift +++ b/DuckDuckGo/Content Blocker/ContentBlocking.swift @@ -66,8 +66,8 @@ final class AppContentBlocking { localProtection: LocalUnprotectedDomains.shared, errorReporting: Self.debugEvents) - trackerDataManager = TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerRadar), - data: ConfigurationStore.shared.loadData(for: .trackerRadar), + trackerDataManager = TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), + data: ConfigurationStore.shared.loadData(for: .trackerDataSet), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: Self.debugEvents) From 26ad982487ce2c13b8180309a54c27039060bcf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Wed, 22 Feb 2023 18:08:52 +0100 Subject: [PATCH 07/16] Fix tests --- DuckDuckGo.xcodeproj/project.pbxproj | 12 +- .../Utilities/UserDefaultsWrapper.swift | 2 +- .../AutoconsentBackgroundTests.swift | 23 +- .../AutoconsentMessageProtocolTests.swift | 7 +- .../ConfigurationDownloaderTests.swift | 358 ------------------ .../ConfigurationStorageTests.swift | 9 +- .../AppPrivacyConfigurationTests.swift | 5 +- .../ContentBlockingUpdatingTests.swift | 10 +- .../MockConfigurationStore.swift | 63 +++ .../BrokenSiteReportingReferenceTests.swift | 14 +- .../PrivacyReferenceTestHelper.swift | 9 +- Unit Tests/Statistics/PixelTests.swift | 1 + .../WebsiteBreakageReportTests.swift | 14 +- 13 files changed, 112 insertions(+), 415 deletions(-) delete mode 100644 Unit Tests/Configuration/ConfigurationDownloaderTests.swift create mode 100644 Unit Tests/Content Blocker/MockConfigurationStore.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index b51b6b5cf8..705c1a9893 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -812,7 +812,6 @@ 3706FE5D293F661700E42796 /* FileSystemDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF09222830812900EE1418 /* FileSystemDSL.swift */; }; 3706FE5E293F661700E42796 /* DataImportMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DFF26B0003E00E14D75 /* DataImportMocks.swift */; }; 3706FE5F293F661700E42796 /* CrashReportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B70C00027B0793D000386ED /* CrashReportTests.swift */; }; - 3706FE60293F661700E42796 /* ConfigurationDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B1625D9BC1A00C7D2AA /* ConfigurationDownloaderTests.swift */; }; 3706FE61293F661700E42796 /* PinnedTabsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D23786287F5C2900BCE03B /* PinnedTabsViewModelTests.swift */; }; 3706FE62293F661700E42796 /* PasswordManagementListSectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF4EA4F27C71F26004E57C4 /* PasswordManagementListSectionTests.swift */; }; 3706FE63293F661700E42796 /* RecentlyClosedCoordinatorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7E9175286DB05D00AB6B62 /* RecentlyClosedCoordinatorMock.swift */; }; @@ -1266,7 +1265,6 @@ 85AC3AEF25D5CE9800C7D2AA /* UserScripts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3AEE25D5CE9800C7D2AA /* UserScripts.swift */; }; 85AC3AF725D5DBFD00C7D2AA /* DataExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3AF625D5DBFD00C7D2AA /* DataExtension.swift */; }; 85AC3B0525D6B1D800C7D2AA /* ScriptSourceProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B0425D6B1D800C7D2AA /* ScriptSourceProviding.swift */; }; - 85AC3B1725D9BC1A00C7D2AA /* ConfigurationDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B1625D9BC1A00C7D2AA /* ConfigurationDownloaderTests.swift */; }; 85AC3B3525DA82A600C7D2AA /* DataTaskProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B3425DA82A600C7D2AA /* DataTaskProviding.swift */; }; 85AC3B4925DAC9BD00C7D2AA /* ConfigurationStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B4825DAC9BD00C7D2AA /* ConfigurationStorageTests.swift */; }; 85AC7AD927BD625000FFB69B /* HomePageAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 85AC7AD827BD625000FFB69B /* HomePageAssets.xcassets */; }; @@ -1697,6 +1695,8 @@ CB6BCDF927C6BEFF00CC76DC /* PrivacyFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */; }; CB7E2B8B29A24CBF00997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8A29A24CBF00997A73 /* Configuration */; }; CB7E2B8D29A24D3800997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8C29A24D3800997A73 /* Configuration */; }; + CBDD5DE329A67F2700832877 /* MockConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */; }; + CBDD5DE429A6800300832877 /* MockConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */; }; EA0BA3A9272217E6002A0B6C /* ClickToLoadUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */; }; EA18D1CA272F0DC8006DC101 /* social_images in Resources */ = {isa = PBXBuildFile; fileRef = EA18D1C9272F0DC8006DC101 /* social_images */; }; EA1E52B52798CF98002EC53C /* ClickToLoadModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1E52B42798CF98002EC53C /* ClickToLoadModelTests.swift */; }; @@ -2205,7 +2205,6 @@ 85AC3AEE25D5CE9800C7D2AA /* UserScripts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserScripts.swift; sourceTree = ""; }; 85AC3AF625D5DBFD00C7D2AA /* DataExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataExtension.swift; sourceTree = ""; }; 85AC3B0425D6B1D800C7D2AA /* ScriptSourceProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptSourceProviding.swift; sourceTree = ""; }; - 85AC3B1625D9BC1A00C7D2AA /* ConfigurationDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationDownloaderTests.swift; sourceTree = ""; }; 85AC3B3425DA82A600C7D2AA /* DataTaskProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTaskProviding.swift; sourceTree = ""; }; 85AC3B4825DAC9BD00C7D2AA /* ConfigurationStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationStorageTests.swift; sourceTree = ""; }; 85AC7AD827BD625000FFB69B /* HomePageAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HomePageAssets.xcassets; sourceTree = ""; }; @@ -2636,6 +2635,7 @@ CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfigurationURLProvider.swift; sourceTree = ""; }; CB5E2CF629A1A5680062D13E /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyFeatures.swift; sourceTree = ""; }; + CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockConfigurationStore.swift; sourceTree = ""; }; EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClickToLoadUserScript.swift; sourceTree = ""; }; EA18D1C9272F0DC8006DC101 /* social_images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = social_images; sourceTree = ""; }; EA1E52B42798CF98002EC53C /* ClickToLoadModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClickToLoadModelTests.swift; sourceTree = ""; }; @@ -3484,6 +3484,7 @@ B610F2E727AA397100FCEBE9 /* ContentBlockerRulesManagerMock.swift */, B6AE39F029373AF200C37AA4 /* EmptyAttributionRulesProver.swift */, B6BDD9F429409DDD00F68088 /* ContentBlockingMock.swift */, + CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */, ); path = "Content Blocker"; sourceTree = ""; @@ -3862,7 +3863,6 @@ 85AC3B1525D9BBFA00C7D2AA /* Configuration */ = { isa = PBXGroup; children = ( - 85AC3B1625D9BC1A00C7D2AA /* ConfigurationDownloaderTests.swift */, 85AC3B4825DAC9BD00C7D2AA /* ConfigurationStorageTests.swift */, ); path = Configuration; @@ -6706,6 +6706,7 @@ 3706FE0A293F661700E42796 /* UserAgentTests.swift in Sources */, 3706FE0B293F661700E42796 /* AVCaptureDeviceMock.swift in Sources */, 3706FE0C293F661700E42796 /* GeolocationProviderMock.swift in Sources */, + CBDD5DE429A6800300832877 /* MockConfigurationStore.swift in Sources */, 3706FE0D293F661700E42796 /* MainMenuTests.swift in Sources */, 3706FE0E293F661700E42796 /* FirefoxDataImporterTests.swift in Sources */, 3706FE0F293F661700E42796 /* CSVLoginExporterTests.swift in Sources */, @@ -6795,7 +6796,6 @@ 3706FE5D293F661700E42796 /* FileSystemDSL.swift in Sources */, 3706FE5E293F661700E42796 /* DataImportMocks.swift in Sources */, 3706FE5F293F661700E42796 /* CrashReportTests.swift in Sources */, - 3706FE60293F661700E42796 /* ConfigurationDownloaderTests.swift in Sources */, 3706FE61293F661700E42796 /* PinnedTabsViewModelTests.swift in Sources */, 3706FE62293F661700E42796 /* PasswordManagementListSectionTests.swift in Sources */, 3706FE63293F661700E42796 /* RecentlyClosedCoordinatorMock.swift in Sources */, @@ -7551,6 +7551,7 @@ B6106BAF26A7C6180013B453 /* PermissionStoreMock.swift in Sources */, 4B98D27A28D95F1A003C2B6F /* ChromiumFaviconsReaderTests.swift in Sources */, AA652CD325DDA6E9009059CC /* LocalBookmarkManagerTests.swift in Sources */, + CBDD5DE329A67F2700832877 /* MockConfigurationStore.swift in Sources */, B63ED0DC26AE7B1E00A9DAD1 /* WebViewMock.swift in Sources */, 4B4F72EC266B2ED300814C60 /* CollectionExtension.swift in Sources */, AAE39D1B24F44885008EF28B /* TabCollectionViewModelDelegateMock.swift in Sources */, @@ -7604,7 +7605,6 @@ 4BBF09232830812900EE1418 /* FileSystemDSL.swift in Sources */, 4B723E0526B0003E00E14D75 /* DataImportMocks.swift in Sources */, 4B70C00227B0793D000386ED /* CrashReportTests.swift in Sources */, - 85AC3B1725D9BC1A00C7D2AA /* ConfigurationDownloaderTests.swift in Sources */, 37D23787287F5C2900BCE03B /* PinnedTabsViewModelTests.swift in Sources */, 4BF4EA5027C71F26004E57C4 /* PasswordManagementListSectionTests.swift in Sources */, AA7E9176286DB05D00AB6B62 /* RecentlyClosedCoordinatorMock.swift in Sources */, diff --git a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift index 1ec4229a1d..948f6527d6 100644 --- a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift +++ b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift @@ -24,7 +24,7 @@ public struct UserDefaultsWrapper { public enum Key: String, CaseIterable { case configLastUpdated = "config.last.updated" - case configStorageTrackerRadarEtag = "config.storage.trackerradar.etag" + case configStorageTrackerRadarEtag = "config.storage.trackerDataSet.etag" case configStorageBloomFilterSpecEtag = "config.storage.bloomfilter.spec.etag" case configStorageBloomFilterBinaryEtag = "config.storage.bloomfilter.binary.etag" case configStorageBloomFilterExclusionsEtag = "config.storage.bloomfilter.exclusions.etag" diff --git a/Integration Tests/Autoconsent/AutoconsentBackgroundTests.swift b/Integration Tests/Autoconsent/AutoconsentBackgroundTests.swift index b11c4d2085..9271afa981 100644 --- a/Integration Tests/Autoconsent/AutoconsentBackgroundTests.swift +++ b/Integration Tests/Autoconsent/AutoconsentBackgroundTests.swift @@ -20,6 +20,7 @@ import XCTest import Common import BrowserServicesKit import TrackerRadarKit +import Configuration @testable import DuckDuckGo_Privacy_Browser @available(macOS 11, *) @@ -36,8 +37,8 @@ class AutoconsentBackgroundTests: XCTestCase { privacyConfigurationManager: MockPrivacyConfigurationManager(), privacySettings: preferences, contentBlockingManager: ContentBlockerRulesManagerMock(), - trackerDataManager: TrackerDataManager(etag: DefaultConfigurationStorage.shared.loadEtag(for: .trackerRadar), - data: DefaultConfigurationStorage.shared.loadData(for: .trackerRadar), + trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), + data: ConfigurationStore.shared.loadData(for: .trackerDataSet), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: nil), @@ -83,8 +84,8 @@ class AutoconsentBackgroundTests: XCTestCase { privacyConfigurationManager: MockPrivacyConfigurationManager(), privacySettings: preferences, contentBlockingManager: ContentBlockerRulesManagerMock(), - trackerDataManager: TrackerDataManager(etag: DefaultConfigurationStorage.shared.loadEtag(for: .trackerRadar), - data: DefaultConfigurationStorage.shared.loadData(for: .trackerRadar), + trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), + data: ConfigurationStore.shared.loadData(for: .trackerDataSet), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: nil), @@ -132,20 +133,20 @@ class MockStorage: ConfigurationStoring { var errorOnStoreEtag = false var data: Data? - var dataConfig: ConfigurationLocation? + var dataConfig: Configuration? var etag: String? - var etagConfig: ConfigurationLocation? + var etagConfig: Configuration? - func loadData(for: ConfigurationLocation) -> Data? { + func loadData(for: Configuration) -> Data? { return data } - func loadEtag(for: ConfigurationLocation) -> String? { + func loadEtag(for: Configuration) -> String? { return etag } - func saveData(_ data: Data, for config: ConfigurationLocation) throws { + func saveData(_ data: Data, for config: Configuration) throws { if errorOnStoreData { throw Error.mockError } @@ -154,7 +155,7 @@ class MockStorage: ConfigurationStoring { self.dataConfig = config } - func saveEtag(_ etag: String, for config: ConfigurationLocation) throws { + func saveEtag(_ etag: String, for config: Configuration) throws { if errorOnStoreEtag { throw Error.mockError } @@ -165,4 +166,6 @@ class MockStorage: ConfigurationStoring { func log() { } + func loadEmbeddedEtag(for configuration: Configuration) -> String? { nil } + } diff --git a/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift b/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift index b3cca5cf0e..b19eef720b 100644 --- a/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift +++ b/Unit Tests/Autoconsent/AutoconsentMessageProtocolTests.swift @@ -25,15 +25,14 @@ import XCTest class AutoconsentMessageProtocolTests: XCTestCase { let userScript = AutoconsentUserScript( - scriptSource: ScriptSourceProvider(configStorage: ConfigurationDownloaderTests.MockStorage(), + scriptSource: ScriptSourceProvider(configStorage: MockConfigurationStore(), privacyConfigurationManager: MockPrivacyConfigurationManager(), privacySettings: PrivacySecurityPreferences.shared, // todo: mock contentBlockingManager: ContentBlockerRulesManagerMock(), - trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerRadar), - data: ConfigurationStore.shared.loadData(for: .trackerRadar), + trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), + data: ConfigurationStore.shared.loadData(for: .trackerDataSet), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: nil), - tld: TLD()), config: MockPrivacyConfiguration() ) diff --git a/Unit Tests/Configuration/ConfigurationDownloaderTests.swift b/Unit Tests/Configuration/ConfigurationDownloaderTests.swift deleted file mode 100644 index b42b2c13e5..0000000000 --- a/Unit Tests/Configuration/ConfigurationDownloaderTests.swift +++ /dev/null @@ -1,358 +0,0 @@ -// -// ConfigurationDownloaderTests.swift -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import XCTest -import Combine -@testable import DuckDuckGo_Privacy_Browser - -final class ConfigurationDownloaderTests: XCTestCase { - - static let resultData = "test".data(using: .utf8)! - - var cancellables = Set() - - func test_urls_do_not_contain_localhost() { - for url in ConfigurationLocation.allCases { - XCTAssertFalse(url.rawValue.contains("localhost")) - XCTAssertFalse(url.rawValue.contains("127.0.0.1")) - } - } - - func test_when_store_etag_fails_then_failure_returned_and_no_etag_stored() { - let response = HTTPURLResponse.success - let storageMock = MockStorage() - storageMock.errorOnStoreEtag = true - - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - - var completionResult: Subscribers.Completion? - downloader.download(.bloomFilterBinary, embeddedEtag: nil).sink { completion in - completionResult = completion - } receiveValue: { _ in - XCTFail("expected value") - }.store(in: &cancellables) - - XCTAssertNotNil(completionResult) - if case .failure = completionResult! { - // we good - } else { - XCTFail("completion was not expected failure") - } - - // Data may have been stored by this point, nothing we can do about that - XCTAssertNil(storageMock.etag) - XCTAssertNil(storageMock.etagConfig) - } - - func test_when_store_data_fails_then_failure_returned_and_no_data_or_etag_stored() { - let response = HTTPURLResponse.success - let storageMock = MockStorage() - storageMock.errorOnStoreData = true - - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - - var completionResult: Subscribers.Completion? - downloader.download(.bloomFilterBinary, embeddedEtag: nil).sink { completion in - completionResult = completion - } receiveValue: { _ in - XCTFail("expected value") - }.store(in: &cancellables) - - XCTAssertNotNil(completionResult) - if case .failure = completionResult! { - // we good - } else { - XCTFail("completion was not expected failure") - } - - XCTAssertNil(storageMock.data) - XCTAssertNil(storageMock.etag) - XCTAssertNil(storageMock.dataConfig) - XCTAssertNil(storageMock.etagConfig) - } - - func test_when_response_is_success_and_no_etag_then_error_returned() { - let response = HTTPURLResponse.successNoEtag - let storageMock = MockStorage() - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - - var completionResult: Subscribers.Completion? - downloader.download(.bloomFilterBinary, embeddedEtag: nil).sink { completion in - completionResult = completion - } receiveValue: { _ in - XCTFail("expected value") - }.store(in: &cancellables) - - XCTAssertNotNil(completionResult) - if case .failure = completionResult! { - // we good - } else { - XCTFail("completion was not expected failure") - } - - XCTAssertNil(storageMock.data) - XCTAssertNil(storageMock.etag) - XCTAssertNil(storageMock.dataConfig) - XCTAssertNil(storageMock.etagConfig) - } - - func test_when_response_is_error_then_error_returned() { - let response = HTTPURLResponse.internalServerError - let storageMock = MockStorage() - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - - var completionResult: Subscribers.Completion? - downloader.download(.bloomFilterBinary, embeddedEtag: nil).sink { completion in - completionResult = completion - } receiveValue: { _ in - XCTFail("expected value") - }.store(in: &cancellables) - - XCTAssertNotNil(completionResult) - if case .failure = completionResult! { - // we good - } else { - XCTFail("completion was not expected failure") - } - - XCTAssertNil(storageMock.data) - XCTAssertNil(storageMock.etag) - XCTAssertNil(storageMock.dataConfig) - XCTAssertNil(storageMock.etagConfig) - } - - func test_when_response_is_not_modified_and_valid_etag_then_nil_meta_returned_and_no_data_stored() { - let response = HTTPURLResponse.notModified - let storageMock = MockStorage() - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - var meta: ConfigurationDownloadMeta? - downloader.download(.bloomFilterBinary, embeddedEtag: nil).sink { completion in - if case .failure = completion { - XCTFail("unexpected failure") - } - } receiveValue: { value in - meta = value - }.store(in: &cancellables) - - XCTAssertNil(meta) - XCTAssertNil(storageMock.data) - XCTAssertNil(storageMock.etag) - XCTAssertNil(storageMock.dataConfig) - XCTAssertNil(storageMock.etagConfig) - } - - func test_when_etag_and_data_stored_then_etag_added_to_request() { - - let requestedEtag = UUID().uuidString - - let response = HTTPURLResponse.success - let storageMock = MockStorage() - storageMock.data = Data() - storageMock.etag = requestedEtag - - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - _ = downloader.download(.bloomFilterSpec, embeddedEtag: nil) - - XCTAssertEqual(requestedEtag, networkingMock.request?.value(forHTTPHeaderField: HTTPURLResponse.ifNoneMatchHeader)) - } - - func test_when_no_etag_stored_then_no_etag_added_to_request() { - - let response = HTTPURLResponse.success - let storageMock = MockStorage() - storageMock.data = Data() - - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - _ = downloader.download(.bloomFilterSpec, embeddedEtag: nil) - - XCTAssertNil(networkingMock.request?.value(forHTTPHeaderField: HTTPURLResponse.ifNoneMatchHeader)) - } - - func test_when_no_data_stored_then_no_etag_added_to_request() { - - let response = HTTPURLResponse.success - let storageMock = MockStorage() - storageMock.etag = "" - - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - _ = downloader.download(.bloomFilterSpec, embeddedEtag: nil) - - XCTAssertNil(networkingMock.request?.value(forHTTPHeaderField: HTTPURLResponse.ifNoneMatchHeader)) - } - - func test_when_embedded_etag_and_external_etag_provided_then_external_included_in_request() { - let embeddedEtag = UUID().uuidString - let externalEtag = UUID().uuidString - - let response = HTTPURLResponse.success - let storageMock = MockStorage() - storageMock.data = Data() - storageMock.etag = externalEtag - - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - _ = downloader.download(.bloomFilterSpec, embeddedEtag: embeddedEtag) - - XCTAssertEqual(externalEtag, networkingMock.request?.value(forHTTPHeaderField: HTTPURLResponse.ifNoneMatchHeader)) - } - - func test_when_embedded_etag_provided_then_is_included_in_request() { - let embeddedEtag = UUID().uuidString - - let response = HTTPURLResponse.success - let storageMock = MockStorage() - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - _ = downloader.download(.bloomFilterSpec, embeddedEtag: embeddedEtag) - - XCTAssertEqual(embeddedEtag, networkingMock.request?.value(forHTTPHeaderField: HTTPURLResponse.ifNoneMatchHeader)) - } - - func test_when_response_is_success_and_valid_etag_then_meta_returned_and_data_stored() { - - for config in ConfigurationLocation.allCases { - - let response = HTTPURLResponse.success - let storageMock = MockStorage() - let networkingMock = MockNetworking(result: (Self.resultData, response)) - let downloader = DefaultConfigurationDownloader(storage: storageMock, dataTaskProvider: networkingMock, deliveryQueue: DispatchQueue.main) - var meta: ConfigurationDownloadMeta? - downloader.download(config, embeddedEtag: nil).sink { completion in - if case .failure = completion { - XCTFail("unexpected failure for \(config.rawValue)") - } - } receiveValue: { value in - meta = value - }.store(in: &cancellables) - - XCTAssertEqual(meta?.etag, HTTPURLResponse.etagValue) - XCTAssertEqual(meta?.data, Self.resultData) - XCTAssertNotNil(storageMock.data) - XCTAssertNotNil(storageMock.etag) - XCTAssertEqual(storageMock.dataConfig, config) - XCTAssertNotNil(storageMock.etagConfig, HTTPURLResponse.etagValue) - - } - - } - - class MockNetworking: DataTaskProviding { - - let result: (Data, URLResponse) - var publisher: CurrentValueSubject<(data: Data, response: URLResponse), URLError>? - var request: URLRequest? - - init(result: (Data, URLResponse)) { - self.result = result - } - - func send(_ data: Data, _ response: URLResponse) { - publisher?.send((data: data, response: response)) - } - - func dataTaskPublisher(for request: URLRequest) -> AnyPublisher<(data: Data, response: URLResponse), URLError> { - self.request = request - let publisher = CurrentValueSubject<(data: Data, response: URLResponse), URLError>(result) - self.publisher = publisher - return publisher.eraseToAnyPublisher() - } - - } - - class MockStorage: ConfigurationStoring { - - enum Error: Swift.Error { - case mockError - } - - var errorOnStoreData = false - var errorOnStoreEtag = false - - var data: Data? - var dataConfig: ConfigurationLocation? - - var etag: String? - var etagConfig: ConfigurationLocation? - - func loadData(for: ConfigurationLocation) -> Data? { - return data - } - - func loadEtag(for: ConfigurationLocation) -> String? { - return etag - } - - func saveData(_ data: Data, for config: ConfigurationLocation) throws { - if errorOnStoreData { - throw Error.mockError - } - - self.data = data - self.dataConfig = config - } - - func saveEtag(_ etag: String, for config: ConfigurationLocation) throws { - if errorOnStoreEtag { - throw Error.mockError - } - - self.etag = etag - self.etagConfig = config - } - - func log() { } - - } - -} - -fileprivate extension HTTPURLResponse { - - static let etagHeader = "Etag" - static let ifNoneMatchHeader = "If-None-Match" - static let etagValue = "test-etag" - - static let success = HTTPURLResponse(url: URL.blankPage, - statusCode: 200, - httpVersion: nil, - headerFields: [HTTPURLResponse.etagHeader: HTTPURLResponse.etagValue])! - - static let notModified = HTTPURLResponse(url: URL.blankPage, - statusCode: 304, - httpVersion: nil, - headerFields: [HTTPURLResponse.etagHeader: HTTPURLResponse.etagValue])! - - static let internalServerError = HTTPURLResponse(url: URL.blankPage, - statusCode: 500, - httpVersion: nil, - headerFields: [:])! - - static let successNoEtag = HTTPURLResponse(url: URL.blankPage, - statusCode: 200, - httpVersion: nil, - headerFields: [:])! - -} diff --git a/Unit Tests/Configuration/ConfigurationStorageTests.swift b/Unit Tests/Configuration/ConfigurationStorageTests.swift index 23824ce407..81d4b7a890 100644 --- a/Unit Tests/Configuration/ConfigurationStorageTests.swift +++ b/Unit Tests/Configuration/ConfigurationStorageTests.swift @@ -18,22 +18,21 @@ import XCTest import Combine +import Configuration @testable import DuckDuckGo_Privacy_Browser final class ConfigurationStorageTests: XCTestCase { override func tearDown() { super.tearDown() - - for config in ConfigurationLocation.allCases { + for config in Configuration.allCases { let url = ConfigurationStore.shared.fileUrl(for: config) try? FileManager.default.removeItem(at: url) } - } func test_when_data_is_saved_for_config_then_it_can_be_loaded_correctly() { - for config in ConfigurationLocation.allCases { + for config in Configuration.allCases { let uuid = UUID().uuidString try? ConfigurationStore.shared.saveData(uuid.data(using: .utf8)!, for: config) XCTAssertEqual(uuid, ConfigurationStore.shared.loadData(for: config)?.utf8String()) @@ -41,7 +40,7 @@ final class ConfigurationStorageTests: XCTestCase { } func test_when_etag_is_saved_for_config_then_it_can_be_loaded_correctly() { - for config in ConfigurationLocation.allCases { + for config in Configuration.allCases { let etag = UUID().uuidString try? ConfigurationStore.shared.saveEtag(etag, for: config) XCTAssertEqual(etag, ConfigurationStore.shared.loadEtag(for: config)) diff --git a/Unit Tests/Content Blocker/AppPrivacyConfigurationTests.swift b/Unit Tests/Content Blocker/AppPrivacyConfigurationTests.swift index 673fcc19c1..e5ae91381e 100644 --- a/Unit Tests/Content Blocker/AppPrivacyConfigurationTests.swift +++ b/Unit Tests/Content Blocker/AppPrivacyConfigurationTests.swift @@ -44,13 +44,12 @@ class AppPrivacyConfigurationTests: XCTestCase { "Error: please update SHA and ETag when changing embedded config") } - func testWhenEmbeddedDataIsUsedThenItCanBeParsed() { + func testWhenEmbeddedDataIsUsedThenItCanBeParsed() throws { let provider = AppPrivacyConfigurationDataProvider() let jsonData = provider.embeddedData - let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] - let configData = PrivacyConfigurationData(json: json!) + let configData = try PrivacyConfigurationData(data: jsonData) let config = AppPrivacyConfiguration(data: configData, identifier: "", diff --git a/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift b/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift index 4182a661ac..caaed6b2b5 100644 --- a/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift +++ b/Unit Tests/Content Blocker/ContentBlockingUpdatingTests.swift @@ -23,8 +23,8 @@ import TrackerRadarKit import BrowserServicesKit @testable import DuckDuckGo_Privacy_Browser -class ContentBlockingUpdatingTests: XCTestCase { - // todo: mock +final class ContentBlockingUpdatingTests: XCTestCase { + let preferences = PrivacySecurityPreferences.shared let rulesManager = ContentBlockerRulesManagerMock() var updating: UserContentUpdating! @@ -32,11 +32,11 @@ class ContentBlockingUpdatingTests: XCTestCase { override func setUp() { updating = UserContentUpdating(contentBlockerRulesManager: rulesManager, privacyConfigurationManager: MockPrivacyConfigurationManager(), - trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerRadar), - data: ConfigurationStore.shared.loadData(for: .trackerRadar), + trackerDataManager: TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), + data: ConfigurationStore.shared.loadData(for: .trackerDataSet), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: nil), - configStorage: ConfigurationDownloaderTests.MockStorage(), + configStorage: MockConfigurationStore(), privacySecurityPreferences: preferences, tld: TLD()) } diff --git a/Unit Tests/Content Blocker/MockConfigurationStore.swift b/Unit Tests/Content Blocker/MockConfigurationStore.swift new file mode 100644 index 0000000000..f7d19af95d --- /dev/null +++ b/Unit Tests/Content Blocker/MockConfigurationStore.swift @@ -0,0 +1,63 @@ +// +// MockConfigurationStore.swift +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Configuration + +final class MockConfigurationStore: ConfigurationStoring { + + enum Error: Swift.Error { + case mockError + } + + var errorOnStoreData = false + var errorOnStoreEtag = false + + var data: Data? + var dataConfig: Configuration? + + var etag: String? + var etagConfig: Configuration? + + func loadData(for: Configuration) -> Data? { data } + + func loadEtag(for: Configuration) -> String? { etag } + + func loadEmbeddedEtag(for configuration: Configuration) -> String? { nil } + + func saveData(_ data: Data, for config: Configuration) throws { + if errorOnStoreData { + throw Error.mockError + } + + self.data = data + self.dataConfig = config + } + + func saveEtag(_ etag: String, for config: Configuration) throws { + if errorOnStoreEtag { + throw Error.mockError + } + + self.etag = etag + self.etagConfig = config + } + + func log() { } + +} diff --git a/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift b/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift index 7d0b08b92c..bf7dfce5a8 100644 --- a/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift +++ b/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift @@ -20,6 +20,7 @@ import XCTest import os.log import BrowserServicesKit +@testable import API @testable import DuckDuckGo_Privacy_Browser final class BrokenSiteReportingReferenceTests: XCTestCase { @@ -30,14 +31,11 @@ final class BrokenSiteReportingReferenceTests: XCTestCase { } private func makeURLRequest(with parameters: [String: String]) -> URLRequest { - APIRequest.urlRequestFor( - url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), - method: .get, - parameters: parameters, - allowedQueryReservedCharacters: WebsiteBreakageSender.allowedQueryReservedCharacters, - headers: [:], - timeoutInterval: 60 - ) + APIHeaders.setUserAgent("") + let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), + queryParameters: parameters, + allowedQueryReservedCharacters: WebsiteBreakageSender.allowedQueryReservedCharacters) + return configuration.request } func testBrokenSiteReporting() { diff --git a/Unit Tests/Privacy Reference Tests/PrivacyReferenceTestHelper.swift b/Unit Tests/Privacy Reference Tests/PrivacyReferenceTestHelper.swift index 4d0dec5e1d..e818932475 100644 --- a/Unit Tests/Privacy Reference Tests/PrivacyReferenceTestHelper.swift +++ b/Unit Tests/Privacy Reference Tests/PrivacyReferenceTestHelper.swift @@ -44,16 +44,11 @@ struct PrivacyReferenceTestHelper { } } - func privacyConfigurationData(withConfigPath path: String, bundle: Bundle) -> PrivacyConfigurationData { + func privacyConfigurationData(withConfigPath path: String, bundle: Bundle) throws -> PrivacyConfigurationData { guard let configData = try? data(for: path, in: bundle) else { fatalError("Can't decode \(path)") } - - guard let json = try? JSONSerialization.jsonObject(with: configData, options: []) as? [String: Any] else { - fatalError("Can't decode \(path)") - } - - return PrivacyConfigurationData(json: json) + return try PrivacyConfigurationData(data: configData) } func privacyConfiguration(withData data: PrivacyConfigurationData) -> PrivacyConfiguration { diff --git a/Unit Tests/Statistics/PixelTests.swift b/Unit Tests/Statistics/PixelTests.swift index 45c9a48b6f..e0417785d9 100644 --- a/Unit Tests/Statistics/PixelTests.swift +++ b/Unit Tests/Statistics/PixelTests.swift @@ -19,6 +19,7 @@ import XCTest import OHHTTPStubs import OHHTTPStubsSwift +import API @testable import DuckDuckGo_Privacy_Browser class PixelTests: XCTestCase { diff --git a/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift b/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift index 545c609aa9..5b5297b1bb 100644 --- a/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift +++ b/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift @@ -17,6 +17,7 @@ // import XCTest +@testable import API @testable import DuckDuckGo_Privacy_Browser class WebsiteBreakageReportTests: XCTestCase { @@ -100,14 +101,11 @@ class WebsiteBreakageReportTests: XCTestCase { } func makeURLRequest(with parameters: [String: String]) -> URLRequest { - APIRequest.urlRequestFor( - url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), - method: .get, - parameters: parameters, - allowedQueryReservedCharacters: WebsiteBreakageSender.allowedQueryReservedCharacters, - headers: [:], - timeoutInterval: 60 - ) + APIHeaders.setUserAgent("") + let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), + queryParameters: parameters, + allowedQueryReservedCharacters: WebsiteBreakageSender.allowedQueryReservedCharacters) + return configuration.request } } From 8c29a4d6bf13c5c42243983c22077ea255bcc4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Thu, 23 Feb 2023 15:21:33 +0100 Subject: [PATCH 08/16] Point BSK to unify-configuration branch --- DuckDuckGo.xcodeproj/project.pbxproj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 705c1a9893..e2289f14b1 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -2633,7 +2633,6 @@ B6FA893E269C424500588ECD /* PrivacyDashboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardViewController.swift; sourceTree = ""; }; B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardPopover.swift; sourceTree = ""; }; CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfigurationURLProvider.swift; sourceTree = ""; }; - CB5E2CF629A1A5680062D13E /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyFeatures.swift; sourceTree = ""; }; CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockConfigurationStore.swift; sourceTree = ""; }; EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClickToLoadUserScript.swift; sourceTree = ""; }; @@ -4110,7 +4109,6 @@ AA585D75248FD31100E9A3E2 = { isa = PBXGroup; children = ( - CB5E2CF629A1A5680062D13E /* BrowserServicesKit */, 378E279C2970217400FCADA2 /* Plugins */, 378B5886295CF2A4002C0CC0 /* Configuration */, AA68C3D62490F821001B8783 /* README.md */, @@ -8112,8 +8110,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { - kind = exactVersion; - version = 46.2.0; + branch = "jacek/unify-configuration"; + kind = branch; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { From 78ca58b3db8aae69005df9528a026681c3516c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Thu, 23 Feb 2023 15:26:25 +0100 Subject: [PATCH 09/16] Fix crash on startup --- DuckDuckGo/App Delegate/AppDelegate.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/App Delegate/AppDelegate.swift b/DuckDuckGo/App Delegate/AppDelegate.swift index faf7c37473..31ac24f208 100644 --- a/DuckDuckGo/App Delegate/AppDelegate.swift +++ b/DuckDuckGo/App Delegate/AppDelegate.swift @@ -63,6 +63,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate { var appUsageActivityMonitor: AppUsageActivityMonitor? func applicationWillFinishLaunching(_ notification: Notification) { + APIHeaders.setUserAgent(UserAgent.duckDuckGoUserAgent()) + Configuration.setURLProvider(AppConfigurationURLProvider()) + if !Self.isRunningTests { #if DEBUG Pixel.setUp(dryRun: true) @@ -122,9 +125,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { guard !Self.isRunningTests else { return } - APIHeaders.setUserAgent(UserAgent.duckDuckGoUserAgent()) - Configuration.setURLProvider(AppConfigurationURLProvider()) - HistoryCoordinator.shared.loadHistory() PrivacyFeatures.httpsUpgrade.loadDataAsync() LocalBookmarkManager.shared.loadBookmarks() From ad1eb5d11602a90b82f3dcd8cd6793ce995f28aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 6 Mar 2023 15:10:44 +0100 Subject: [PATCH 10/16] Update macos client to new BSK changes --- DuckDuckGo.xcodeproj/project.pbxproj | 14 --- .../AppConfigurationURLProvider.swift | 2 +- DuckDuckGo/App Delegate/AppDelegate.swift | 4 +- .../Configuration/ConfigurationManager.swift | 96 +++++++++---------- .../Content Blocker/ContentBlocking.swift | 2 +- .../Model/FeedbackSender.swift | 2 +- DuckDuckGo/Menus/MainMenuActions.swift | 3 +- .../Statistics/ATB/StatisticsLoader.swift | 2 +- DuckDuckGo/Statistics/Pixel.swift | 8 +- .../BrokenSiteReportingReferenceTests.swift | 4 +- Unit Tests/Statistics/PixelTests.swift | 2 +- .../WebsiteBreakageReportTests.swift | 4 +- 12 files changed, 63 insertions(+), 80 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index e2289f14b1..bab3fbc34c 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1693,8 +1693,6 @@ CB24F70C29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; CB24F70D29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; CB6BCDF927C6BEFF00CC76DC /* PrivacyFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */; }; - CB7E2B8B29A24CBF00997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8A29A24CBF00997A73 /* Configuration */; }; - CB7E2B8D29A24D3800997A73 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CB7E2B8C29A24D3800997A73 /* Configuration */; }; CBDD5DE329A67F2700832877 /* MockConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */; }; CBDD5DE429A6800300832877 /* MockConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */; }; EA0BA3A9272217E6002A0B6C /* ClickToLoadUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */; }; @@ -2671,7 +2669,6 @@ 3706FCAE293F65D500E42796 /* Lottie in Frameworks */, 3706FCAF293F65D500E42796 /* PrivacyDashboard in Frameworks */, 3706FCB0293F65D500E42796 /* Common in Frameworks */, - CB7E2B8D29A24D3800997A73 /* Configuration in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2716,7 +2713,6 @@ 1E950E432912A10D0051A99B /* UserScript in Frameworks */, 4B82E9B325B69E3E00656FE7 /* TrackerRadarKit in Frameworks */, 1D02633328D898E1005CBB41 /* OpenSSL in Frameworks */, - CB7E2B8B29A24CBF00997A73 /* Configuration in Frameworks */, AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */, 85FF55C825F82E4F00E2AB99 /* Lottie in Frameworks */, 1E950E412912A10D0051A99B /* PrivacyDashboard in Frameworks */, @@ -5515,7 +5511,6 @@ 3706FA77293F65D500E42796 /* PrivacyDashboard */, 3706FA78293F65D500E42796 /* UserScript */, 37A5E2EF298AA1B20047046B /* Persistence */, - CB7E2B8C29A24D3800997A73 /* Configuration */, ); productName = DuckDuckGo; productReference = 3706FD05293F65D500E42796 /* DuckDuckGo App Store.app */; @@ -5629,7 +5624,6 @@ 1E950E402912A10D0051A99B /* PrivacyDashboard */, 1E950E422912A10D0051A99B /* UserScript */, 98A50963294B691800D10880 /* Persistence */, - CB7E2B8A29A24CBF00997A73 /* Configuration */, ); productName = DuckDuckGo; productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */; @@ -8261,14 +8255,6 @@ package = B6DA44152616C13800DD1EC2 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; productName = OHHTTPStubsSwift; }; - CB7E2B8A29A24CBF00997A73 /* Configuration */ = { - isa = XCSwiftPackageProductDependency; - productName = Configuration; - }; - CB7E2B8C29A24D3800997A73 /* Configuration */ = { - isa = XCSwiftPackageProductDependency; - productName = Configuration; - }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ diff --git a/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift index 93846eda7d..e26716fd45 100644 --- a/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift +++ b/DuckDuckGo/App Delegate/AppConfigurationURLProvider.swift @@ -19,7 +19,7 @@ import Foundation import Configuration -struct AppConfigurationURLProvider: ConfigurationURLProvider { +struct AppConfigurationURLProvider: ConfigurationURLProviding { func url(for configuration: Configuration) -> URL { switch configuration { diff --git a/DuckDuckGo/App Delegate/AppDelegate.swift b/DuckDuckGo/App Delegate/AppDelegate.swift index 31ac24f208..40487b9728 100644 --- a/DuckDuckGo/App Delegate/AppDelegate.swift +++ b/DuckDuckGo/App Delegate/AppDelegate.swift @@ -22,7 +22,7 @@ import os.log import BrowserServicesKit import Persistence import Configuration -import API +import Networking @NSApplicationMain final class AppDelegate: NSObject, NSApplicationDelegate { @@ -63,7 +63,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { var appUsageActivityMonitor: AppUsageActivityMonitor? func applicationWillFinishLaunching(_ notification: Notification) { - APIHeaders.setUserAgent(UserAgent.duckDuckGoUserAgent()) + APIRequest.Headers.setUserAgent(UserAgent.duckDuckGoUserAgent()) Configuration.setURLProvider(AppConfigurationURLProvider()) if !Self.isRunningTests { diff --git a/DuckDuckGo/Configuration/ConfigurationManager.swift b/DuckDuckGo/Configuration/ConfigurationManager.swift index 1808ef4921..40a2d623da 100644 --- a/DuckDuckGo/Configuration/ConfigurationManager.swift +++ b/DuckDuckGo/Configuration/ConfigurationManager.swift @@ -22,6 +22,7 @@ import os import BrowserServicesKit import Configuration +@MainActor final class ConfigurationManager { enum Error: Swift.Error { @@ -49,14 +50,12 @@ final class ConfigurationManager { } static let shared = ConfigurationManager() - static let queue: DispatchQueue = DispatchQueue(label: "Configuration Manager") @UserDefaultsWrapper(key: .configLastUpdated, defaultValue: .distantPast) - var lastUpdateTime: Date + private var lastUpdateTime: Date private var timerCancellable: AnyCancellable? - private var refreshCancellable: AnyCancellable? private var lastRefreshCheckTime: Date = Date() func start() { @@ -80,37 +79,45 @@ final class ConfigurationManager { private func refreshNow() async { - let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared) - do { - try await fetcher.fetch([.trackerDataSet, .surrogates, .privacyConfiguration]) { - self.updateTrackerBlockingDependencies() - self.tryAgainLater() + let updateTrackerBlockingDependenciesTask = Task { + do { + let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) + try await fetcher.fetch(any: [.trackerDataSet, .surrogates, .privacyConfiguration]) + updateTrackerBlockingDependencies() + tryAgainLater() + } catch { + handleRefreshError(error) } - } catch { - handleRefreshError(error) } - do { - try await fetcher.fetch([.bloomFilterBinary, .bloomFilterSpec]) { - try self.updateBloomFilter() - self.tryAgainLater() + let updateBloomFilterTask = Task { + do { + let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) + try await fetcher.fetch(all: [.bloomFilterBinary, .bloomFilterSpec]) + try updateBloomFilter() + tryAgainLater() + } catch { + handleRefreshError(error) } - } catch { - handleRefreshError(error) } - do { - try await fetcher.fetch([.bloomFilterExcludedDomains]) { - try self.updateBloomFilterExclusions() - self.tryAgainLater() + let updateBloomFilterExclusionsTask = Task { + do { + let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) + try await fetcher.fetch(any: [.bloomFilterExcludedDomains]) + try updateBloomFilterExclusions() + tryAgainLater() + } catch { + handleRefreshError(error) } - } catch { - handleRefreshError(error) } + await updateTrackerBlockingDependenciesTask.value + await updateBloomFilterTask.value + await updateBloomFilterExclusionsTask.value + ConfigurationStore.shared.log() log() - } private func handleRefreshError(_ error: Swift.Error) { @@ -120,7 +127,7 @@ final class ConfigurationManager { } public func refreshIfNeeded() { - guard isReadyToRefresh, refreshCancellable == nil else { + guard isReadyToRefresh else { os_log("Configuration refresh is not needed at this time", log: .config, type: .debug) return } @@ -131,6 +138,12 @@ final class ConfigurationManager { private var isReadyToRefresh: Bool { Date().timeIntervalSince(lastUpdateTime) > Constants.refreshPeriodSeconds } + public func forceRefresh() { + Task { + await refreshNow() + } + } + private func tryAgainLater() { lastUpdateTime = Date() } @@ -141,50 +154,35 @@ final class ConfigurationManager { } private func updateTrackerBlockingDependencies() { - let tdsEtag = ConfigurationStore.shared.loadEtag(for: .trackerDataSet) - let tdsData = ConfigurationStore.shared.loadData(for: .trackerDataSet) - ContentBlocking.shared.trackerDataManager.reload(etag: tdsEtag, data: tdsData) - - let configEtag = ConfigurationStore.shared.loadEtag(for: .privacyConfiguration) - let configData = ConfigurationStore.shared.loadData(for: .privacyConfiguration) - _ = ContentBlocking.shared.privacyConfigurationManager.reload(etag: configEtag, data: configData) - - _ = ContentBlocking.shared.contentBlockingManager.scheduleCompilation() + ContentBlocking.shared.trackerDataManager.reload(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), + data: ConfigurationStore.shared.loadData(for: .trackerDataSet)) + ContentBlocking.shared.privacyConfigurationManager.reload(etag: ConfigurationStore.shared.loadEtag(for: .privacyConfiguration), + data: ConfigurationStore.shared.loadData(for: .privacyConfiguration)) + ContentBlocking.shared.contentBlockingManager.scheduleCompilation() } private func updateBloomFilter() throws { - let configStore = ConfigurationStore.shared - guard let specData = configStore.loadData(for: .bloomFilterSpec) else { + guard let specData = ConfigurationStore.shared.loadData(for: .bloomFilterSpec) else { throw Error.bloomFilterSpecNotFound } - - guard let bloomFilterData = configStore.loadData(for: .bloomFilterBinary) else { + guard let bloomFilterData = ConfigurationStore.shared.loadData(for: .bloomFilterBinary) else { throw Error.bloomFilterBinaryNotFound } - let spec = try JSONDecoder().decode(HTTPSBloomFilterSpecification.self, from: specData) - - let httpsStore = AppHTTPSUpgradeStore() - guard httpsStore.persistBloomFilter(specification: spec, data: bloomFilterData) else { + guard AppHTTPSUpgradeStore().persistBloomFilter(specification: spec, data: bloomFilterData) else { throw Error.bloomFilterPersistenceFailed } - PrivacyFeatures.httpsUpgrade.loadData() } private func updateBloomFilterExclusions() throws { - let configStore = ConfigurationStore.shared - guard let bloomFilterExclusions = configStore.loadData(for: .bloomFilterExcludedDomains) else { + guard let bloomFilterExclusions = ConfigurationStore.shared.loadData(for: .bloomFilterExcludedDomains) else { throw Error.bloomFilterExclusionsNotFound } - let excludedDomains = try JSONDecoder().decode(HTTPSExcludedDomains.self, from: bloomFilterExclusions).data - - let httpsStore = AppHTTPSUpgradeStore() - guard httpsStore.persistExcludedDomains(excludedDomains) else { + guard AppHTTPSUpgradeStore().persistExcludedDomains(excludedDomains) else { throw Error.bloomFilterExclusionsPersistenceFailed } - PrivacyFeatures.httpsUpgrade.loadData() } diff --git a/DuckDuckGo/Content Blocker/ContentBlocking.swift b/DuckDuckGo/Content Blocker/ContentBlocking.swift index 5848a54e85..f6bad32502 100644 --- a/DuckDuckGo/Content Blocker/ContentBlocking.swift +++ b/DuckDuckGo/Content Blocker/ContentBlocking.swift @@ -195,7 +195,7 @@ final class AppContentBlocking { protocol ContentBlockerRulesManagerProtocol: CompiledRuleListsSource { var updatesPublisher: AnyPublisher { get } var currentRules: [ContentBlockerRulesManager.Rules] { get } - func scheduleCompilation() -> ContentBlockerRulesManager.CompletionToken + @discardableResult func scheduleCompilation() -> ContentBlockerRulesManager.CompletionToken } extension ContentBlockerRulesManager: ContentBlockerRulesManagerProtocol {} diff --git a/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift b/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift index 6ccce7c8a8..e0672e0cb1 100644 --- a/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift +++ b/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift @@ -18,7 +18,7 @@ import Foundation import os.log -import API +import Networking final class FeedbackSender { diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift index 5a1c8d3468..b965344bc5 100644 --- a/DuckDuckGo/Menus/MainMenuActions.swift +++ b/DuckDuckGo/Menus/MainMenuActions.swift @@ -653,8 +653,7 @@ extension MainViewController { } @IBAction func fetchConfigurationNow(_ sender: Any?) { - ConfigurationManager.shared.lastUpdateTime = .distantPast - ConfigurationManager.shared.refreshIfNeeded() + ConfigurationManager.shared.forceRefresh() } // MARK: - Developer Tools diff --git a/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift b/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift index 707df78da2..ff5d1ee3e8 100644 --- a/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift +++ b/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift @@ -19,7 +19,7 @@ import Foundation import BrowserServicesKit import os.log -import API +import Networking final class StatisticsLoader { diff --git a/DuckDuckGo/Statistics/Pixel.swift b/DuckDuckGo/Statistics/Pixel.swift index 9963ec2aa5..e9f27fc186 100644 --- a/DuckDuckGo/Statistics/Pixel.swift +++ b/DuckDuckGo/Statistics/Pixel.swift @@ -18,7 +18,7 @@ import Foundation import os.log -import API +import Networking import Common final class Pixel { @@ -43,7 +43,7 @@ final class Pixel { withAdditionalParameters params: [String: String]? = nil, allowedQueryReservedCharacters: CharacterSet? = nil, includeAppVersionParameter: Bool = true, - withHeaders headers: HTTPHeaders = APIHeaders().defaultHeaders, + withHeaders headers: HTTPHeaders = APIRequest.Headers().default, onComplete: @escaping (Error?) -> Void = {_ in }) { var newParams = params ?? [:] @@ -55,7 +55,7 @@ final class Pixel { #endif var headers = headers - headers[HTTPHeaderField.moreInfo] = "See " + URL.duckDuckGoMorePrivacyInfo.absoluteString + headers[APIRequest.HTTPHeaderField.moreInfo] = "See " + URL.duckDuckGoMorePrivacyInfo.absoluteString guard !dryRun else { let params = params?.filter { key, _ in !["appVersion", "test"].contains(key) } ?? [:] @@ -67,7 +67,7 @@ final class Pixel { } return } - + let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: pixelName), queryParameters: newParams, allowedQueryReservedCharacters: allowedQueryReservedCharacters, diff --git a/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift b/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift index bf7dfce5a8..3691923f4a 100644 --- a/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift +++ b/Unit Tests/Privacy Reference Tests/BrokenSiteReportingReferenceTests.swift @@ -20,7 +20,7 @@ import XCTest import os.log import BrowserServicesKit -@testable import API +@testable import Networking @testable import DuckDuckGo_Privacy_Browser final class BrokenSiteReportingReferenceTests: XCTestCase { @@ -31,7 +31,7 @@ final class BrokenSiteReportingReferenceTests: XCTestCase { } private func makeURLRequest(with parameters: [String: String]) -> URLRequest { - APIHeaders.setUserAgent("") + APIRequest.Headers.setUserAgent("") let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), queryParameters: parameters, allowedQueryReservedCharacters: WebsiteBreakageSender.allowedQueryReservedCharacters) diff --git a/Unit Tests/Statistics/PixelTests.swift b/Unit Tests/Statistics/PixelTests.swift index e0417785d9..35ab7f0194 100644 --- a/Unit Tests/Statistics/PixelTests.swift +++ b/Unit Tests/Statistics/PixelTests.swift @@ -19,7 +19,7 @@ import XCTest import OHHTTPStubs import OHHTTPStubsSwift -import API +import Networking @testable import DuckDuckGo_Privacy_Browser class PixelTests: XCTestCase { diff --git a/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift b/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift index 5b5297b1bb..9069b93806 100644 --- a/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift +++ b/Unit Tests/Website Breakage Report/WebsiteBreakageReportTests.swift @@ -17,7 +17,7 @@ // import XCTest -@testable import API +@testable import Networking @testable import DuckDuckGo_Privacy_Browser class WebsiteBreakageReportTests: XCTestCase { @@ -101,7 +101,7 @@ class WebsiteBreakageReportTests: XCTestCase { } func makeURLRequest(with parameters: [String: String]) -> URLRequest { - APIHeaders.setUserAgent("") + APIRequest.Headers.setUserAgent("") let configuration = APIRequest.Configuration(url: URL.pixelUrl(forPixelNamed: Pixel.Event.brokenSiteReport.name), queryParameters: parameters, allowedQueryReservedCharacters: WebsiteBreakageSender.allowedQueryReservedCharacters) From 8649763502313a1797c0b31006a7e3b2ecee50ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 6 Mar 2023 15:32:26 +0100 Subject: [PATCH 11/16] Revert to old name not to migrate data --- DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift index 948f6527d6..1ec4229a1d 100644 --- a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift +++ b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift @@ -24,7 +24,7 @@ public struct UserDefaultsWrapper { public enum Key: String, CaseIterable { case configLastUpdated = "config.last.updated" - case configStorageTrackerRadarEtag = "config.storage.trackerDataSet.etag" + case configStorageTrackerRadarEtag = "config.storage.trackerradar.etag" case configStorageBloomFilterSpecEtag = "config.storage.bloomfilter.spec.etag" case configStorageBloomFilterBinaryEtag = "config.storage.bloomfilter.binary.etag" case configStorageBloomFilterExclusionsEtag = "config.storage.bloomfilter.exclusions.etag" From 77c255feafcfac4eaf1298508d6684e45ca9a4bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Mon, 6 Mar 2023 16:25:47 +0100 Subject: [PATCH 12/16] Make app compilable --- DuckDuckGo.xcodeproj/project.pbxproj | 16 ++++++++++++++++ .../Configuration/ConfigurationManager.swift | 4 +--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index bab3fbc34c..e343e317c3 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1693,6 +1693,8 @@ CB24F70C29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; CB24F70D29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; CB6BCDF927C6BEFF00CC76DC /* PrivacyFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */; }; + CBC83E3629B63D380008E19C /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CBC83E3529B63D380008E19C /* Configuration */; }; + CBC83E3829B63D400008E19C /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CBC83E3729B63D400008E19C /* Configuration */; }; CBDD5DE329A67F2700832877 /* MockConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */; }; CBDD5DE429A6800300832877 /* MockConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */; }; EA0BA3A9272217E6002A0B6C /* ClickToLoadUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */; }; @@ -2669,6 +2671,7 @@ 3706FCAE293F65D500E42796 /* Lottie in Frameworks */, 3706FCAF293F65D500E42796 /* PrivacyDashboard in Frameworks */, 3706FCB0293F65D500E42796 /* Common in Frameworks */, + CBC83E3829B63D400008E19C /* Configuration in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2713,6 +2716,7 @@ 1E950E432912A10D0051A99B /* UserScript in Frameworks */, 4B82E9B325B69E3E00656FE7 /* TrackerRadarKit in Frameworks */, 1D02633328D898E1005CBB41 /* OpenSSL in Frameworks */, + CBC83E3629B63D380008E19C /* Configuration in Frameworks */, AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */, 85FF55C825F82E4F00E2AB99 /* Lottie in Frameworks */, 1E950E412912A10D0051A99B /* PrivacyDashboard in Frameworks */, @@ -5511,6 +5515,7 @@ 3706FA77293F65D500E42796 /* PrivacyDashboard */, 3706FA78293F65D500E42796 /* UserScript */, 37A5E2EF298AA1B20047046B /* Persistence */, + CBC83E3729B63D400008E19C /* Configuration */, ); productName = DuckDuckGo; productReference = 3706FD05293F65D500E42796 /* DuckDuckGo App Store.app */; @@ -5624,6 +5629,7 @@ 1E950E402912A10D0051A99B /* PrivacyDashboard */, 1E950E422912A10D0051A99B /* UserScript */, 98A50963294B691800D10880 /* Persistence */, + CBC83E3529B63D380008E19C /* Configuration */, ); productName = DuckDuckGo; productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */; @@ -8255,6 +8261,16 @@ package = B6DA44152616C13800DD1EC2 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; productName = OHHTTPStubsSwift; }; + CBC83E3529B63D380008E19C /* Configuration */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Configuration; + }; + CBC83E3729B63D400008E19C /* Configuration */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Configuration; + }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ diff --git a/DuckDuckGo/Configuration/ConfigurationManager.swift b/DuckDuckGo/Configuration/ConfigurationManager.swift index 40a2d623da..b6a7e0f5b4 100644 --- a/DuckDuckGo/Configuration/ConfigurationManager.swift +++ b/DuckDuckGo/Configuration/ConfigurationManager.swift @@ -78,10 +78,10 @@ final class ConfigurationManager { } private func refreshNow() async { + let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) let updateTrackerBlockingDependenciesTask = Task { do { - let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) try await fetcher.fetch(any: [.trackerDataSet, .surrogates, .privacyConfiguration]) updateTrackerBlockingDependencies() tryAgainLater() @@ -92,7 +92,6 @@ final class ConfigurationManager { let updateBloomFilterTask = Task { do { - let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) try await fetcher.fetch(all: [.bloomFilterBinary, .bloomFilterSpec]) try updateBloomFilter() tryAgainLater() @@ -103,7 +102,6 @@ final class ConfigurationManager { let updateBloomFilterExclusionsTask = Task { do { - let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) try await fetcher.fetch(any: [.bloomFilterExcludedDomains]) try updateBloomFilterExclusions() tryAgainLater() From b0841fee31c5fe718f8e766d090657ee76eefe1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Tue, 7 Mar 2023 17:15:15 +0100 Subject: [PATCH 13/16] Address comments and update to new BSK --- .../Configuration/ConfigurationManager.swift | 34 ++++++++++++++++--- .../Model/FeedbackSender.swift | 2 +- .../Statistics/ATB/StatisticsLoader.swift | 8 ++--- DuckDuckGo/Statistics/Pixel.swift | 2 +- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/DuckDuckGo/Configuration/ConfigurationManager.swift b/DuckDuckGo/Configuration/ConfigurationManager.swift index b6a7e0f5b4..1b4053e24f 100644 --- a/DuckDuckGo/Configuration/ConfigurationManager.swift +++ b/DuckDuckGo/Configuration/ConfigurationManager.swift @@ -81,12 +81,10 @@ final class ConfigurationManager { let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) let updateTrackerBlockingDependenciesTask = Task { - do { - try await fetcher.fetch(any: [.trackerDataSet, .surrogates, .privacyConfiguration]) + let didFetchAnyTrackerBlockingDependencies = await fetchTrackerBlockingDependencies() + if didFetchAnyTrackerBlockingDependencies { updateTrackerBlockingDependencies() tryAgainLater() - } catch { - handleRefreshError(error) } } @@ -102,7 +100,7 @@ final class ConfigurationManager { let updateBloomFilterExclusionsTask = Task { do { - try await fetcher.fetch(any: [.bloomFilterExcludedDomains]) + try await fetcher.fetch(.bloomFilterExcludedDomains) try updateBloomFilterExclusions() tryAgainLater() } catch { @@ -118,6 +116,32 @@ final class ConfigurationManager { log() } + private func fetchTrackerBlockingDependencies() async -> Bool { + var didFetchAnyTrackerBlockingDependencies = false + let fetcher = ConfigurationFetcher(store: ConfigurationStore.shared, log: .config) + + var tasks = [Configuration: Task<(), Swift.Error>]() + tasks[.trackerDataSet] = Task { try await fetcher.fetch(.trackerDataSet) } + tasks[.surrogates] = Task { try await fetcher.fetch(.surrogates) } + tasks[.privacyConfiguration] = Task { try await fetcher.fetch(.privacyConfiguration) } + + for (configuration, task) in tasks { + do { + try await task.value + didFetchAnyTrackerBlockingDependencies = true + } catch { + os_log("Failed to complete configuration update to %@: %@", + log: .config, + type: .error, + configuration.rawValue, + error.localizedDescription) + tryAgainSoon() + } + } + + return didFetchAnyTrackerBlockingDependencies + } + private func handleRefreshError(_ error: Swift.Error) { os_log("Failed to complete configuration update %@", log: .config, type: .error, error.localizedDescription) Pixel.fire(.debug(event: .configurationFetchError, error: error)) diff --git a/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift b/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift index e0672e0cb1..51d3df15b4 100644 --- a/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift +++ b/DuckDuckGo/Feedback and Breakage/Model/FeedbackSender.swift @@ -39,7 +39,7 @@ final class FeedbackSender { ] let configuration = APIRequest.Configuration(url: Self.feedbackURL, method: .post, queryParameters: parameters) - let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession()) + let request = APIRequest(configuration: configuration, urlSession: URLSession.session()) request.fetch { _, error in if let error = error { os_log("FeedbackSender: Failed to submit feedback %s", type: .error, error.localizedDescription) diff --git a/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift b/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift index ff5d1ee3e8..5f5a0493cb 100644 --- a/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift +++ b/DuckDuckGo/Statistics/ATB/StatisticsLoader.swift @@ -80,7 +80,7 @@ final class StatisticsLoader { os_log("Requesting install statistics", log: .atb, type: .debug) let configuration = APIRequest.Configuration(url: URL.initialAtb) - let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + let request = APIRequest(configuration: configuration, urlSession: URLSession.session(useMainThreadCallbackQueue: true)) request.fetch { response, error in self.isAppRetentionRequestInProgress = false if let error = error { @@ -110,7 +110,7 @@ final class StatisticsLoader { let installAtb = atb.version + (statisticsStore.variant ?? "") let configuration = APIRequest.Configuration(url: URL.exti(forAtb: installAtb)) - let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + let request = APIRequest(configuration: configuration, urlSession: URLSession.session(useMainThreadCallbackQueue: true)) request.fetch { _, error in self.isAppRetentionRequestInProgress = false if let error = error { @@ -144,7 +144,7 @@ final class StatisticsLoader { let url = URL.searchAtb(atbWithVariant: atbWithVariant, setAtb: searchRetentionAtb, isSignedIntoEmailProtection: emailManager.isSignedIn) let configuration = APIRequest.Configuration(url: url) - let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + let request = APIRequest(configuration: configuration, urlSession: URLSession.session(useMainThreadCallbackQueue: true)) request.fetch { (response, error) in if let error = error { os_log("Search atb request failed with error %s", type: .error, error.localizedDescription) @@ -180,7 +180,7 @@ final class StatisticsLoader { let url = URL.appRetentionAtb(atbWithVariant: atbWithVariant, setAtb: appRetentionAtb) let configuration = APIRequest.Configuration(url: url) - let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + let request = APIRequest(configuration: configuration, urlSession: URLSession.session(useMainThreadCallbackQueue: true)) request.fetch { response, error in self.isAppRetentionRequestInProgress = false diff --git a/DuckDuckGo/Statistics/Pixel.swift b/DuckDuckGo/Statistics/Pixel.swift index e9f27fc186..fe0fad6dc4 100644 --- a/DuckDuckGo/Statistics/Pixel.swift +++ b/DuckDuckGo/Statistics/Pixel.swift @@ -72,7 +72,7 @@ final class Pixel { queryParameters: newParams, allowedQueryReservedCharacters: allowedQueryReservedCharacters, headers: headers) - let request = APIRequest(configuration: configuration, urlSession: URLSession.makeSession(useMainThreadCallbackQueue: true)) + let request = APIRequest(configuration: configuration, urlSession: URLSession.session(useMainThreadCallbackQueue: true)) request.fetch { (_, error) in onComplete(error) } From ed207df58b1b68a45947c4ee773a60b724482201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Tue, 7 Mar 2023 18:16:41 +0100 Subject: [PATCH 14/16] Fix tests --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- Unit Tests/Content Blocker/ContentBlockingMock.swift | 4 ++-- Unit Tests/Statistics/PixelTests.swift | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 930eb5d9bf..cfc6fdd0ff 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "d2d7850a5a1402036650e5900635700574cc39d1", - "version" : "47.0.0" + "branch" : "jacek/unify-configuration", + "revision" : "351d4d9c31a2892e4ffb05d79c7374052db2eb96" } }, { diff --git a/Unit Tests/Content Blocker/ContentBlockingMock.swift b/Unit Tests/Content Blocker/ContentBlockingMock.swift index bea30d639d..a140fab228 100644 --- a/Unit Tests/Content Blocker/ContentBlockingMock.swift +++ b/Unit Tests/Content Blocker/ContentBlockingMock.swift @@ -29,8 +29,8 @@ final class ContentBlockingMock: NSObject, ContentBlockingProtocol, AdClickAttri var embeddedDataEtag: String = "" var embeddedData: Data = .init() } - var trackerDataManager = TrackerDataManager(etag: DefaultConfigurationStorage.shared.loadEtag(for: .trackerRadar), - data: DefaultConfigurationStorage.shared.loadData(for: .trackerRadar), + var trackerDataManager = TrackerDataManager(etag: ConfigurationStore.shared.loadEtag(for: .trackerDataSet), + data: ConfigurationStore.shared.loadData(for: .trackerDataSet), embeddedDataProvider: AppTrackerDataSetProvider(), errorReporting: nil) diff --git a/Unit Tests/Statistics/PixelTests.swift b/Unit Tests/Statistics/PixelTests.swift index 35ab7f0194..b5768d360a 100644 --- a/Unit Tests/Statistics/PixelTests.swift +++ b/Unit Tests/Statistics/PixelTests.swift @@ -74,7 +74,7 @@ class PixelTests: XCTestCase { return HTTPStubsResponse(data: Data(), statusCode: 200, headers: nil) } - var headers = APIHeaders().defaultHeaders + var headers = APIRequest.Headers().default headers[userAgentName] = testAgent Pixel.shared!.fire(pixelNamed: "test", withHeaders: headers) From db7a6530d215d40714cc0118f6599c6dafc7b28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Wed, 8 Mar 2023 13:11:40 +0100 Subject: [PATCH 15/16] Update BSK --- DuckDuckGo.xcodeproj/project.pbxproj | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 5a807ed8ec..5d96c3a303 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -8212,8 +8212,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { - branch = "jacek/unify-configuration"; - kind = branch; + kind = exactVersion; + version = 48.0.0; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index cfc6fdd0ff..7b77add0fa 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "branch" : "jacek/unify-configuration", - "revision" : "351d4d9c31a2892e4ffb05d79c7374052db2eb96" + "revision" : "c10bf5256ba0b286fc62bd557e9d9100e7ea8c8f", + "version" : "48.0.0" } }, { From 4724176ff09391236c7f2215fcc66bef2822ab36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Wed, 8 Mar 2023 13:16:22 +0100 Subject: [PATCH 16/16] Add Package.resolved --- .../xcshareddata/swiftpm/Package.resolved | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7b77add0fa..cbe9b39509 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "c10bf5256ba0b286fc62bd557e9d9100e7ea8c8f", - "version" : "48.0.0" + "revision" : "86a7a3a68f53a37aa292ff3193b2dd587f943527", + "version" : "47.2.0" } }, { @@ -99,6 +99,15 @@ "version" : "0.5.0" } }, + { + "identity" : "swifter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/httpswift/swifter.git", + "state" : { + "revision" : "9483a5d459b45c3ffd059f7b55f9638e268632fd", + "version" : "1.5.0" + } + }, { "identity" : "trackerradarkit", "kind" : "remoteSourceControl",