Skip to content

Commit

Permalink
Add Environment setting to the Debug menu (#1788)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1199230911884351/1204544375475063/f

**Description**:

**Steps to test this PR**:
1. Go to Debug > Network Protection > Environment 
2. Choose either Production or Staging
3. Go to Debug > Network Protection > Preferred Server. The server list
should update accordingly
4. Pick any server. You should connect to that particular server under
the selected environment

Co-authored-by: Diego Rey Mendez <[email protected]>
  • Loading branch information
quanganhdo and diegoreymendez authored Nov 9, 2023
1 parent 1f4bccb commit 8deabfa
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 63 deletions.
2 changes: 1 addition & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14399,7 +14399,7 @@
repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 82.2.3;
version = 82.3.0;
};
};
AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/BrowserServicesKit",
"state" : {
"revision" : "f2936a65ef7685fe9c39d6a996c8391cdb3d95ff",
"version" : "82.2.3"
"revision" : "c4d5f6df0340f0a5c109dcded9801ab676de7db5",
"version" : "82.3.0"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ import Common
extension NetworkProtectionDeviceManager {

static func create() -> NetworkProtectionDeviceManager {
let settings = TunnelSettings(defaults: .shared)
let networkClient = NetworkProtectionBackendClient(environment: settings.selectedEnvironment)
let keyStore = NetworkProtectionKeychainKeyStore()
let tokenStore = NetworkProtectionKeychainTokenStore()
return NetworkProtectionDeviceManager(tokenStore: tokenStore, keyStore: keyStore, errorEvents: .networkProtectionAppDebugEvents)
return NetworkProtectionDeviceManager(networkClient: networkClient, tokenStore: tokenStore, keyStore: keyStore, errorEvents: .networkProtectionAppDebugEvents)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import SwiftUI
@MainActor
final class NetworkProtectionDebugMenu: NSMenu {

private let environmentMenu = NSMenu()

private let preferredServerMenu: NSMenu
private let preferredServerAutomaticItem = NSMenuItem(title: "Automatic", action: #selector(NetworkProtectionDebugMenu.setSelectedServer))

Expand Down Expand Up @@ -87,6 +89,9 @@ final class NetworkProtectionDebugMenu: NSMenu {
NSMenuItem(title: "Onboarding")
.submenu(NetworkProtectionOnboardingMenu())

NSMenuItem(title: "Environment")
.submenu(environmentMenu)

NSMenuItem(title: "Preferred Server").submenu(preferredServerMenu)

NSMenuItem(title: "Registration Key") {
Expand Down Expand Up @@ -148,6 +153,7 @@ final class NetworkProtectionDebugMenu: NSMenu {
}

preferredServerMenu.autoenablesItems = false
populateNetworkProtectionEnvironmentListMenuItems()
populateNetworkProtectionServerListMenuItems()
populateNetworkProtectionRegistrationKeyValidityMenuItems()

Expand Down Expand Up @@ -293,6 +299,13 @@ final class NetworkProtectionDebugMenu: NSMenu {

// MARK: Populating Menu Items

private func populateNetworkProtectionEnvironmentListMenuItems() {
environmentMenu.items = [
NSMenuItem(title: "Production", action: #selector(setSelectedEnvironment(_:)), target: self, keyEquivalent: ""),
NSMenuItem(title: "Staging", action: #selector(setSelectedEnvironment(_:)), target: self, keyEquivalent: ""),
]
}

private func populateNetworkProtectionServerListMenuItems() {
let networkProtectionServerStore = NetworkProtectionServerListFileSystemStore(errorEvents: nil)
let servers = (try? networkProtectionServerStore.storedNetworkProtectionServerList()) ?? []
Expand Down Expand Up @@ -381,12 +394,26 @@ final class NetworkProtectionDebugMenu: NSMenu {
// MARK: - Menu State Update

override func update() {
updateEnvironmentMenu()
updatePreferredServerMenu()
updateRekeyValidityMenu()
updateNetworkProtectionMenuItemsState()
updateNetworkProtectionItems()
}

private func updateEnvironmentMenu() {
let selectedEnvironment = settings.selectedEnvironment

switch selectedEnvironment {
case .production:
environmentMenu.items.first?.state = .on
environmentMenu.items.last?.state = .off
case .staging:
environmentMenu.items.first?.state = .off
environmentMenu.items.last?.state = .on
}
}

private func updatePreferredServerMenu() {
let selectedServer = settings.selectedServer

Expand Down Expand Up @@ -533,6 +560,28 @@ final class NetworkProtectionDebugMenu: NSMenu {
return ""
}
}

// MARK: Environment
@objc func setSelectedEnvironment(_ menuItem: NSMenuItem) {
let title = menuItem.title
let selectedEnvironment: TunnelSettings.SelectedEnvironment

if title == "Staging" {
selectedEnvironment = .staging
} else {
selectedEnvironment = .production
}

settings.selectedEnvironment = selectedEnvironment

Task {
_ = try await NetworkProtectionDeviceManager.create().refreshServerList()
await MainActor.run {
populateNetworkProtectionServerListMenuItems()
}
settings.selectedServer = .automatic
}
}
}

extension NetworkProtectionDebugMenu: NSMenuDelegate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ final class NetworkProtectionDebugUtilities {
}

func removeSystemExtensionAndAgents() async throws {
await networkProtectionFeatureDisabler.resetAllStateForVPNApp(uninstallSystemExtension: true)
await networkProtectionFeatureDisabler.removeSystemExtension()
networkProtectionFeatureDisabler.disableLoginItems()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ final class NetworkProtectionTunnelController: NetworkProtection.TunnelControlle
case .setExcludeLocalNetworks(let excludeLocalNetworks):
try await handleSetExcludeLocalNetworks(excludeLocalNetworks)
case .setRegistrationKeyValidity,
.setSelectedServer:
.setSelectedServer,
.setSelectedEnvironment:
// Intentional no-op as this is handled by the extension
break
}
Expand Down Expand Up @@ -385,6 +386,7 @@ final class NetworkProtectionTunnelController: NetworkProtection.TunnelControlle

options[NetworkProtectionOptionKey.activationAttemptId] = UUID().uuidString as NSString
options[NetworkProtectionOptionKey.authToken] = try tokenStore.fetchToken() as NSString?
options[NetworkProtectionOptionKey.selectedEnvironment] = settings.selectedEnvironment.rawValue as? NSString
options[NetworkProtectionOptionKey.selectedServer] = settings.selectedServer.stringValue as? NSString

if case .custom(let keyValidity) = settings.registrationKeyValidity {
Expand Down
39 changes: 22 additions & 17 deletions DuckDuckGo/Waitlist/NetworkProtectionFeatureDisabler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,26 @@ final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling
///
func disable(keepAuthToken: Bool, uninstallSystemExtension: Bool) {
Task {
// To disable NetP we need the login item to be running
// This should be fine though as we'll disable them further down below
enableLoginItems()

// Allow some time for the login items to fully launch
try? await Task.sleep(interval: 0.5)

unpinNetworkProtection()

if uninstallSystemExtension {
await resetAllStateForVPNApp(uninstallSystemExtension: uninstallSystemExtension)
await removeSystemExtension()
}

disableLoginItems()

await resetNetworkExtensionState()
await removeVPNConfiguration()

// ☝️ Take care of resetting all state within the extension first, and wait half a second
// We want to give some time for the login item to reset state before disabling it
try? await Task.sleep(interval: 0.5)
// 👇 And only afterwards turn off the tunnel and remove it from preferences

await stopTunnel()
disableLoginItems()

resetUserDefaults()

if !keepAuthToken {
Expand All @@ -84,12 +89,16 @@ final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling
}
}

private func enableLoginItems() {
loginItemsManager.enableLoginItems(LoginItemsManager.networkProtectionLoginItems, log: log)
}

func disableLoginItems() {
loginItemsManager.disableLoginItems(LoginItemsManager.networkProtectionLoginItems)
}

func resetAllStateForVPNApp(uninstallSystemExtension: Bool) async {
await ipcClient.resetAll(uninstallSystemExtension: uninstallSystemExtension)
func removeSystemExtension() async {
await ipcClient.debugCommand(.removeSystemExtension)

#if NETP_SYSTEM_EXTENSION
userDefaults.networkProtectionOnboardingStatusRawValue = OnboardingStatus.default.rawValue
Expand All @@ -104,15 +113,11 @@ final class NetworkProtectionFeatureDisabler: NetworkProtectionFeatureDisabling
try NetworkProtectionKeychainTokenStore().deleteToken()
}

private func resetNetworkExtensionState() async {
if let activeSession = try? await ConnectionSessionUtilities.activeSession() {
try? activeSession.sendProviderMessage(.resetAllState) {
os_log("Status was reset in the extension", log: self.log)
}
}
}
private func removeVPNConfiguration() async {
// Remove the agent VPN configuration
await ipcClient.debugCommand(.removeVPNConfiguration)

private func stopTunnel() async {
// Remove the legacy (local) configuration
let tunnels = try? await NETunnelProviderManager.loadAllFromPreferences()

if let tunnels = tunnels {
Expand Down
21 changes: 18 additions & 3 deletions DuckDuckGoVPN/TunnelControllerIPCService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,25 @@ extension TunnelControllerIPCService: IPCServerInterface {
}

func debugCommand(_ command: DebugCommand) async {
guard let activeSession = try? await ConnectionSessionUtilities.activeSession(networkExtensionBundleID: Bundle.main.networkExtensionBundleID) else {
return
if let activeSession = try? await ConnectionSessionUtilities.activeSession(networkExtensionBundleID: Bundle.main.networkExtensionBundleID) {

// First give a chance to the extension to process the command, since some commands
// may remove the VPN configuration or deactivate the extension.
try? await activeSession.sendProviderRequest(.debugCommand(command))
}

try? await activeSession.sendProviderRequest(.debugCommand(command))
switch command {
case .removeSystemExtension:
await VPNConfigurationManager().removeVPNConfiguration()
try? await networkExtensionController.deactivateSystemExtension()
case .expireRegistrationKey:
// Intentional no-op: handled by the extension
break
case .sendTestNotification:
// Intentional no-op: handled by the extension
break
case .removeVPNConfiguration:
await VPNConfigurationManager().removeVPNConfiguration()
}
}
}
2 changes: 1 addition & 1 deletion LocalPackages/Account/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let package = Package(
targets: ["Account"]),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.2.3"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.3.0"),
.package(path: "../Purchase")
],
targets: [
Expand Down
2 changes: 1 addition & 1 deletion LocalPackages/DataBrokerProtection/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ let package = Package(
targets: ["DataBrokerProtection"])
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.2.3"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.3.0"),
.package(path: "../PixelKit"),
.package(path: "../SwiftUIExtensions"),
.package(path: "../XPCHelper")
Expand Down
2 changes: 1 addition & 1 deletion LocalPackages/NetworkProtectionMac/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ let package = Package(
.library(name: "NetworkProtectionUI", targets: ["NetworkProtectionUI"])
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.2.3"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "82.3.0"),
.package(path: "../XPCHelper"),
.package(path: "../SwiftUIExtensions")
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,30 +95,22 @@ extension TunnelControllerIPCClient: IPCServerInterface {
})
}

public func resetAll(uninstallSystemExtension: Bool) async {
xpc.execute(call: { server in
Task {
await server.resetAll(uninstallSystemExtension: uninstallSystemExtension)
}
}, xpcReplyErrorHandler: { _ in
// Intentional no-op as there's no completion block
// If you add a completion block, please remember to call it here too!
})
}

public func debugCommand(_ command: DebugCommand) async {
guard let payload = try? JSONEncoder().encode(command) else {
return
}

xpc.execute(call: { server in
Task {
await server.debugCommand(payload)
}
}, xpcReplyErrorHandler: { _ in
// Intentional no-op as there's no completion block
// If you add a completion block, please remember to call it here too!
})
await withCheckedContinuation { continuation in
xpc.execute(call: { server in
server.debugCommand(payload) {
continuation.resume()
}
}, xpcReplyErrorHandler: { _ in
// Intentional no-op as there's no completion block
// If you add a completion block, please remember to call it here too!
continuation.resume()
})
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ public protocol IPCServerInterface: AnyObject {
///
func stop()

/// Resets all of Network Protection's state that's handled by the server
///
func resetAll(uninstallSystemExtension: Bool) async

/// Debug commands
///
func debugCommand(_ command: DebugCommand) async
Expand All @@ -67,13 +63,9 @@ protocol XPCServerInterface {
///
func stop()

/// Resets all of Network Protection's state that's handled by the server
///
func resetAll(uninstallSystemExtension: Bool) async

/// Debug commands
///
func debugCommand(_ payload: Data) async
func debugCommand(_ payload: Data, completion: @escaping () -> Void)
}

public final class TunnelControllerIPCServer {
Expand Down Expand Up @@ -156,15 +148,15 @@ extension TunnelControllerIPCServer: XPCServerInterface {
serverDelegate?.stop()
}

func resetAll(uninstallSystemExtension: Bool) async {
await serverDelegate?.resetAll(uninstallSystemExtension: uninstallSystemExtension)
}

func debugCommand(_ payload: Data) async {
func debugCommand(_ payload: Data, completion: @escaping () -> Void) {
guard let command = try? JSONDecoder().decode(DebugCommand.self, from: payload) else {
completion()
return
}

await serverDelegate?.debugCommand(command)
Task {
await serverDelegate?.debugCommand(command)
completion()
}
}
}

0 comments on commit 8deabfa

Please sign in to comment.