Skip to content

Commit

Permalink
Fire a pixel when removing the VPN configuration (#3014)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/414235014887631/1207698850203829/f
Tech Design URL:
CC:

Description:

This PR adds a pixel that reports when the VPN configuration has been removed, and why.
  • Loading branch information
samsymons authored Jul 1, 2024
1 parent 62131b2 commit 53a405f
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 22 deletions.
6 changes: 6 additions & 0 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ extension Pixel {
case networkProtectionDNSUpdateCustom
case networkProtectionDNSUpdateDefault

case networkProtectionVPNConfigurationRemoved
case networkProtectionVPNConfigurationRemovalFailed

// MARK: remote messaging pixels

case remoteMessageShown
Expand Down Expand Up @@ -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"
Expand Down
22 changes: 5 additions & 17 deletions DuckDuckGo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -512,15 +512,14 @@ import WebKit
#if NETWORK_PROTECTION
widgetRefreshModel.refreshVPNWidget()

stopTunnelAndShowThankYouMessagingIfNeeded()

if tunnelDefaults.showEntitlementAlert {
presentExpiredEntitlementAlert()
}

presentExpiredEntitlementNotificationIfNeeded()

Task {
await stopAndRemoveVPNIfNotAuthenticated()
await refreshShortcuts()
await vpnWorkaround.installRedditSessionWorkaround()
}
Expand All @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions DuckDuckGo/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1503,15 +1503,15 @@ class MainViewController: UIViewController {
}

await networkProtectionTunnelController.stop()
await networkProtectionTunnelController.removeVPN()
await networkProtectionTunnelController.removeVPN(reason: .entitlementCheck)
}
}

@objc
private func onNetworkProtectionAccountSignOut(_ notification: Notification) {
Task {
await networkProtectionTunnelController.stop()
await networkProtectionTunnelController.removeVPN()
await networkProtectionTunnelController.removeVPN(reason: .signedOut)
}
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/NetworkProtectionDebugViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down
21 changes: 19 additions & 2 deletions DuckDuckGo/NetworkProtectionTunnelController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 53a405f

Please sign in to comment.