From 9098cd1161be1c6e7175fdf48128faed6a4438f5 Mon Sep 17 00:00:00 2001 From: Eric Kuck Date: Fri, 21 Dec 2018 21:59:43 -0600 Subject: Removing a tunnel from iOS's settings is now immediately reflected in app Signed-off-by: Eric Kuck --- WireGuard/WireGuard/Tunnel/TunnelsManager.swift | 76 ++++++++++++---------- WireGuard/WireGuard/UI/iOS/AppDelegate.swift | 7 +- .../WireGuard/UI/iOS/View/TunnelListCell.swift | 2 +- .../UI/iOS/ViewController/MainViewController.swift | 26 +++++++- .../TunnelDetailTableViewController.swift | 9 +-- 5 files changed, 72 insertions(+), 48 deletions(-) (limited to 'WireGuard/WireGuard') diff --git a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift index c25d4b6..8d8cec9 100644 --- a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift +++ b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift @@ -52,6 +52,28 @@ class TunnelsManager { } #endif } + + func reload(completionHandler: @escaping (Bool) -> Void) { + #if targetEnvironment(simulator) + completionHandler(.success(false)) + #else + NETunnelProviderManager.loadAllFromPreferences { managers, _ in + guard let managers = managers else { + completionHandler(false) + return + } + + let newTunnels = managers.map { TunnelContainer(tunnel: $0) }.sorted { $0.name < $1.name } + let hasChanges = self.tunnels.map { $0.name } != newTunnels.map { $0.name } + if hasChanges { + self.tunnels = newTunnels + completionHandler(true) + } else { + completionHandler(false) + } + } + #endif + } func add(tunnelConfiguration: TunnelConfiguration, activateOnDemandSetting: ActivateOnDemandSetting = ActivateOnDemandSetting.defaultSetting, completionHandler: @escaping (WireGuardResult) -> Void) { let tunnelName = tunnelConfiguration.name ?? "" @@ -255,8 +277,6 @@ class TunnelsManager { } private func startObservingTunnelStatuses() { - guard statusObservationToken == nil else { return } - statusObservationToken = NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: OperationQueue.main) { [weak self] statusChangeNotification in guard let self = self, let session = statusChangeNotification.object as? NETunnelProviderSession, @@ -265,14 +285,13 @@ class TunnelsManager { wg_log(.debug, message: "Tunnel '\(tunnel.name)' connection status changed to '\(tunnel.tunnelProvider.connection.status)'") - // Track what happened to our attempt to start the tunnel if tunnel.isAttemptingActivation { if session.status == .connected { tunnel.isAttemptingActivation = false self.activationDelegate?.tunnelActivationSucceeded(tunnel: tunnel) } else if session.status == .disconnected { tunnel.isAttemptingActivation = false - if let (title, message) = self.lastErrorTextFromNetworkExtension(for: tunnel) { + if let (title, message) = lastErrorTextFromNetworkExtension(for: tunnel) { self.activationDelegate?.tunnelActivationFailed(tunnel: tunnel, error: .activationFailedWithExtensionError(title: title, message: message, wasOnDemandEnabled: tunnelProvider.isOnDemandEnabled)) } else { self.activationDelegate?.tunnelActivationFailed(tunnel: tunnel, error: .activationFailed(wasOnDemandEnabled: tunnelProvider.isOnDemandEnabled)) @@ -280,9 +299,7 @@ class TunnelsManager { } } - // In case we're restarting the tunnel if (tunnel.status == .restarting) && (session.status == .disconnected || session.status == .disconnecting) { - // Don't change tunnel.status when disconnecting for a restart if session.status == .disconnected { tunnel.startActivation(activationDelegate: self.activationDelegate) } @@ -293,35 +310,28 @@ class TunnelsManager { } } - func lastErrorTextFromNetworkExtension(for tunnel: TunnelContainer) -> (title: String, message: String)? { - guard let lastErrorFileURL = FileManager.networkExtensionLastErrorFileURL else { return nil } - guard let lastErrorData = try? Data(contentsOf: lastErrorFileURL) else { return nil } - guard let lastErrorText = String(data: lastErrorData, encoding: .utf8) else { return nil } - let lastErrorStrings = lastErrorText.splitToArray(separator: "\n") - guard lastErrorStrings.count == 2 && tunnel.activationAttemptId == lastErrorStrings[0] else { return nil } - - switch PacketTunnelProviderError(rawValue: lastErrorStrings[1]) { - case .some(.savedProtocolConfigurationIsInvalid): - return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationSavedConfigFailureMessage")) - case .some(.dnsResolutionFailure): - return (tr("alertTunnelDNSFailureTitle"), tr("alertTunnelDNSFailureMessage")) - case .some(.couldNotStartBackend): - return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationBackendFailureMessage")) - case .some(.couldNotDetermineFileDescriptor): - return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationFileDescriptorFailureMessage")) - case .some(.couldNotSetNetworkSettings): - return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationSetNetworkSettingsMessage")) - default: - return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationFailureMessage")) - } - } +} - deinit { - if let statusObservationToken = statusObservationToken { - NotificationCenter.default.removeObserver(statusObservationToken) - } +private func lastErrorTextFromNetworkExtension(for tunnel: TunnelContainer) -> (title: String, message: String)? { + guard let lastErrorFileURL = FileManager.networkExtensionLastErrorFileURL else { return nil } + guard let lastErrorData = try? Data(contentsOf: lastErrorFileURL) else { return nil } + guard let lastErrorStrings = String(data: lastErrorData, encoding: .utf8)?.splitToArray(separator: "\n") else { return nil } + guard lastErrorStrings.count == 2 && tunnel.activationAttemptId == lastErrorStrings[0] else { return nil } + + switch PacketTunnelProviderError(rawValue: lastErrorStrings[1]) { + case .some(.savedProtocolConfigurationIsInvalid): + return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationSavedConfigFailureMessage")) + case .some(.dnsResolutionFailure): + return (tr("alertTunnelDNSFailureTitle"), tr("alertTunnelDNSFailureMessage")) + case .some(.couldNotStartBackend): + return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationBackendFailureMessage")) + case .some(.couldNotDetermineFileDescriptor): + return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationFileDescriptorFailureMessage")) + case .some(.couldNotSetNetworkSettings): + return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationSetNetworkSettingsMessage")) + default: + return (tr("alertTunnelActivationFailureTitle"), tr("alertTunnelActivationFailureMessage")) } - } class TunnelContainer: NSObject { diff --git a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift index 428f732..9c3aa9f 100644 --- a/WireGuard/WireGuard/UI/iOS/AppDelegate.swift +++ b/WireGuard/WireGuard/UI/iOS/AppDelegate.swift @@ -10,8 +10,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var mainVC: MainViewController? - func application(_ application: UIApplication, - willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Logger.configureGlobal(withFilePath: FileManager.appLogFileURL?.path) let window = UIWindow(frame: UIScreen.main.bounds) @@ -50,9 +49,7 @@ extension AppDelegate { return true } - func application(_ application: UIApplication, - viewControllerWithRestorationIdentifierPath identifierComponents: [String], - coder: NSCoder) -> UIViewController? { + func application(_ application: UIApplication, viewControllerWithRestorationIdentifierPath identifierComponents: [String], coder: NSCoder) -> UIViewController? { guard let vcIdentifier = identifierComponents.last else { return nil } if vcIdentifier.hasPrefix("TunnelDetailVC:") { let tunnelName = String(vcIdentifier.suffix(vcIdentifier.count - "TunnelDetailVC:".count)) diff --git a/WireGuard/WireGuard/UI/iOS/View/TunnelListCell.swift b/WireGuard/WireGuard/UI/iOS/View/TunnelListCell.swift index 294964a..7ab3965 100644 --- a/WireGuard/WireGuard/UI/iOS/View/TunnelListCell.swift +++ b/WireGuard/WireGuard/UI/iOS/View/TunnelListCell.swift @@ -72,7 +72,7 @@ class TunnelListCell: UITableViewCell { statusSwitch.addTarget(self, action: #selector(switchToggled), for: .valueChanged) } - + @objc func switchToggled() { onSwitchToggled?(statusSwitch.isOn) } diff --git a/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift b/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift index 1e480b9..2798127 100644 --- a/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift @@ -7,8 +7,8 @@ class MainViewController: UISplitViewController { var tunnelsManager: TunnelsManager? var onTunnelsManagerReady: ((TunnelsManager) -> Void)? - var tunnelsListVC: TunnelsListTableViewController? + private var foregroundObservationToken: AnyObject? init() { let detailVC = UIViewController() @@ -57,7 +57,31 @@ class MainViewController: UISplitViewController { self.onTunnelsManagerReady?(tunnelsManager) self.onTunnelsManagerReady = nil } + + foregroundObservationToken = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: OperationQueue.main) { [weak self] _ in + guard let self = self else { return } + self.tunnelsManager?.reload { [weak self] hasChanges in + guard let self = self, let tunnelsManager = self.tunnelsManager, hasChanges else { return } + + self.tunnelsListVC?.setTunnelsManager(tunnelsManager: tunnelsManager) + + if self.isCollapsed { + (self.viewControllers[0] as? UINavigationController)?.popViewController(animated: false) + } else { + let detailVC = UIViewController() + detailVC.view.backgroundColor = .white + let detailNC = UINavigationController(rootViewController: detailVC) + self.showDetailViewController(detailNC, sender: self) + } + + if let presentedNavController = self.presentedViewController as? UINavigationController, presentedNavController.viewControllers.first is TunnelEditTableViewController { + self.presentedViewController?.dismiss(animated: false, completion: nil) + } + } + + } } + } extension MainViewController: TunnelsManagerActivationDelegate { diff --git a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift index 187f7fd..2912e07 100644 --- a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift @@ -3,8 +3,6 @@ import UIKit -// MARK: TunnelDetailTableViewController - class TunnelDetailTableViewController: UITableViewController { private enum Section { @@ -44,11 +42,6 @@ class TunnelDetailTableViewController: UITableViewController { fatalError("init(coder:) has not been implemented") } - deinit { - onDemandStatusObservationToken = nil - statusObservationToken = nil - } - override func viewDidLoad() { super.viewDidLoad() title = tunnelViewModel.interfaceData[.name] @@ -250,7 +243,7 @@ extension TunnelDetailTableViewController { return } } - if self.splitViewController?.isCollapsed ?? true { + if self.splitViewController?.isCollapsed != false { self.navigationController?.navigationController?.popToRootViewController(animated: true) } else { let detailVC = UIViewController() -- cgit v1.2.3-59-g8ed1b