-
Notifications
You must be signed in to change notification settings - Fork 14
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
Conversation
DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionDebugUtilities.swift
Show resolved
Hide resolved
@@ -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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
case sysexInstallationCancelled | ||
|
||
/// The user was asked for login / pwd or touchID and cancelled | ||
/// | ||
case sysexInstallationRequiresAuthorization |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. 😅
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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.
@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) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
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.
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.
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
Make sure uninstallation works well, and that you see these pixels.
Test Cancel Case
Uninstallation will be cancelled and you should see these pixels:
Test Failure Case
Uninstallation will fail and you should see these pixels:
Internal references:
Pull Request Review Checklist
Software Engineering Expectations
Technical Design Template
Pull Request Documentation