]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
Removing a tunnel from iOS's settings is now immediately reflected in app
authorEric Kuck <eric@bluelinelabs.com>
Sat, 22 Dec 2018 03:59:43 +0000 (21:59 -0600)
committerEric Kuck <eric@bluelinelabs.com>
Sat, 22 Dec 2018 03:59:43 +0000 (21:59 -0600)
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
WireGuard/WireGuard/Tunnel/TunnelsManager.swift
WireGuard/WireGuard/UI/iOS/AppDelegate.swift
WireGuard/WireGuard/UI/iOS/View/TunnelListCell.swift
WireGuard/WireGuard/UI/iOS/ViewController/MainViewController.swift
WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift
WireGuard/WireGuardNetworkExtension/PacketTunnelProvider.swift

index c25d4b6172865482675d061db9a4b37baf966bd1..8d8cec93069ec8956cfe4ff80dcbcc7c6f49053e 100644 (file)
@@ -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<TunnelContainer>) -> 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 {
index 428f73243247746ea7e63663b6f4d5b377d66f60..9c3aa9fdc4618226d313ad77938dd709bf6f0363 100644 (file)
@@ -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))
index 294964a68675024399103492cec53226888e62ea..7ab396508d52f7ecf36e617681c1b1fdbce773a1 100644 (file)
@@ -72,7 +72,7 @@ class TunnelListCell: UITableViewCell {
 
         statusSwitch.addTarget(self, action: #selector(switchToggled), for: .valueChanged)
     }
-
     @objc func switchToggled() {
         onSwitchToggled?(statusSwitch.isOn)
     }
index 1e480b96f025af4b516c88a99abcbaf826303ad8..27981272c766b3abd375b7e0ebb6481c9775717c 100644 (file)
@@ -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 {
index 187f7fd6417356138ffc85548a41894629b74071..2912e075c8edc8f95edc3f134a789ada72f7ebbf 100644 (file)
@@ -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()
index bc4b542a75ed2c06cbb191b4151890829aca59a4..fd6bb9b920284e3331ec3e264ab17a4fb7b14031 100644 (file)
@@ -13,10 +13,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
     private var lastFirstInterface: NWInterface?
     private var packetTunnelSettingsGenerator: PacketTunnelSettingsGenerator?
 
-    deinit {
-        networkMonitor?.cancel()
-    }
-
     override func startTunnel(options: [String: NSObject]?, completionHandler startTunnelCompletionHandler: @escaping (Error?) -> Void) {
         let activationAttemptId = options?["activationAttemptId"] as? String
         let errorNotifier = ErrorNotifier(activationAttemptId: activationAttemptId)