Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add controller VPN uninstall pixels #2781

Merged
merged 8 commits into from
May 16, 2024

Conversation

diegoreymendez
Copy link
Contributor

@diegoreymendez diegoreymendez commented May 15, 2024

Task/Issue URL: https://app.asana.com/0/1206580121312550/1207324076451291/f

iOS PR: duckduckgo/iOS#2857
BSK PR: duckduckgo/BrowserServicesKit#822

Description

Adds VPN uninstall pixels to the controller.

Testing

Test Success Case

  1. Install the VPN
  2. Uninstall the VPN

Make sure uninstallation works well, and that you see these pixels.

👾[Standard-Fired] m_mac_vpn_controller_uninstall_attempt ["pixelSource": "vpnAgent", "appVersion": "1.88.0"]
👾[Daily and Count-Fired] m_mac_vpn_controller_uninstall_success_d ["pixelSource": "vpnAgent", "appVersion": "1.88.0"]
👾[Daily and Count-Fired] m_mac_vpn_controller_uninstall_success_c ["appVersion": "1.88.0", "pixelSource": "vpnAgent"]

Test Cancel Case

  1. Install the VPN
  2. Uninstall the VPN
  3. When the dialog comes up asking touch ID permission or admin pwd, cancel.

Uninstallation will be cancelled and you should see these pixels:

👾[Standard-Fired] m_mac_vpn_controller_uninstall_attempt ["pixelSource": "vpnAgent", "appVersion": "1.88.0"]
👾[Daily and Count-Fired] m_mac_vpn_controller_uninstall_cancelled_d ["pixelSource": "vpnAgent", "appVersion": "1.88.0", "reason": "sysexInstallationRequiresAuthorization"]
👾[Daily and Count-Fired] m_mac_vpn_controller_uninstall_cancelled_c ["reason": "sysexInstallationRequiresAuthorization", "appVersion": "1.88.0", "pixelSource": "vpnAgent"]

Test Failure Case

  1. Throw an error in this line
  2. Install the VPN
  3. Uninstall the VPN

Uninstallation will fail and you should see these pixels:

👾[Standard-Fired] m_mac_vpn_controller_uninstall_attempt ["appVersion": "1.88.0", "pixelSource": "vpnAgent"]
👾[Daily and Count-Fired] m_mac_vpn_controller_uninstall_failure_d ["d": "Testing", "pixelSource": "vpnAgent", "e": "1", "appVersion": "1.88.0"]
👾[Daily and Count-Fired] m_mac_vpn_controller_uninstall_failure_c ["d": "Testing", "pixelSource": "vpnAgent", "e": "1", "appVersion": "1.88.0"]

Internal references:

Pull Request Review Checklist
Software Engineering Expectations
Technical Design Template
Pull Request Documentation

@diegoreymendez diegoreymendez self-assigned this May 15, 2024
@diegoreymendez diegoreymendez marked this pull request as ready for review May 15, 2024 11:51
@diegoreymendez diegoreymendez marked this pull request as draft May 15, 2024 11:51
@@ -262,7 +263,7 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate {
locationFormatter: DefaultVPNLocationFormatter(),
uninstallHandler: { [weak self] in
guard let self else { return }
await self.vpnUninstaller.uninstall(includingSystemExtension: true)
try? await self.vpnUninstaller.uninstall(includingSystemExtension: true)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@quanganhdo - You'll probably want to connect this to the UI, if you haven't already.

}
try await uninstaller.removeVPNConfiguration()
case .uninstallVPN:
try await uninstaller.uninstall(includingSystemExtension: true)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tidying things up so that we can have a single uninstall call instead of calling IPC twice from the client for removing the extension and the VPN configuration.

@diegoreymendez diegoreymendez requested a review from samsymons May 15, 2024 15:40
@diegoreymendez diegoreymendez marked this pull request as ready for review May 15, 2024 15:40
Comment on lines +38 to +42
case sysexInstallationCancelled

/// The user was asked for login / pwd or touchID and cancelled
///
case sysexInstallationRequiresAuthorization
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm keeping this separation because it exists in macOS. Not sure what cancelled is precisely, but I"m accounting for it anyway since it's purpose is quite clear.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this could be the user cancelling the system dialog that's presented to them during installation. If it's not that, I have no clue. 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly that, I'm just confused as to what the other one is.

throw UninstallError.vpnConfigurationError(error)
}
do {
try await ipcClient.command(.uninstallVPN)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reduced the two IPC calls we had to a single one. I'm avoiding retries because it was causing some weird issues in edge cases, but IMHO it should be fine... we have pixels to see if there are issues.

do {
try await ipcClient.command(.removeSystemExtension)
} catch {
throw UninstallError.systemExtensionError(error)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is no longer called individually in the uninstall call, I'm throwing the error here.

do {
try await ipcClient.command(.removeVPNConfiguration)
} catch {
throw UninstallError.vpnConfigurationError(error)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is no longer called individually in the uninstall call, I'm throwing the error here.

@@ -43,6 +43,8 @@ final class DuckDuckGoVPNApplication: NSApplication {
}

super.init()

setupPixelKit()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to move this setup to happen earlier as otherwise the lazy initializers in the delegate would just fail to fire pixels for some reason.

In any case this should always happen as soon as possible.

Comment on lines +65 to +98
@MainActor
private func setupPixelKit() {
let dryRun: Bool

#if DEBUG
dryRun = true
#else
dryRun = false
#endif

let pixelSource: String

#if NETP_SYSTEM_EXTENSION
pixelSource = "vpnAgent"
#else
pixelSource = "vpnAgentAppStore"
#endif

PixelKit.setUp(dryRun: dryRun,
appVersion: AppVersion.shared.versionNumber,
source: pixelSource,
defaultHeaders: [:],
defaults: .netP) { (pixelName: String, headers: [String: String], parameters: [String: String], _, _, onComplete: @escaping PixelKit.CompletionBlock) in

let url = URL.pixelUrl(forPixelNamed: pixelName)
let apiHeaders = APIRequest.Headers(additionalHeaders: headers) // workaround - Pixel class should really handle APIRequest.Headers by itself
let configuration = APIRequest.Configuration(url: url, method: .get, queryParameters: parameters, headers: apiHeaders)
let request = APIRequest(configuration: configuration)

request.fetch { _, error in
onComplete(error == nil, error)
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just moved, no modifications.


do {
try await self.vpnUninstaller.uninstall(includingSystemExtension: true)
exit(EXIT_SUCCESS)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was previously done in the uninstall call, but when uninstall is called from IPC we don't want this to happen, and it's truly not inherent to calling uninstall. This should be the responsibility of the App delegate or an otherwise high-level manager.

try await networkExtensionController.deactivateSystemExtension()
defaults.networkProtectionOnboardingStatus = .isOnboarding(step: .userNeedsToAllowExtension)
} catch {
func uninstall(includingSystemExtension: Bool) async throws {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the gist of the changes. We're doing it all in one go with proper pixel attempt logic.

diegoreymendez added a commit to duckduckgo/BrowserServicesKit that referenced this pull request May 16, 2024
Task/Issue URL: https://app.asana.com/0/1206580121312550/1207324076451291/f

iOS PR: duckduckgo/iOS#2857
macOS PR: duckduckgo/macos-browser#2781

What kind of version bump will this require?: Minor

## Description

Integrating the latest macOS changes in BSK.  Nothing should change for iOS except for a crash being fixed.
@diegoreymendez diegoreymendez merged commit 7c85aa0 into main May 16, 2024
19 checks passed
@diegoreymendez diegoreymendez deleted the diego/add-uninstall-pixels-for-menu-app branch May 16, 2024 10:58
diegoreymendez added a commit to duckduckgo/iOS that referenced this pull request May 16, 2024
Task/Issue URL: https://app.asana.com/0/1206580121312550/1207324076451291/f

macOS PR: duckduckgo/macos-browser#2781
BSK PR: duckduckgo/BrowserServicesKit#822

## Description

Integrating the latest macOS changes in BSK.  Nothing should change for iOS except for a crash being fixed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants