diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 60da1bb74a..d8a87f3132 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -416,6 +416,9 @@ extension Pixel { case networkProtectionDNSUpdateCustom case networkProtectionDNSUpdateDefault + case networkProtectionVPNConfigurationRemoved + case networkProtectionVPNConfigurationRemovalFailed + // MARK: remote messaging pixels case remoteMessageShown @@ -1102,6 +1105,9 @@ extension Pixel.Event { case .networkProtectionDNSUpdateCustom: return "m_netp_ev_update_dns_custom" case .networkProtectionDNSUpdateDefault: return "m_netp_ev_update_dns_default" + case .networkProtectionVPNConfigurationRemoved: return "m_netp_vpn_configuration_removed" + case .networkProtectionVPNConfigurationRemovalFailed: return "m_netp_vpn_configuration_removal_failed" + // MARK: remote messaging pixels case .remoteMessageShown: return "m_remote_message_shown" diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index d33015d5df..ef4149ff99 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -512,8 +512,6 @@ import WebKit #if NETWORK_PROTECTION widgetRefreshModel.refreshVPNWidget() - stopTunnelAndShowThankYouMessagingIfNeeded() - if tunnelDefaults.showEntitlementAlert { presentExpiredEntitlementAlert() } @@ -521,6 +519,7 @@ import WebKit presentExpiredEntitlementNotificationIfNeeded() Task { + await stopAndRemoveVPNIfNotAuthenticated() await refreshShortcuts() await vpnWorkaround.installRedditSessionWorkaround() } @@ -536,25 +535,14 @@ import WebKit importPasswordsStatusHandler.checkSyncSuccessStatus() } - private func stopTunnelAndShowThankYouMessagingIfNeeded() { - if accountManager.isUserAuthenticated { - return - } - - if AppDependencyProvider.shared.vpnFeatureVisibility.isPrivacyProLaunched() && !accountManager.isUserAuthenticated { - Task { - await self.stopAndRemoveVPN(with: "subscription-check") - } - } - } - - private func stopAndRemoveVPN(with reason: String) async { - guard await AppDependencyProvider.shared.networkProtectionTunnelController.isInstalled else { + private func stopAndRemoveVPNIfNotAuthenticated() async { + // Only remove the VPN if the user is not authenticated, and it's installed: + guard !accountManager.isUserAuthenticated, await AppDependencyProvider.shared.networkProtectionTunnelController.isInstalled else { return } await AppDependencyProvider.shared.networkProtectionTunnelController.stop() - await AppDependencyProvider.shared.networkProtectionTunnelController.removeVPN() + await AppDependencyProvider.shared.networkProtectionTunnelController.removeVPN(reason: .didBecomeActiveCheck) } func applicationWillResignActive(_ application: UIApplication) { diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 9b68900b42..5b2a294cdc 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -1503,7 +1503,7 @@ class MainViewController: UIViewController { } await networkProtectionTunnelController.stop() - await networkProtectionTunnelController.removeVPN() + await networkProtectionTunnelController.removeVPN(reason: .entitlementCheck) } } @@ -1511,7 +1511,7 @@ class MainViewController: UIViewController { private func onNetworkProtectionAccountSignOut(_ notification: Notification) { Task { await networkProtectionTunnelController.stop() - await networkProtectionTunnelController.removeVPN() + await networkProtectionTunnelController.removeVPN(reason: .signedOut) } } #endif diff --git a/DuckDuckGo/NetworkProtectionDebugViewController.swift b/DuckDuckGo/NetworkProtectionDebugViewController.swift index 472402a443..c37fa4c53a 100644 --- a/DuckDuckGo/NetworkProtectionDebugViewController.swift +++ b/DuckDuckGo/NetworkProtectionDebugViewController.swift @@ -700,7 +700,7 @@ shouldShowVPNShortcut: \(vpnVisibility.shouldShowVPNShortcut() ? "YES" : "NO") private func deleteVPNConfiguration() { Task { await AppDependencyProvider.shared.networkProtectionTunnelController.stop() - await AppDependencyProvider.shared.networkProtectionTunnelController.removeVPN() + await AppDependencyProvider.shared.networkProtectionTunnelController.removeVPN(reason: .debugMenu) } } } diff --git a/DuckDuckGo/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtectionTunnelController.swift index 80ee7defa2..02f5953de7 100644 --- a/DuckDuckGo/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtectionTunnelController.swift @@ -26,6 +26,13 @@ import NetworkExtension import NetworkProtection import Subscription +enum VPNConfigurationRemovalReason: String { + case didBecomeActiveCheck + case entitlementCheck + case signedOut + case debugMenu +} + final class NetworkProtectionTunnelController: TunnelController { static var shouldSimulateFailure: Bool = false @@ -114,8 +121,18 @@ final class NetworkProtectionTunnelController: TunnelController { tunnelManager.connection.stopVPNTunnel() } - func removeVPN() async { - try? await tunnelManager?.removeFromPreferences() + func removeVPN(reason: VPNConfigurationRemovalReason) async { + do { + try await tunnelManager?.removeFromPreferences() + + DailyPixel.fireDailyAndCount(pixel: .networkProtectionVPNConfigurationRemoved, withAdditionalParameters: [ + PixelParameters.reason: reason.rawValue + ]) + } catch { + DailyPixel.fireDailyAndCount(pixel: .networkProtectionVPNConfigurationRemovalFailed, error: error, withAdditionalParameters: [ + PixelParameters.reason: reason.rawValue + ]) + } } // MARK: - Connection Status Querying