diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index bec5d4c023..37b8fe137c 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1323,6 +1323,8 @@ 7B1E819E27C8874900FF0E60 /* ContentOverlayPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1E819B27C8874900FF0E60 /* ContentOverlayPopover.swift */; }; 7B1E819F27C8874900FF0E60 /* ContentOverlay.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7B1E819C27C8874900FF0E60 /* ContentOverlay.storyboard */; }; 7B1E81A027C8874900FF0E60 /* ContentOverlayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1E819D27C8874900FF0E60 /* ContentOverlayViewController.swift */; }; + 7B2DDD0B2A93EA570039D884 /* NetworkProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2DDD0A2A93EA570039D884 /* NetworkProtectionAppEvents.swift */; }; + 7B2DDD0D2A93EB630039D884 /* NetworkProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2DDD0A2A93EA570039D884 /* NetworkProtectionAppEvents.swift */; }; 7B2E52252A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2E52242A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift */; }; 7B430EA12A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */; }; 7B430EA22A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */; }; @@ -2586,6 +2588,7 @@ 7B1E819B27C8874900FF0E60 /* ContentOverlayPopover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentOverlayPopover.swift; sourceTree = ""; }; 7B1E819C27C8874900FF0E60 /* ContentOverlay.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ContentOverlay.storyboard; sourceTree = ""; }; 7B1E819D27C8874900FF0E60 /* ContentOverlayViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentOverlayViewController.swift; sourceTree = ""; }; + 7B2DDD0A2A93EA570039D884 /* NetworkProtectionAppEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionAppEvents.swift; sourceTree = ""; }; 7B2E52242A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionAgentNotificationsPresenter.swift; sourceTree = ""; }; 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionSimulateFailureMenu.swift; sourceTree = ""; }; 7B4CE8DA26F02108009134B1 /* UI Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UI Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -4004,6 +4007,7 @@ 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */, 4B4D606B2A0B29FA00BCD287 /* Invite */, 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */, + 7B2DDD0A2A93EA570039D884 /* NetworkProtectionAppEvents.swift */, ); path = BothAppTargets; sourceTree = ""; @@ -7585,6 +7589,7 @@ 3706FAD2293F65D500E42796 /* Atb.swift in Sources */, 3706FAD3293F65D500E42796 /* DownloadsViewController.swift in Sources */, 3706FAD4293F65D500E42796 /* DataExtension.swift in Sources */, + 7B2DDD0D2A93EB630039D884 /* NetworkProtectionAppEvents.swift in Sources */, 3706FAD6293F65D500E42796 /* ConfigurationStore.swift in Sources */, 3706FAD7293F65D500E42796 /* Feedback.swift in Sources */, 3707C722294B5D2900682A9F /* WKWebViewExtension.swift in Sources */, @@ -8604,6 +8609,7 @@ 4B9292A426670D2A00AD2C21 /* PasteboardWriting.swift in Sources */, 4B92928D26670D1700AD2C21 /* BookmarkOutlineViewCell.swift in Sources */, B604085C274B8FBA00680351 /* UnprotectedDomains.xcdatamodeld in Sources */, + 7B2DDD0B2A93EA570039D884 /* NetworkProtectionAppEvents.swift in Sources */, 4BB88B5025B7BA2B006F6B06 /* TabInstrumentation.swift in Sources */, 4B59024326B35F7C00489384 /* BrowserImportViewController.swift in Sources */, 4B9292D72667124000AD2C21 /* NSPopUpButtonExtension.swift in Sources */, diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index a0404bd723..c32ad6ad05 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -129,7 +129,7 @@ { "identity" : "trackerradarkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/TrackerRadarKit.git", + "location" : "https://github.com/duckduckgo/TrackerRadarKit", "state" : { "revision" : "4684440d03304e7638a2c8086895367e90987463", "version" : "1.2.1" diff --git a/DuckDuckGo/AppDelegate/AppDelegate.swift b/DuckDuckGo/AppDelegate/AppDelegate.swift index 6ae7e3f113..83db2e1b8f 100644 --- a/DuckDuckGo/AppDelegate/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate/AppDelegate.swift @@ -211,7 +211,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel UserDefaultsWrapper.clearRemovedKeys() #if NETWORK_PROTECTION - startupNetworkProtection() + if #available(macOS 11.4, *) { + NetworkProtectionAppEvents().applicationDidFinishLaunching() + } #endif } @@ -311,82 +313,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel } } - // MARK: - Network Protection - -#if NETWORK_PROTECTION - - private func startupNetworkProtection() { - guard #available(macOS 11.4, *) else { return } - - let loginItemsManager = NetworkProtectionLoginItemsManager() - let networkProtectionFeatureVisibility = NetworkProtectionKeychainTokenStore() - - guard networkProtectionFeatureVisibility.isFeatureActivated else { - loginItemsManager.disableLoginItems() - LocalPinningManager.shared.unpin(.networkProtection) - return - } - - restartNetworkProtectionIfVersionChanged(using: loginItemsManager) - refreshNetworkProtectionServers() - } - - @available(macOS 11.4, *) - private func restartNetworkProtectionIfVersionChanged(using loginItemsManager: NetworkProtectionLoginItemsManager) { - let currentVersion = AppVersion.shared.versionNumber - let versionStore = NetworkProtectionLastVersionRunStore() - defer { - versionStore.lastVersionRun = currentVersion - } - - // should‘ve been run at least once with NetP enabled - guard let lastVersionRun = versionStore.lastVersionRun else { - os_log(.info, log: .networkProtection, "No last version found for the NetP login items, skipping update") - return - } - - if lastVersionRun != currentVersion { - os_log(.info, log: .networkProtection, "App updated from %{public}s to %{public}s: updating login items", lastVersionRun, currentVersion) - restartNetworkProtectionTunnelAndMenu(using: loginItemsManager) - } else { - // If login items failed to launch (e.g. because of the App bundle rename), launch using NSWorkspace - loginItemsManager.ensureLoginItemsAreRunning(.ifLoginItemsAreEnabled, after: 1) - } - } - - @available(macOS 11.4, *) - private func restartNetworkProtectionTunnelAndMenu(using loginItemsManager: NetworkProtectionLoginItemsManager) { - loginItemsManager.restartLoginItems() - - Task { - let provider = NetworkProtectionTunnelController() - - // Restart NetP SysEx on app update - if await provider.isConnected { - await provider.stop() - await provider.start() - } - } - } - - /// Fetches a new list of Network Protection servers, and updates the existing set. - @available(macOS 11.4, *) - private func refreshNetworkProtectionServers() { - Task { - let serverCount: Int - do { - serverCount = try await NetworkProtectionDeviceManager.create().refreshServerList().count - } catch { - os_log("Failed to update Network Protection servers", log: .networkProtection, type: .error) - return - } - - os_log("Successfully updated Network Protection servers; total server count = %{public}d", log: .networkProtection, serverCount) - } - } - -#endif - private func subscribeToEmailProtectionStatusNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(emailDidSignInNotification(_:)), diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift new file mode 100644 index 0000000000..814bd00233 --- /dev/null +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionAppEvents.swift @@ -0,0 +1,99 @@ +// +// NetworkProtectionAppEvents.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 Common +import Foundation + +#if NETWORK_PROTECTION +import NetworkProtection + +/// Implements the sequence of steps that Network Protection needs to execute when the App starts up. +/// +@available(macOS 11.4, *) +final class NetworkProtectionAppEvents { + + /// Call this method when the app finishes launching, to run the startup logic for NetP. + /// + func applicationDidFinishLaunching() { + let loginItemsManager = NetworkProtectionLoginItemsManager() + let keychainStore = NetworkProtectionKeychainTokenStore() + + guard keychainStore.isFeatureActivated else { + loginItemsManager.disableLoginItems() + LocalPinningManager.shared.unpin(.networkProtection) + return + } + + restartNetworkProtectionIfVersionChanged(using: loginItemsManager) + refreshNetworkProtectionServers() + } + + private func restartNetworkProtectionIfVersionChanged(using loginItemsManager: NetworkProtectionLoginItemsManager) { + let currentVersion = AppVersion.shared.versionNumber + let versionStore = NetworkProtectionLastVersionRunStore() + defer { + versionStore.lastVersionRun = currentVersion + } + + // should‘ve been run at least once with NetP enabled + guard let lastVersionRun = versionStore.lastVersionRun else { + os_log(.info, log: .networkProtection, "No last version found for the NetP login items, skipping update") + return + } + + if lastVersionRun != currentVersion { + os_log(.info, log: .networkProtection, "App updated from %{public}s to %{public}s: updating login items", lastVersionRun, currentVersion) + restartNetworkProtectionTunnelAndMenu(using: loginItemsManager) + } else { + // If login items failed to launch (e.g. because of the App bundle rename), launch using NSWorkspace + loginItemsManager.ensureLoginItemsAreRunning(.ifLoginItemsAreEnabled, after: 1) + } + } + + private func restartNetworkProtectionTunnelAndMenu(using loginItemsManager: NetworkProtectionLoginItemsManager) { + loginItemsManager.restartLoginItems() + + Task { + let provider = NetworkProtectionTunnelController() + + // Restart NetP SysEx on app update + if await provider.isConnected { + await provider.stop() + await provider.start() + } + } + } + + /// Fetches a new list of Network Protection servers, and updates the existing set. + /// + private func refreshNetworkProtectionServers() { + Task { + let serverCount: Int + do { + serverCount = try await NetworkProtectionDeviceManager.create().refreshServerList().count + } catch { + os_log("Failed to update Network Protection servers", log: .networkProtection, type: .error) + return + } + + os_log("Successfully updated Network Protection servers; total server count = %{public}d", log: .networkProtection, serverCount) + } + } +} + +#endif