diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a5a233c122..e26e8314b9 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -162,12 +162,11 @@ 3158B1492B0BF73000AF130C /* DBPHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3192EC872A4DCF21001E97A5 /* DBPHomeViewController.swift */; }; 3158B14A2B0BF74300AF130C /* DataBrokerProtectionDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316850712AF3AD58009A2828 /* DataBrokerProtectionDebugMenu.swift */; }; 3158B14D2B0BF74D00AF130C /* DataBrokerProtectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3139A1512AA4B3C000969C7D /* DataBrokerProtectionManager.swift */; }; - 3158B1502B0BF75200AF130C /* DataBrokerProtectionLoginItemScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */; }; + 3158B1502B0BF75200AF130C /* DataBrokerProtectionLoginItemInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemInterface.swift */; }; 3158B1532B0BF75700AF130C /* LoginItem+DataBrokerProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */; }; 3158B1562B0BF75D00AF130C /* DataBrokerProtectionFeatureVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C5FFB82AF64D120008A79F /* DataBrokerProtectionFeatureVisibility.swift */; }; 3158B1592B0BF76400AF130C /* DataBrokerProtectionFeatureDisabler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6F82AF94F5B002A7BA1 /* DataBrokerProtectionFeatureDisabler.swift */; }; 3158B15C2B0BF76D00AF130C /* DataBrokerProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6FC2AF97367002A7BA1 /* DataBrokerProtectionAppEvents.swift */; }; - 315A023D2B64216B00BFA577 /* IPCServiceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */; }; 315A023F2B6421AE00BFA577 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 315A023E2B6421AE00BFA577 /* Networking */; }; 315AA07028CA5CC800200030 /* YoutubePlayerNavigationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315AA06F28CA5CC800200030 /* YoutubePlayerNavigationHandler.swift */; }; 3168506D2AF3AD1D009A2828 /* WaitlistViewControllerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3168506C2AF3AD1C009A2828 /* WaitlistViewControllerPresenter.swift */; }; @@ -209,7 +208,7 @@ 31E163C0293A581900963C10 /* privacy-reference-tests in Resources */ = {isa = PBXBuildFile; fileRef = 31E163BF293A581900963C10 /* privacy-reference-tests */; }; 31EF1E802B63FFA800E6DB17 /* DBPHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3192EC872A4DCF21001E97A5 /* DBPHomeViewController.swift */; }; 31EF1E812B63FFB800E6DB17 /* DataBrokerProtectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3139A1512AA4B3C000969C7D /* DataBrokerProtectionManager.swift */; }; - 31EF1E822B63FFC200E6DB17 /* DataBrokerProtectionLoginItemScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */; }; + 31EF1E822B63FFC200E6DB17 /* DataBrokerProtectionLoginItemInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemInterface.swift */; }; 31EF1E832B63FFCA00E6DB17 /* LoginItem+DataBrokerProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */; }; 31EF1E842B63FFD100E6DB17 /* DataBrokerProtectionDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316850712AF3AD58009A2828 /* DataBrokerProtectionDebugMenu.swift */; }; 31F28C4F28C8EEC500119F70 /* YoutubePlayerUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F28C4C28C8EEC500119F70 /* YoutubePlayerUserScript.swift */; }; @@ -1542,7 +1541,6 @@ 7BBD45B12A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; 7BBD45B22A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; 7BBE2B7B2B61663C00697445 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7BBE2B7A2B61663C00697445 /* NetworkProtectionProxy */; }; - 7BD01C192AD8319C0088B32E /* IPCServiceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */; }; 7BD1688E2AD4A4C400D24876 /* NetworkExtensionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD1688D2AD4A4C400D24876 /* NetworkExtensionController.swift */; }; 7BD3AF5D2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; 7BDA36E62B7E037100AD5388 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B4D603E2A0B290200BCD287 /* NetworkExtension.framework */; }; @@ -1691,8 +1689,8 @@ 9D9AE9202AAA3B450026E7DC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D9AE9162AAA3B450026E7DC /* Assets.xcassets */; }; 9D9AE9212AAA3B450026E7DC /* UserText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9172AAA3B450026E7DC /* UserText.swift */; }; 9D9AE9222AAA3B450026E7DC /* UserText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9172AAA3B450026E7DC /* UserText.swift */; }; - 9D9AE9292AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */; }; - 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */; }; + 9D9AE9292AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift */; }; + 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift */; }; 9D9AE92C2AAB84FF0026E7DC /* DBPMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */; }; 9D9AE92D2AAB84FF0026E7DC /* DBPMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */; }; 9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DC70B192AA1FA5B005A844B /* LoginItems */; }; @@ -3296,7 +3294,7 @@ 7B4D8A202BDA857300852966 /* VPNOperationErrorRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNOperationErrorRecorder.swift; sourceTree = ""; }; 7B5291882A1697680022E406 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 7B5291892A169BC90022E406 /* DeveloperID.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DeveloperID.xcconfig; sourceTree = ""; }; - 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionLoginItemScheduler.swift; sourceTree = ""; }; + 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionLoginItemInterface.swift; sourceTree = ""; }; 7B6EC5E42AE2D8AF004FE6DF /* DuckDuckGoDBPAgentAppStore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DuckDuckGoDBPAgentAppStore.xcconfig; sourceTree = ""; }; 7B6EC5E52AE2D8AF004FE6DF /* DuckDuckGoDBPAgent.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DuckDuckGoDBPAgent.xcconfig; sourceTree = ""; }; 7B76E6852AD5D77600186A84 /* XPCHelper */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = XPCHelper; sourceTree = ""; }; @@ -3322,7 +3320,6 @@ 7BB108582A43375D000AB95F /* PFMoveApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PFMoveApplication.m; sourceTree = ""; }; 7BBA7CE52BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift"; sourceTree = ""; }; 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionDebugUtilities.swift; sourceTree = ""; }; - 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPCServiceManager.swift; sourceTree = ""; }; 7BD1688D2AD4A4C400D24876 /* NetworkExtensionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkExtensionController.swift; sourceTree = ""; }; 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeychainType+ClientDefault.swift"; sourceTree = ""; }; 7BD8679A2A9E9E000063B9F7 /* NetworkProtectionFeatureVisibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionFeatureVisibility.swift; sourceTree = ""; }; @@ -3447,7 +3444,7 @@ 9D9AE9182AAA3B450026E7DC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9D9AE9192AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppStore.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = DuckDuckGoDBPBackgroundAgentAppStore.entitlements; sourceTree = ""; }; 9D9AE91A2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgent.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = DuckDuckGoDBPBackgroundAgent.entitlements; sourceTree = ""; }; - 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionBackgroundManager.swift; sourceTree = ""; }; + 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionAgentManager.swift; sourceTree = ""; }; 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBPMocks.swift; sourceTree = ""; }; 9DB6E7222AA0DA7A00A17F3C /* LoginItems */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = LoginItems; sourceTree = ""; }; 9F0A2CF72B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseBookmarkEntityTests.swift; sourceTree = ""; }; @@ -4531,7 +4528,7 @@ 316850712AF3AD58009A2828 /* DataBrokerProtectionDebugMenu.swift */, 3192EC872A4DCF21001E97A5 /* DBPHomeViewController.swift */, 3139A1512AA4B3C000969C7D /* DataBrokerProtectionManager.swift */, - 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */, + 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemInterface.swift */, 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */, 31C5FFB82AF64D120008A79F /* DataBrokerProtectionFeatureVisibility.swift */, 3199C6F82AF94F5B002A7BA1 /* DataBrokerProtectionFeatureDisabler.swift */, @@ -6241,8 +6238,7 @@ isa = PBXGroup; children = ( 9D9AE9152AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift */, - 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */, - 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */, + 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift */, 7B0099782B65013800FE7C31 /* BrowserWindowManager.swift */, 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */, 9D9AE9172AAA3B450026E7DC /* UserText.swift */, @@ -10019,7 +10015,7 @@ 3706FC34293F65D500E42796 /* PermissionAuthorizationViewController.swift in Sources */, 3706FC35293F65D500E42796 /* BookmarkNode.swift in Sources */, B6ABD0CB2BC03F610000EB69 /* SecurityScopedFileURLController.swift in Sources */, - 31EF1E822B63FFC200E6DB17 /* DataBrokerProtectionLoginItemScheduler.swift in Sources */, + 31EF1E822B63FFC200E6DB17 /* DataBrokerProtectionLoginItemInterface.swift in Sources */, B6B140892ABDBCC1004F8E85 /* HoverTrackingArea.swift in Sources */, 3706FC36293F65D500E42796 /* LongPressButton.swift in Sources */, 3706FC37293F65D500E42796 /* CoreDataStore.swift in Sources */, @@ -10719,10 +10715,9 @@ 31A83FB72BE28D8A00F74E67 /* UserText+DBP.swift in Sources */, 9D9AE92C2AAB84FF0026E7DC /* DBPMocks.swift in Sources */, 7B0099792B65013800FE7C31 /* BrowserWindowManager.swift in Sources */, - 9D9AE9292AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */, + 9D9AE9292AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift in Sources */, 9D9AE91D2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */, 9D9AE9212AAA3B450026E7DC /* UserText.swift in Sources */, - 7BD01C192AD8319C0088B32E /* IPCServiceManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -10733,10 +10728,9 @@ 31A83FB82BE28D8A00F74E67 /* UserText+DBP.swift in Sources */, 7B1459542B7D437200047F2C /* BrowserWindowManager.swift in Sources */, 9D9AE92D2AAB84FF0026E7DC /* DBPMocks.swift in Sources */, - 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */, + 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionAgentManager.swift in Sources */, 9D9AE91E2AAA3B450026E7DC /* DuckDuckGoDBPBackgroundAgentAppDelegate.swift in Sources */, 9D9AE9222AAA3B450026E7DC /* UserText.swift in Sources */, - 315A023D2B64216B00BFA577 /* IPCServiceManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -10929,7 +10923,7 @@ 85707F26276A335700DC0649 /* Onboarding.swift in Sources */, B68C92C1274E3EF4002AC6B0 /* PopUpWindow.swift in Sources */, AA5FA6A0275F948900DCE9C9 /* Favicons.xcdatamodeld in Sources */, - 3158B1502B0BF75200AF130C /* DataBrokerProtectionLoginItemScheduler.swift in Sources */, + 3158B1502B0BF75200AF130C /* DataBrokerProtectionLoginItemInterface.swift in Sources */, 7BBA7CE62BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift in Sources */, B684592225C93BE000DC17B6 /* Publisher.asVoid.swift in Sources */, 4B9DB01D2A983B24000927DB /* Waitlist.swift in Sources */, diff --git a/DuckDuckGo/DBP/DBPHomeViewController.swift b/DuckDuckGo/DBP/DBPHomeViewController.swift index cf9e05e900..37691d9cac 100644 --- a/DuckDuckGo/DBP/DBPHomeViewController.swift +++ b/DuckDuckGo/DBP/DBPHomeViewController.swift @@ -61,7 +61,7 @@ final class DBPHomeViewController: NSViewController { featureToggles: features) return DataBrokerProtectionViewController( - scheduler: dataBrokerProtectionManager.scheduler, + agentInterface: dataBrokerProtectionManager.loginItemInterface, dataManager: dataBrokerProtectionManager.dataManager, privacyConfig: privacyConfigurationManager, prefs: prefs, diff --git a/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift b/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift index b22ee8eac2..5882131727 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift @@ -208,57 +208,21 @@ final class DataBrokerProtectionDebugMenu: NSMenu { os_log("Running queued operations...", log: .dataBrokerProtection) let showWebView = sender.representedObject as? Bool ?? false - DataBrokerProtectionManager.shared.scheduler.runQueuedOperations(showWebView: showWebView) { errors in - if let errors = errors { - if let oneTimeError = errors.oneTimeError { - os_log("Queued operations finished, error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) - } - if let operationErrors = errors.operationErrors, - operationErrors.count != 0 { - os_log("Queued operations finished, operation errors count: %{public}d", log: .dataBrokerProtection, operationErrors.count) - } - } else { - os_log("Queued operations finished", log: .dataBrokerProtection) - } - } + DataBrokerProtectionManager.shared.loginItemInterface.runQueuedOperations(showWebView: showWebView) } @objc private func runScanOperations(_ sender: NSMenuItem) { os_log("Running scan operations...", log: .dataBrokerProtection) let showWebView = sender.representedObject as? Bool ?? false - DataBrokerProtectionManager.shared.scheduler.startManualScan(showWebView: showWebView, startTime: Date()) { errors in - if let errors = errors { - if let oneTimeError = errors.oneTimeError { - os_log("scan operations finished, error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) - } - if let operationErrors = errors.operationErrors, - operationErrors.count != 0 { - os_log("scan operations finished, operation errors count: %{public}d", log: .dataBrokerProtection, operationErrors.count) - } - } else { - os_log("Scan operations finished", log: .dataBrokerProtection) - } - } + DataBrokerProtectionManager.shared.loginItemInterface.startManualScan(showWebView: showWebView) } @objc private func runOptoutOperations(_ sender: NSMenuItem) { os_log("Running Optout operations...", log: .dataBrokerProtection) let showWebView = sender.representedObject as? Bool ?? false - DataBrokerProtectionManager.shared.scheduler.optOutAllBrokers(showWebView: showWebView) { errors in - if let errors = errors { - if let oneTimeError = errors.oneTimeError { - os_log("Optout operations finished, error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) - } - if let operationErrors = errors.operationErrors, - operationErrors.count != 0 { - os_log("Optout operations finished, operation errors count: %{public}d", log: .dataBrokerProtection, operationErrors.count) - } - } else { - os_log("Optout operations finished", log: .dataBrokerProtection) - } - } + DataBrokerProtectionManager.shared.loginItemInterface.runAllOptOuts(showWebView: showWebView) } @objc private func backgroundAgentRestart() { diff --git a/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift b/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift index 83489b21bb..8d5ea0401a 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift @@ -31,20 +31,18 @@ protocol DataBrokerProtectionFeatureDisabling { } struct DataBrokerProtectionFeatureDisabler: DataBrokerProtectionFeatureDisabling { - private let scheduler: DataBrokerProtectionLoginItemScheduler + private let loginItemInterface: DataBrokerProtectionLoginItemInterface private let dataManager: InMemoryDataCacheDelegate - init(scheduler: DataBrokerProtectionLoginItemScheduler = DataBrokerProtectionManager.shared.scheduler, + init(loginItemInterface: DataBrokerProtectionLoginItemInterface = DataBrokerProtectionManager.shared.loginItemInterface, dataManager: InMemoryDataCacheDelegate = DataBrokerProtectionManager.shared.dataManager) { self.dataManager = dataManager - self.scheduler = scheduler + self.loginItemInterface = loginItemInterface } func disableAndDelete() { if !DefaultDataBrokerProtectionFeatureVisibility.bypassWaitlist { - scheduler.stopScheduler() - - scheduler.disableLoginItem() + loginItemInterface.disableLoginItem() do { try dataManager.removeAllData() diff --git a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemInterface.swift b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemInterface.swift new file mode 100644 index 0000000000..87652a1aa6 --- /dev/null +++ b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemInterface.swift @@ -0,0 +1,101 @@ +// +// DataBrokerProtectionLoginItemInterface.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. +// + +#if DBP + +import Foundation +import DataBrokerProtection +import Common + +protocol DataBrokerProtectionLoginItemInterface: DataBrokerProtectionAgentInterface { + func disableLoginItem() + func enableLoginItem() +} + +/// Launches a login item and then communicates with it through IPC +/// +final class DefaultDataBrokerProtectionLoginItemInterface { + private let ipcClient: DataBrokerProtectionIPCClient + private let loginItemsManager: LoginItemsManager + + init(ipcClient: DataBrokerProtectionIPCClient, loginItemsManager: LoginItemsManager = .init()) { + self.ipcClient = ipcClient + self.loginItemsManager = loginItemsManager + } +} + +extension DefaultDataBrokerProtectionLoginItemInterface: DataBrokerProtectionLoginItemInterface { + + // MARK: - Login Item Management + + func disableLoginItem() { + DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerDisableLoginItemDaily, frequency: .daily) + loginItemsManager.disableLoginItems([.dbpBackgroundAgent]) + } + + func enableLoginItem() { + DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerEnableLoginItemDaily, frequency: .daily) + loginItemsManager.enableLoginItems([.dbpBackgroundAgent], log: .dbp) + } + + // MARK: - DataBrokerProtectionAgentInterface + // MARK: - DataBrokerProtectionAgentAppEvents + + func profileSaved() { + enableLoginItem() + ipcClient.profileSaved { error in + // TODO + } + } + + func dataDeleted() { + ipcClient.dataDeleted { error in + // TODO + } + } + + func appLaunched() { + ipcClient.appLaunched { error in + // TODO + } + } + + // MARK: - DataBrokerProtectionAgentDebugCommands + + func openBrowser(domain: String) { + ipcClient.openBrowser(domain: domain) + } + + func startManualScan(showWebView: Bool) { + ipcClient.startManualScan(showWebView: showWebView) + } + + func runQueuedOperations(showWebView: Bool) { + ipcClient.runQueuedOperations(showWebView: showWebView) + } + + func runAllOptOuts(showWebView: Bool) { + ipcClient.runAllOptOuts(showWebView: showWebView) + } + + func getDebugMetadata() async -> DataBrokerProtection.DBPBackgroundAgentMetadata? { + return await ipcClient.getDebugMetadata() + } +} + +#endif diff --git a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift deleted file mode 100644 index 50b75e9fac..0000000000 --- a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// DataBrokerProtectionLoginItemScheduler.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. -// - -#if DBP - -import Foundation -import DataBrokerProtection -import Common - -/// A scheduler that launches a login item and the communicates with it through an IPC scheduler. -/// -final class DataBrokerProtectionLoginItemScheduler { - private let ipcScheduler: DataBrokerProtectionIPCScheduler - private let loginItemsManager: LoginItemsManager - - init(ipcScheduler: DataBrokerProtectionIPCScheduler, loginItemsManager: LoginItemsManager = .init()) { - self.ipcScheduler = ipcScheduler - self.loginItemsManager = loginItemsManager - } - - // MARK: - Login Item Management - - func disableLoginItem() { - DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerDisableLoginItemDaily, frequency: .daily) - loginItemsManager.disableLoginItems([.dbpBackgroundAgent]) - } - - func enableLoginItem() { - DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerEnableLoginItemDaily, frequency: .daily) - loginItemsManager.enableLoginItems([.dbpBackgroundAgent], log: .dbp) - } -} - -extension DataBrokerProtectionLoginItemScheduler: DataBrokerProtectionScheduler { - var status: DataBrokerProtection.DataBrokerProtectionSchedulerStatus { - ipcScheduler.status - } - - var statusPublisher: Published.Publisher { - ipcScheduler.statusPublisher - } - - func startManualScan(showWebView: Bool, - startTime: Date, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { - enableLoginItem() - ipcScheduler.startManualScan(showWebView: showWebView, startTime: startTime, completion: completion) - } - - func startScheduler(showWebView: Bool) { - enableLoginItem() - ipcScheduler.startScheduler(showWebView: showWebView) - } - - func stopScheduler() { - ipcScheduler.stopScheduler() - } - - func optOutAllBrokers(showWebView: Bool, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { - ipcScheduler.optOutAllBrokers(showWebView: showWebView, completion: completion) - } - - func runAllOperations(showWebView: Bool) { - ipcScheduler.runAllOperations(showWebView: showWebView) - } - - func runQueuedOperations(showWebView: Bool, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { - ipcScheduler.runQueuedOperations(showWebView: showWebView, completion: completion) - } - - func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) { - ipcScheduler.getDebugMetadata(completion: completion) - } -} - -#endif diff --git a/DuckDuckGo/DBP/DataBrokerProtectionManager.swift b/DuckDuckGo/DBP/DataBrokerProtectionManager.swift index f3b8705674..41844bb3cc 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionManager.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionManager.swift @@ -48,11 +48,8 @@ public final class DataBrokerProtectionManager { loginItemStatusChecker: loginItemStatusChecker) }() - lazy var scheduler: DataBrokerProtectionLoginItemScheduler = { - - let ipcScheduler = DataBrokerProtectionIPCScheduler(ipcClient: ipcClient) - - return DataBrokerProtectionLoginItemScheduler(ipcScheduler: ipcScheduler) + lazy var loginItemInterface: DataBrokerProtectionLoginItemInterface = { + return DefaultDataBrokerProtectionLoginItemInterface(ipcClient: ipcClient) }() private init() { @@ -74,14 +71,14 @@ public final class DataBrokerProtectionManager { extension DataBrokerProtectionManager: DataBrokerProtectionDataManagerDelegate { public func dataBrokerProtectionDataManagerDidUpdateData() { - scheduler.startScheduler() + loginItemInterface.profileSaved() let dbpDateStore = DefaultWaitlistActivationDateStore(source: .dbp) dbpDateStore.setActivationDateIfNecessary() } public func dataBrokerProtectionDataManagerDidDeleteData() { - scheduler.stopScheduler() + loginItemInterface.dataDeleted() } } diff --git a/DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionBackgroundManager.swift b/DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionAgentManager.swift similarity index 60% rename from DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionBackgroundManager.swift rename to DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionAgentManager.swift index 2bdc06947a..2c43ba5592 100644 --- a/DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionBackgroundManager.swift +++ b/DuckDuckGoDBPBackgroundAgent/DataBrokerProtectionAgentManager.swift @@ -1,5 +1,5 @@ // -// DataBrokerProtectionBackgroundManager.swift +// DataBrokerProtectionAgentManager.swift // // Copyright © 2023 DuckDuckGo. All rights reserved. // @@ -22,9 +22,9 @@ import BrowserServicesKit import DataBrokerProtection import PixelKit -public final class DataBrokerProtectionBackgroundManager { +public final class DataBrokerProtectionAgentManager { - static let shared = DataBrokerProtectionBackgroundManager() + static let shared = DataBrokerProtectionAgentManager() private let pixelHandler: EventMapping = DataBrokerProtectionPixelsHandler() @@ -32,14 +32,19 @@ public final class DataBrokerProtectionBackgroundManager { private let authenticationService: DataBrokerProtectionAuthenticationService = AuthenticationService() private let redeemUseCase: DataBrokerProtectionRedeemUseCase private let fakeBrokerFlag: DataBrokerDebugFlag = DataBrokerDebugFlagFakeBroker() + private lazy var browserWindowManager = BrowserWindowManager() - private lazy var ipcServiceManager = IPCServiceManager(scheduler: scheduler, pixelHandler: pixelHandler) + private lazy var ipcServer: DataBrokerProtectionIPCServer = { + let server = DataBrokerProtectionIPCServer(machServiceName: Bundle.main.bundleIdentifier!) + server.serverDelegate = self + return server + }() lazy var dataManager: DataBrokerProtectionDataManager = { DataBrokerProtectionDataManager(pixelHandler: pixelHandler, fakeBrokerFlag: fakeBrokerFlag) }() - lazy var scheduler: DataBrokerProtectionScheduler = { + lazy var scheduler: DefaultDataBrokerProtectionScheduler = { let privacyConfigurationManager = PrivacyConfigurationManagingMock() // Forgive me, for I have sinned let features = ContentScopeFeatureToggles(emailProtection: false, emailProtectionIncontextSignup: false, @@ -72,10 +77,10 @@ public final class DataBrokerProtectionBackgroundManager { private init() { self.redeemUseCase = RedeemUseCase(authenticationService: authenticationService, authenticationRepository: authenticationRepository) - _ = ipcServiceManager + ipcServer.activate() } - public func runOperationsAndStartSchedulerIfPossible() { + public func agentFinishedLaunching() { pixelHandler.fire(.backgroundAgentRunOperationsAndStartSchedulerIfPossible) do { @@ -90,24 +95,71 @@ public final class DataBrokerProtectionBackgroundManager { return } - scheduler.runQueuedOperations(showWebView: false) { [weak self] errors in - if let errors = errors { - if let oneTimeError = errors.oneTimeError { - os_log("Error during BackgroundManager runOperationsAndStartSchedulerIfPossible in scheduler.runQueuedOperations(), error: %{public}@", - log: .dataBrokerProtection, - oneTimeError.localizedDescription) - self?.pixelHandler.fire(.generalError(error: oneTimeError, - functionOccurredIn: "DataBrokerProtectionBackgroundManager.runOperationsAndStartSchedulerIfPossible")) - } - if let operationErrors = errors.operationErrors, - operationErrors.count != 0 { - os_log("Operation error(s) during BackgroundManager runOperationsAndStartSchedulerIfPossible in scheduler.runQueuedOperations(), count: %{public}d", log: .dataBrokerProtection, operationErrors.count) - } - return - } - + scheduler.runQueuedOperations(showWebView: false) { [weak self] _ in self?.pixelHandler.fire(.backgroundAgentRunOperationsAndStartSchedulerIfPossibleRunQueuedOperationsCallbackStartScheduler) self?.scheduler.startScheduler() } } } + +extension DataBrokerProtectionAgentManager: DataBrokerProtectionAgentAppEvents { + + public func profileSaved() { + scheduler.startManualScan(startTime: Date()) { _ in + + } + } + + public func dataDeleted() { + scheduler.stopScheduler() + } + + public func appLaunched() { + scheduler.runQueuedOperations() + } +} + +extension DataBrokerProtectionAgentManager: DataBrokerProtectionAgentDebugCommands { + public func openBrowser(domain: String) { + Task { @MainActor in + browserWindowManager.show(domain: domain) + } + } + + public func startManualScan(showWebView: Bool) { + scheduler.startManualScan(startTime: Date()) { _ in + + } + } + + public func runQueuedOperations(showWebView: Bool) { + scheduler.runQueuedOperations(showWebView: showWebView) + } + + public func runAllOptOuts(showWebView: Bool) { + scheduler.optOutAllBrokers(showWebView: showWebView) { _ in + + } + } + + public func getDebugMetadata() async -> DataBrokerProtection.DBPBackgroundAgentMetadata? { + + if let backgroundAgentVersion = Bundle.main.releaseVersionNumber, + let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String { + + return DBPBackgroundAgentMetadata(backgroundAgentVersion: backgroundAgentVersion + " (build: \(buildNumber))", + isAgentRunning: scheduler.status == .running, + agentSchedulerState: scheduler.status.toString, + lastSchedulerSessionStartTimestamp: scheduler.lastSchedulerSessionStartTimestamp?.timeIntervalSince1970) + } else { + return DBPBackgroundAgentMetadata(backgroundAgentVersion: "ERROR: Error fetching background agent version", + isAgentRunning: scheduler.status == .running, + agentSchedulerState: scheduler.status.toString, + lastSchedulerSessionStartTimestamp: scheduler.lastSchedulerSessionStartTimestamp?.timeIntervalSince1970) + } + } +} + +extension DataBrokerProtectionAgentManager: DataBrokerProtectionAgentInterface { + +} diff --git a/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift index 0a3e777138..f1b42dad3a 100644 --- a/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift +++ b/DuckDuckGoDBPBackgroundAgent/DuckDuckGoDBPBackgroundAgentAppDelegate.swift @@ -85,8 +85,8 @@ final class DuckDuckGoDBPBackgroundAgentAppDelegate: NSObject, NSApplicationDele func applicationDidFinishLaunching(_ aNotification: Notification) { os_log("DuckDuckGoAgent started", log: .dbpBackgroundAgent, type: .info) - let manager = DataBrokerProtectionBackgroundManager.shared - manager.runOperationsAndStartSchedulerIfPossible() + let manager = DataBrokerProtectionAgentManager.shared + manager.agentFinishedLaunching() setupStatusBarMenu() } diff --git a/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift b/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift deleted file mode 100644 index 8c39f28e07..0000000000 --- a/DuckDuckGoDBPBackgroundAgent/IPCServiceManager.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// IPCServiceManager.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 Combine -import Common -import DataBrokerProtection -import Foundation -import PixelKit - -/// Manages the IPC service for the Agent app -/// -/// This class will handle all interactions between IPC requests and the classes those requests -/// demand interaction with. -/// -final class IPCServiceManager { - private var browserWindowManager: BrowserWindowManager - private let ipcServer: DataBrokerProtectionIPCServer - private let scheduler: DataBrokerProtectionScheduler - private let pixelHandler: EventMapping - private var cancellables = Set() - - init(ipcServer: DataBrokerProtectionIPCServer = .init(machServiceName: Bundle.main.bundleIdentifier!), - scheduler: DataBrokerProtectionScheduler, - pixelHandler: EventMapping) { - - self.ipcServer = ipcServer - self.scheduler = scheduler - self.pixelHandler = pixelHandler - - browserWindowManager = BrowserWindowManager() - - ipcServer.serverDelegate = self - ipcServer.activate() - } - - private func subscribeToSchedulerStatusChanges() { - scheduler.statusPublisher - .subscribe(on: DispatchQueue.main) - .sink { [weak self] status in - self?.ipcServer.schedulerStatusChanges(status) - } - .store(in: &cancellables) - } -} - -extension IPCServiceManager: IPCServerInterface { - - func register() { - // When a new client registers, send the last known status - ipcServer.schedulerStatusChanges(scheduler.status) - } - - func startScheduler(showWebView: Bool) { - pixelHandler.fire(.ipcServerStartSchedulerReceivedByAgent) - scheduler.startScheduler(showWebView: showWebView) - } - - func stopScheduler() { - pixelHandler.fire(.ipcServerStopSchedulerReceivedByAgent) - scheduler.stopScheduler() - } - - func optOutAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - pixelHandler.fire(.ipcServerOptOutAllBrokers) - scheduler.optOutAllBrokers(showWebView: showWebView) { errors in - self.pixelHandler.fire(.ipcServerOptOutAllBrokersCompletion(error: errors?.oneTimeError)) - completion(errors) - } - } - - func startManualScan(showWebView: Bool, - startTime: Date, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - pixelHandler.fire(.ipcServerScanAllBrokersReceivedByAgent) - scheduler.startManualScan(showWebView: showWebView, startTime: startTime) { errors in - if let error = errors?.oneTimeError { - switch error { - case DataBrokerProtectionSchedulerError.operationsInterrupted: - self.pixelHandler.fire(.ipcServerScanAllBrokersInterruptedOnAgent) - default: - self.pixelHandler.fire(.ipcServerScanAllBrokersCompletedOnAgentWithError(error: error)) - } - } else { - self.pixelHandler.fire(.ipcServerScanAllBrokersCompletedOnAgentWithoutError) - } - completion(errors) - } - } - - func runQueuedOperations(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - pixelHandler.fire(.ipcServerRunQueuedOperations) - scheduler.runQueuedOperations(showWebView: showWebView) { errors in - self.pixelHandler.fire(.ipcServerRunQueuedOperationsCompletion(error: errors?.oneTimeError)) - completion(errors) - } - } - - func runAllOperations(showWebView: Bool) { - pixelHandler.fire(.ipcServerRunAllOperations) - scheduler.runAllOperations(showWebView: showWebView) - } - - func openBrowser(domain: String) { - Task { @MainActor in - browserWindowManager.show(domain: domain) - } - } - - func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) { - scheduler.getDebugMetadata(completion: completion) - } -} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift index b006af7433..5a33e63831 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Database/DataBrokerProtectionDataManager.swift @@ -294,7 +294,10 @@ extension InMemoryDataCache: DBPUICommunicationDelegate { } func startScanAndOptOut() -> Bool { - return scanDelegate?.startScan(startDate: Date()) ?? false + // This is now unusused as we decided the web UI shouldn't issue commands directly + // The background agent itself instead decides to start scans based on events + // This should be removed once we can remove it from the web side + return true } func getInitialScanState() async -> DBPUIInitialScanState { diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionAgentInterface.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionAgentInterface.swift new file mode 100644 index 0000000000..3ef3bfc69f --- /dev/null +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionAgentInterface.swift @@ -0,0 +1,81 @@ +// +// DataBrokerProtectionAgentInterface.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 + +public enum DataBrokerProtectionAgentInterfaceError: Error { + case loginItemDoesNotHaveNecessaryPermissions + case appInWrongDirectory + case operationsInterrupted +} + +@objc +public class DataBrokerProtectionAgentErrorCollection: NSObject, NSSecureCoding { + /* + This needs to be an NSObject (rather than a struct) so it can be represented in Objective C + and confrom to NSSecureCoding for the IPC layer. + */ + + private enum NSSecureCodingKeys { + static let oneTimeError = "oneTimeError" + static let operationErrors = "operationErrors" + } + + public let oneTimeError: Error? + public let operationErrors: [Error]? + + public init(oneTimeError: Error? = nil, operationErrors: [Error]? = nil) { + self.oneTimeError = oneTimeError + self.operationErrors = operationErrors + super.init() + } + + // MARK: - NSSecureCoding + + public static var supportsSecureCoding: Bool { + return true + } + + public func encode(with coder: NSCoder) { + coder.encode(oneTimeError, forKey: NSSecureCodingKeys.oneTimeError) + coder.encode(operationErrors, forKey: NSSecureCodingKeys.operationErrors) + } + + public required init?(coder: NSCoder) { + oneTimeError = coder.decodeObject(of: NSError.self, forKey: NSSecureCodingKeys.oneTimeError) + operationErrors = coder.decodeArrayOfObjects(ofClass: NSError.self, forKey: NSSecureCodingKeys.operationErrors) + } +} + +public protocol DataBrokerProtectionAgentAppEvents { + func profileSaved() + func dataDeleted() + func appLaunched() +} + +public protocol DataBrokerProtectionAgentDebugCommands { + func openBrowser(domain: String) + func startManualScan(showWebView: Bool) + func runQueuedOperations(showWebView: Bool) + func runAllOptOuts(showWebView: Bool) + func getDebugMetadata() async -> DBPBackgroundAgentMetadata? +} + +public protocol DataBrokerProtectionAgentInterface: AnyObject, DataBrokerProtectionAgentAppEvents, DataBrokerProtectionAgentDebugCommands { + +} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift index 1f1d2451b2..564e33b1b5 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCClient.swift @@ -24,7 +24,6 @@ import XPCHelper /// This protocol describes the server-side IPC interface for controlling the tunnel /// public protocol IPCClientInterface: AnyObject { - func schedulerStatusChanges(_ status: DataBrokerProtectionSchedulerStatus) } public protocol DBPLoginItemStatusChecker { @@ -35,7 +34,6 @@ public protocol DBPLoginItemStatusChecker { /// This is the XPC interface with parameters that can be packed properly @objc protocol XPCClientInterface: NSObjectProtocol { - func schedulerStatusChanged(_ payload: Data) } public final class DataBrokerProtectionIPCClient: NSObject { @@ -47,15 +45,6 @@ public final class DataBrokerProtectionIPCClient: NSObject { let xpc: XPCClient - // MARK: - Scheduler Status - - @Published - private(set) public var schedulerStatus: DataBrokerProtectionSchedulerStatus = .idle - - public var schedulerStatusPublisher: Published.Publisher { - $schedulerStatus - } - // MARK: - Initializers public init(machServiceName: String, pixelHandler: EventMapping, loginItemStatusChecker: DBPLoginItemStatusChecker) { @@ -100,137 +89,94 @@ extension DataBrokerProtectionIPCClient: IPCServerInterface { }) } - public func startScheduler(showWebView: Bool) { - self.pixelHandler.fire(.ipcServerStartSchedulerCalledByApp) + // MARK: - DataBrokerProtectionAgentAppEvents + + public func profileSaved(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) { xpc.execute(call: { server in - server.startScheduler(showWebView: showWebView) + server.profileSaved(xpcMessageReceivedCompletion: xpcMessageReceivedCompletion) }, xpcReplyErrorHandler: { error in - self.pixelHandler.fire(.ipcServerStartSchedulerXPCError(error: error)) + os_log("Error \(error.localizedDescription)") // Intentional no-op as there's no completion block // If you add a completion block, please remember to call it here too! }) } - public func stopScheduler() { - self.pixelHandler.fire(.ipcServerStopSchedulerCalledByApp) + public func dataDeleted(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) { xpc.execute(call: { server in - server.stopScheduler() + server.dataDeleted(xpcMessageReceivedCompletion: xpcMessageReceivedCompletion) }, xpcReplyErrorHandler: { error in - self.pixelHandler.fire(.ipcServerStopSchedulerXPCError(error: error)) + os_log("Error \(error.localizedDescription)") // Intentional no-op as there's no completion block // If you add a completion block, please remember to call it here too! }) } - public func optOutAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - self.pixelHandler.fire(.ipcServerOptOutAllBrokers) + public func appLaunched(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) { xpc.execute(call: { server in - server.optOutAllBrokers(showWebView: showWebView) { errors in - self.pixelHandler.fire(.ipcServerRunQueuedOperationsCompletion(error: errors?.oneTimeError)) - completion(errors) - } + server.appLaunched(xpcMessageReceivedCompletion: xpcMessageReceivedCompletion) }, xpcReplyErrorHandler: { error in - self.pixelHandler.fire(.ipcServerRunQueuedOperationsCompletion(error: error)) - completion(DataBrokerProtectionSchedulerErrorCollection(oneTimeError: error)) + os_log("Error \(error.localizedDescription)") + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! }) } - public func startManualScan(showWebView: Bool, - startTime: Date, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - self.pixelHandler.fire(.ipcServerScanAllBrokersCalledByApp) - - guard loginItemStatusChecker.doesHaveNecessaryPermissions() else { - self.pixelHandler.fire(.ipcServerScanAllBrokersAttemptedToCallWithoutLoginItemPermissions) - let errors = DataBrokerProtectionSchedulerErrorCollection(oneTimeError: DataBrokerProtectionSchedulerError.loginItemDoesNotHaveNecessaryPermissions) - completion(errors) - return - } - - guard loginItemStatusChecker.isInCorrectDirectory() else { - self.pixelHandler.fire(.ipcServerScanAllBrokersAttemptedToCallInWrongDirectory) - let errors = DataBrokerProtectionSchedulerErrorCollection(oneTimeError: DataBrokerProtectionSchedulerError.appInWrongDirectory) - completion(errors) - return - } + // MARK: - DataBrokerProtectionAgentDebugCommands + public func openBrowser(domain: String) { xpc.execute(call: { server in - server.startManualScan(showWebView: showWebView, startTime: startTime) { errors in - if let error = errors?.oneTimeError { - let nsError = error as NSError - let interruptedError = DataBrokerProtectionSchedulerError.operationsInterrupted as NSError - if nsError.domain == interruptedError.domain, - nsError.code == interruptedError.code { - self.pixelHandler.fire(.ipcServerScanAllBrokersCompletionCalledOnAppAfterInterruption) - } else { - self.pixelHandler.fire(.ipcServerScanAllBrokersCompletionCalledOnAppWithError(error: error)) - } - } else { - self.pixelHandler.fire(.ipcServerScanAllBrokersCompletionCalledOnAppWithoutError) - } - completion(errors) - } + server.openBrowser(domain: domain) }, xpcReplyErrorHandler: { error in - self.pixelHandler.fire(.ipcServerScanAllBrokersXPCError(error: error)) - completion(DataBrokerProtectionSchedulerErrorCollection(oneTimeError: error)) + os_log("Error \(error.localizedDescription)") + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! }) } - public func runQueuedOperations(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - self.pixelHandler.fire(.ipcServerRunQueuedOperations) + public func startManualScan(showWebView: Bool) { xpc.execute(call: { server in - server.runQueuedOperations(showWebView: showWebView) { errors in - self.pixelHandler.fire(.ipcServerRunQueuedOperationsCompletion(error: errors?.oneTimeError)) - completion(errors) - } + server.startManualScan(showWebView: showWebView) }, xpcReplyErrorHandler: { error in - self.pixelHandler.fire(.ipcServerRunQueuedOperationsCompletion(error: error)) - completion(DataBrokerProtectionSchedulerErrorCollection(oneTimeError: error)) - }) - } - - public func runAllOperations(showWebView: Bool) { - self.pixelHandler.fire(.ipcServerRunAllOperations) - xpc.execute(call: { server in - server.runAllOperations(showWebView: showWebView) - }, xpcReplyErrorHandler: { _ in + os_log("Error \(error.localizedDescription)") // Intentional no-op as there's no completion block // If you add a completion block, please remember to call it here too! }) } - public func openBrowser(domain: String) { - self.pixelHandler.fire(.ipcServerRunAllOperations) + public func runQueuedOperations(showWebView: Bool) { xpc.execute(call: { server in - server.openBrowser(domain: domain) + server.runQueuedOperations(showWebView: showWebView) }, xpcReplyErrorHandler: { error in os_log("Error \(error.localizedDescription)") // Intentional no-op as there's no completion block // If you add a completion block, please remember to call it here too! - }) - } + }) } - public func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) { + public func runAllOptOuts(showWebView: Bool) { xpc.execute(call: { server in - server.getDebugMetadata(completion: completion) + server.runAllOptOuts(showWebView: showWebView) }, xpcReplyErrorHandler: { error in os_log("Error \(error.localizedDescription)") - completion(nil) + // Intentional no-op as there's no completion block + // If you add a completion block, please remember to call it here too! }) } + + public func getDebugMetadata() async -> DBPBackgroundAgentMetadata? { + await withCheckedContinuation { continuation in + xpc.execute(call: { server in + server.getDebugMetadata { metaData in + continuation.resume(returning: metaData) + } + }, xpcReplyErrorHandler: { error in + os_log("Error \(error.localizedDescription)") + continuation.resume(returning: nil) + }) + } + } } // MARK: - Incoming communication from the server extension DataBrokerProtectionIPCClient: XPCClientInterface { - func schedulerStatusChanged(_ payload: Data) { - guard let status = try? JSONDecoder().decode(DataBrokerProtectionSchedulerStatus.self, from: payload) else { - - return - } - - schedulerStatus = status - } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift deleted file mode 100644 index ea73c3e1a0..0000000000 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCScheduler.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// DataBrokerProtectionIPCScheduler.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 Combine -import Common - -/// A scheduler that works through IPC to request the scheduling to a different process -/// -public final class DataBrokerProtectionIPCScheduler: DataBrokerProtectionScheduler { - private let ipcClient: DataBrokerProtectionIPCClient - - public init(ipcClient: DataBrokerProtectionIPCClient) { - self.ipcClient = ipcClient - } - - public var status: DataBrokerProtectionSchedulerStatus { - ipcClient.schedulerStatus - } - - public var statusPublisher: Published.Publisher { - ipcClient.schedulerStatusPublisher - } - - public func startScheduler(showWebView: Bool) { - ipcClient.startScheduler(showWebView: showWebView) - } - - public func stopScheduler() { - ipcClient.stopScheduler() - } - - public func optOutAllBrokers(showWebView: Bool, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { - let completion = completion ?? { _ in } - ipcClient.optOutAllBrokers(showWebView: showWebView, completion: completion) - } - - public func startManualScan(showWebView: Bool, - startTime: Date, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { - let completion = completion ?? { _ in } - ipcClient.startManualScan(showWebView: showWebView, startTime: startTime, completion: completion) - } - - public func runQueuedOperations(showWebView: Bool, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { - let completion = completion ?? { _ in } - ipcClient.runQueuedOperations(showWebView: showWebView, completion: completion) - } - - public func runAllOperations(showWebView: Bool) { - ipcClient.runAllOperations(showWebView: showWebView) - } - - public func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) { - ipcClient.getDebugMetadata(completion: completion) - } -} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift index 7f4ae3e840..53e260cdcf 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/IPC/DataBrokerProtectionIPCServer.swift @@ -35,10 +35,10 @@ public final class DBPBackgroundAgentMetadata: NSObject, NSSecureCoding { let agentSchedulerState: String let lastSchedulerSessionStartTimestamp: Double? - init(backgroundAgentVersion: String, - isAgentRunning: Bool, - agentSchedulerState: String, - lastSchedulerSessionStartTimestamp: Double?) { + public init(backgroundAgentVersion: String, + isAgentRunning: Bool, + agentSchedulerState: String, + lastSchedulerSessionStartTimestamp: Double?) { self.backgroundAgentVersion = backgroundAgentVersion self.isAgentRunning = isAgentRunning self.agentSchedulerState = agentSchedulerState @@ -75,40 +75,18 @@ public final class DBPBackgroundAgentMetadata: NSObject, NSSecureCoding { /// This protocol describes the server-side IPC interface for controlling the tunnel /// -public protocol IPCServerInterface: AnyObject { +public protocol IPCServerInterface: AnyObject, DataBrokerProtectionAgentDebugCommands { /// Registers a connection with the server. /// /// This is the point where the server will start sending status updates to the client. /// func register() - // MARK: - Scheduler + // MARK: - DataBrokerProtectionAgentAppEvents - /// Start the scheduler - /// - func startScheduler(showWebView: Bool) - - /// Stop the scheduler - /// - func stopScheduler() - - func optOutAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func startManualScan(showWebView: Bool, - startTime: Date, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func runQueuedOperations(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func runAllOperations(showWebView: Bool) - - // MARK: - Debugging Features - - /// Opens a browser window with the specified domain - /// - func openBrowser(domain: String) - - /// Returns background agent metadata for debugging purposes - func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) + func profileSaved(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) + func dataDeleted(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) + func appLaunched(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) } /// This protocol describes the server-side XPC interface. @@ -124,31 +102,21 @@ protocol XPCServerInterface { /// func register() - // MARK: - Scheduler - - /// Start the scheduler - /// - func startScheduler(showWebView: Bool) - - /// Stop the scheduler - /// - func stopScheduler() + // MARK: - DataBrokerProtectionAgentAppEvents - func optOutAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func startManualScan(showWebView: Bool, - startTime: Date, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func runQueuedOperations(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) - func runAllOperations(showWebView: Bool) + func profileSaved(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) + func dataDeleted(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) + func appLaunched(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) - // MARK: - Debugging Features + // MARK: - DataBrokerProtectionAgentDebugCommands /// Opens a browser window with the specified domain /// func openBrowser(domain: String) + func startManualScan(showWebView: Bool) + func runQueuedOperations(showWebView: Bool) + func runAllOptOuts(showWebView: Bool) func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) } @@ -157,7 +125,7 @@ public final class DataBrokerProtectionIPCServer { /// The delegate. /// - public weak var serverDelegate: IPCServerInterface? + public weak var serverDelegate: DataBrokerProtectionAgentInterface? public init(machServiceName: String) { let clientInterface = NSXPCInterface(with: XPCClientInterface.self) @@ -179,62 +147,55 @@ public final class DataBrokerProtectionIPCServer { // MARK: - Outgoing communication to the clients extension DataBrokerProtectionIPCServer: IPCClientInterface { - - public func schedulerStatusChanges(_ status: DataBrokerProtectionSchedulerStatus) { - let payload: Data - - do { - payload = try JSONEncoder().encode(status) - } catch { - return - } - - xpc.forEachClient { client in - client.schedulerStatusChanged(payload) - } - } } // MARK: - Incoming communication from a client extension DataBrokerProtectionIPCServer: XPCServerInterface { + func register() { - serverDelegate?.register() + } - func startScheduler(showWebView: Bool) { - serverDelegate?.startScheduler(showWebView: showWebView) + // MARK: - DataBrokerProtectionAgentAppEvents + + func profileSaved(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) { + xpcMessageReceivedCompletion(nil) + serverDelegate?.profileSaved() } - func stopScheduler() { - serverDelegate?.stopScheduler() + func dataDeleted(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) { + xpcMessageReceivedCompletion(nil) + serverDelegate?.dataDeleted() } - func optOutAllBrokers(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - serverDelegate?.optOutAllBrokers(showWebView: showWebView, completion: completion) + func appLaunched(xpcMessageReceivedCompletion: @escaping (Error?) -> Void) { + xpcMessageReceivedCompletion(nil) + serverDelegate?.appLaunched() } - func startManualScan(showWebView: Bool, - startTime: Date, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - serverDelegate?.startManualScan(showWebView: showWebView, startTime: startTime, completion: completion) + // MARK: - DataBrokerProtectionAgentDebugCommands + + func openBrowser(domain: String) { + serverDelegate?.openBrowser(domain: domain) } - func runQueuedOperations(showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { - serverDelegate?.runQueuedOperations(showWebView: showWebView, completion: completion) + func startManualScan(showWebView: Bool) { + serverDelegate?.startManualScan(showWebView: showWebView) } - func runAllOperations(showWebView: Bool) { - serverDelegate?.runAllOperations(showWebView: showWebView) + func runQueuedOperations(showWebView: Bool) { + serverDelegate?.runQueuedOperations(showWebView: showWebView) } - func openBrowser(domain: String) { - serverDelegate?.openBrowser(domain: domain) + func runAllOptOuts(showWebView: Bool) { + serverDelegate?.runAllOptOuts(showWebView: showWebView) } func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) { - serverDelegate?.getDebugMetadata(completion: completion) + Task { + let metaData = await serverDelegate?.getDebugMetadata() + completion(metaData) + } } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift index a43f6d9ae0..b66973d3d1 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Model/DBPUIViewModel.swift @@ -23,14 +23,13 @@ import BrowserServicesKit import Common protocol DBPUIScanOps: AnyObject { - func startScan(startDate: Date) -> Bool func updateCacheWithCurrentScans() async func getBackgroundAgentMetadata() async -> DBPBackgroundAgentMetadata? } final class DBPUIViewModel { private let dataManager: DataBrokerProtectionDataManaging - private let scheduler: DataBrokerProtectionScheduler + private let agentInterface: DataBrokerProtectionAgentInterface private let privacyConfig: PrivacyConfigurationManaging? private let prefs: ContentScopeProperties? @@ -40,13 +39,13 @@ final class DBPUIViewModel { private let pixelHandler: EventMapping = DataBrokerProtectionPixelsHandler() init(dataManager: DataBrokerProtectionDataManaging, - scheduler: DataBrokerProtectionScheduler, + agentInterface: DataBrokerProtectionAgentInterface, webUISettings: DataBrokerProtectionWebUIURLSettingsRepresentable, privacyConfig: PrivacyConfigurationManaging? = nil, prefs: ContentScopeProperties? = nil, webView: WKWebView? = nil) { self.dataManager = dataManager - self.scheduler = scheduler + self.agentInterface = agentInterface self.webUISettings = webUISettings self.privacyConfig = privacyConfig self.prefs = prefs @@ -74,9 +73,8 @@ final class DBPUIViewModel { } extension DBPUIViewModel: DBPUIScanOps { - func startScan(startDate: Date) -> Bool { - scheduler.startManualScan(startTime: startDate) - return true + func profileSaved() { + agentInterface.profileSaved() } func updateCacheWithCurrentScans() async { @@ -89,10 +87,6 @@ extension DBPUIViewModel: DBPUIScanOps { } func getBackgroundAgentMetadata() async -> DBPBackgroundAgentMetadata? { - return await withCheckedContinuation { continuation in - scheduler.getDebugMetadata { metadata in - continuation.resume(returning: metadata) - } - } + return await agentInterface.getDebugMetadata() } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift deleted file mode 100644 index 41e02edaca..0000000000 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionNoOpScheduler.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// DataBrokerProtectionNoOpScheduler.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 - -/// Convenience class for SwiftUI previews. -/// -/// Do not use this for any production code. -/// -final class DataBrokerProtectionNoOpScheduler: DataBrokerProtectionScheduler { - - private(set) public var status: DataBrokerProtectionSchedulerStatus = .idle - - private var internalStatusPublisher: Published = .init(initialValue: .idle) - - public var statusPublisher: Published.Publisher { - internalStatusPublisher.projectedValue - } - - func startScheduler(showWebView: Bool) { } - func stopScheduler() { } - func optOutAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { } - func runQueuedOperations(showWebView: Bool, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { } - func startManualScan(showWebView: Bool, startTime: Date, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { } - func runAllOperations(showWebView: Bool) { } - func getDebugMetadata(completion: (DBPBackgroundAgentMetadata?) -> Void) { } -} diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift index b8cf875adf..5cc6c42ea0 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionProcessor.swift @@ -51,7 +51,7 @@ final class DataBrokerProtectionProcessor { // MARK: - Public functions func startManualScans(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { + completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)? = nil) { operationQueue.cancelAllOperations() runOperations(operationType: .manualScan, @@ -69,7 +69,7 @@ final class DataBrokerProtectionProcessor { } func runAllOptOutOperations(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { + completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)? = nil) { operationQueue.cancelAllOperations() runOperations(operationType: .optOut, priorityDate: nil, @@ -80,7 +80,7 @@ final class DataBrokerProtectionProcessor { } func runQueuedOperations(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil ) { + completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)? = nil ) { runOperations(operationType: .all, priorityDate: Date(), showWebView: showWebView) { errors in @@ -90,7 +90,7 @@ final class DataBrokerProtectionProcessor { } func runAllOperations(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil ) { + completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)? = nil ) { runOperations(operationType: .all, priorityDate: nil, showWebView: showWebView) { errors in @@ -107,7 +107,7 @@ final class DataBrokerProtectionProcessor { private func runOperations(operationType: OperationType, priorityDate: Date?, showWebView: Bool, - completion: @escaping ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)) { + completion: @escaping ((DataBrokerProtectionAgentErrorCollection?) -> Void)) { self.operationQueue.maxConcurrentOperationCount = config.concurrentOperationsFor(operationType) // Before running new operations we check if there is any updates to the broker files. @@ -144,14 +144,14 @@ final class DataBrokerProtectionProcessor { } catch { os_log("DataBrokerProtectionProcessor error: runOperations, error: %{public}@", log: .error, error.localizedDescription) operationQueue.addBarrierBlock { - completion(DataBrokerProtectionSchedulerErrorCollection(oneTimeError: error)) + completion(DataBrokerProtectionAgentErrorCollection(oneTimeError: error)) } return } operationQueue.addBarrierBlock { let operationErrors = operations.compactMap { $0.error } - let errorCollection = operationErrors.count != 0 ? DataBrokerProtectionSchedulerErrorCollection(operationErrors: operationErrors) : nil + let errorCollection = operationErrors.count != 0 ? DataBrokerProtectionAgentErrorCollection(operationErrors: operationErrors) : nil completion(errorCollection) } } diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift index fd0b66bbdc..d9ac509201 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionScheduler.swift @@ -27,83 +27,7 @@ public enum DataBrokerProtectionSchedulerStatus: Codable { case running } -public enum DataBrokerProtectionSchedulerError: Error { - case loginItemDoesNotHaveNecessaryPermissions - case appInWrongDirectory - case operationsInterrupted -} - -@objc -public class DataBrokerProtectionSchedulerErrorCollection: NSObject, NSSecureCoding { - /* - This needs to be an NSObject (rather than a struct) so it can be represented in Objective C - and confrom to NSSecureCoding for the IPC layer. - */ - - private enum NSSecureCodingKeys { - static let oneTimeError = "oneTimeError" - static let operationErrors = "operationErrors" - } - - public let oneTimeError: Error? - public let operationErrors: [Error]? - - public init(oneTimeError: Error? = nil, operationErrors: [Error]? = nil) { - self.oneTimeError = oneTimeError - self.operationErrors = operationErrors - super.init() - } - - // MARK: - NSSecureCoding - - public static var supportsSecureCoding: Bool { - return true - } - - public func encode(with coder: NSCoder) { - coder.encode(oneTimeError, forKey: NSSecureCodingKeys.oneTimeError) - coder.encode(operationErrors, forKey: NSSecureCodingKeys.operationErrors) - } - - public required init?(coder: NSCoder) { - oneTimeError = coder.decodeObject(of: NSError.self, forKey: NSSecureCodingKeys.oneTimeError) - operationErrors = coder.decodeArrayOfObjects(ofClass: NSError.self, forKey: NSSecureCodingKeys.operationErrors) - } -} - -public protocol DataBrokerProtectionScheduler { - - var status: DataBrokerProtectionSchedulerStatus { get } - var statusPublisher: Published.Publisher { get } - - func startScheduler(showWebView: Bool) - func stopScheduler() - - func optOutAllBrokers(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) - func startManualScan(showWebView: Bool, startTime: Date, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) - func runQueuedOperations(showWebView: Bool, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) - func runAllOperations(showWebView: Bool) - - /// Debug operations - - func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) -} - -extension DataBrokerProtectionScheduler { - public func startScheduler() { - startScheduler(showWebView: false) - } - - public func runAllOperations() { - runAllOperations(showWebView: false) - } - - public func startManualScan(startTime: Date) { - startManualScan(showWebView: false, startTime: startTime, completion: nil) - } -} - -public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionScheduler { +public final class DefaultDataBrokerProtectionScheduler { private enum SchedulerCycle { // Arbitrary numbers for now @@ -140,7 +64,7 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch public var statusPublisher: Published.Publisher { $status } - private var lastSchedulerSessionStartTimestamp: Date? + public var lastSchedulerSessionStartTimestamp: Date? private lazy var dataBrokerProcessor: DataBrokerProtectionProcessor = { @@ -253,7 +177,7 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch } public func runQueuedOperations(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { + completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)? = nil) { guard self.currentOperation != .manualScan else { os_log("Manual scan in progress, returning...", log: .dataBrokerProtection) return @@ -281,7 +205,7 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch public func startManualScan(showWebView: Bool = false, startTime: Date, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)? = nil) { + completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)? = nil) { pixelHandler.fire(.initialScanPreStartDuration(duration: (Date().timeIntervalSince(startTime) * 1000).rounded(.towardZero))) let backgroundAgentManualScanStartTime = Date() stopScheduler() @@ -306,7 +230,7 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch if let errors = errors { if let oneTimeError = errors.oneTimeError { switch oneTimeError { - case DataBrokerProtectionSchedulerError.operationsInterrupted: + case DataBrokerProtectionAgentInterfaceError.operationsInterrupted: os_log("Interrupted during DefaultDataBrokerProtectionScheduler.startManualScan in dataBrokerProcessor.runAllScanOperations(), error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) default: os_log("Error during DefaultDataBrokerProtectionScheduler.startManualScan in dataBrokerProcessor.runAllScanOperations(), error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) @@ -336,7 +260,7 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch } public func optOutAllBrokers(showWebView: Bool = false, - completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { + completion: ((DataBrokerProtectionAgentErrorCollection?) -> Void)?) { guard self.currentOperation != .manualScan else { os_log("Manual scan in progress, returning...", log: .dataBrokerProtection) @@ -361,23 +285,9 @@ public final class DefaultDataBrokerProtectionScheduler: DataBrokerProtectionSch completion?(errors) }) } - - public func getDebugMetadata(completion: (DBPBackgroundAgentMetadata?) -> Void) { - if let backgroundAgentVersion = Bundle.main.releaseVersionNumber, let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String { - completion(DBPBackgroundAgentMetadata(backgroundAgentVersion: backgroundAgentVersion + " (build: \(buildNumber))", - isAgentRunning: status == .running, - agentSchedulerState: status.toString, - lastSchedulerSessionStartTimestamp: lastSchedulerSessionStartTimestamp?.timeIntervalSince1970)) - } else { - completion(DBPBackgroundAgentMetadata(backgroundAgentVersion: "ERROR: Error fetching background agent version", - isAgentRunning: status == .running, - agentSchedulerState: status.toString, - lastSchedulerSessionStartTimestamp: lastSchedulerSessionStartTimestamp?.timeIntervalSince1970)) - } - } } -extension DataBrokerProtectionSchedulerStatus { +public extension DataBrokerProtectionSchedulerStatus { var toString: String { switch self { case .idle: diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift index 4f26b33b8e..9a240074b3 100644 --- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift +++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/UI/DataBrokerProtectionViewController.swift @@ -26,7 +26,6 @@ import Combine final public class DataBrokerProtectionViewController: NSViewController { private let dataManager: DataBrokerProtectionDataManaging - private let scheduler: DataBrokerProtectionScheduler private var webView: WKWebView? private var loader: NSProgressIndicator! private let webUISettings: DataBrokerProtectionWebUIURLSettingsRepresentable @@ -37,20 +36,19 @@ final public class DataBrokerProtectionViewController: NSViewController { private let openURLHandler: (URL?) -> Void private var reloadObserver: NSObjectProtocol? - public init(scheduler: DataBrokerProtectionScheduler, + public init(agentInterface: DataBrokerProtectionAgentInterface, dataManager: DataBrokerProtectionDataManaging, privacyConfig: PrivacyConfigurationManaging? = nil, prefs: ContentScopeProperties? = nil, webUISettings: DataBrokerProtectionWebUIURLSettingsRepresentable, openURLHandler: @escaping (URL?) -> Void) { - self.scheduler = scheduler self.dataManager = dataManager self.openURLHandler = openURLHandler self.webUISettings = webUISettings self.pixelHandler = DataBrokerProtectionPixelsHandler() self.webUIPixel = DataBrokerProtectionWebUIPixels(pixelHandler: pixelHandler) self.webUIViewModel = DBPUIViewModel(dataManager: dataManager, - scheduler: scheduler, + agentInterface: agentInterface, webUISettings: webUISettings, privacyConfig: privacyConfig, prefs: prefs,