]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
macOS: Better handling of tunnels created by another user
authorRoopesh Chander <roop@roopc.net>
Wed, 3 Apr 2019 11:02:12 +0000 (16:32 +0530)
committerRoopesh Chander <roop@roopc.net>
Wed, 3 Apr 2019 13:34:12 +0000 (19:04 +0530)
Previously, the tunnels just got deleted.

Signed-off-by: Roopesh Chander <roop@roopc.net>
WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift
WireGuard/WireGuard.xcodeproj/project.pbxproj
WireGuard/WireGuard/Base.lproj/Localizable.strings
WireGuard/WireGuard/Tunnel/TunnelsManager.swift
WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift
WireGuard/WireGuard/UI/macOS/ViewController/UnusableTunnelDetailViewController.swift [new file with mode: 0644]

index e3da61a1e2aed2242cf7b7a3dfa3ac2196e9c581..856df1f3ae611e3657fedc591ba18c925856c341 100644 (file)
@@ -49,9 +49,9 @@ extension NETunnelProviderProtocol {
         Keychain.deleteReference(called: ref)
     }
 
-    func verifyConfigurationReference() -> Data? {
-        guard let ref = passwordReference else { return nil }
-        return Keychain.verifyReference(called: ref) ? ref : nil
+    func verifyConfigurationReference() -> Bool {
+        guard let ref = passwordReference else { return false }
+        return Keychain.verifyReference(called: ref)
     }
 
     @discardableResult
index 9ae6f0ff59436592d097b5ed6d76afcff3b71cf5..a7ceac9b6fd2029e387534f0c8ad422b457fdd14 100644 (file)
@@ -93,6 +93,7 @@
                6F919EDB218C65C50023B400 /* wireguard_doc_logo_64x64.png in Resources */ = {isa = PBXBuildFile; fileRef = 6F919ED7218C65C50023B400 /* wireguard_doc_logo_64x64.png */; };
                6F919EDC218C65C50023B400 /* wireguard_doc_logo_320x320.png in Resources */ = {isa = PBXBuildFile; fileRef = 6F919ED8218C65C50023B400 /* wireguard_doc_logo_320x320.png */; };
                6F9B8A8E223398610041B9C4 /* SSIDOptionDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F9B8A8D223398610041B9C4 /* SSIDOptionDetailTableViewController.swift */; };
+               6FADE96C2254B8C300B838A4 /* UnusableTunnelDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FADE96A2254A6C200B838A4 /* UnusableTunnelDetailViewController.swift */; };
                6FB1017921C57DE600766195 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; };
                6FB17946222FD5960018AE71 /* OnDemandWiFiControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB17945222FD5960018AE71 /* OnDemandWiFiControls.swift */; };
                6FB1BD6021D2607A00A991BF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1BD5F21D2607A00A991BF /* AppDelegate.swift */; };
                6F919ED7218C65C50023B400 /* wireguard_doc_logo_64x64.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = wireguard_doc_logo_64x64.png; sourceTree = "<group>"; };
                6F919ED8218C65C50023B400 /* wireguard_doc_logo_320x320.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = wireguard_doc_logo_320x320.png; sourceTree = "<group>"; };
                6F9B8A8D223398610041B9C4 /* SSIDOptionDetailTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSIDOptionDetailTableViewController.swift; sourceTree = "<group>"; };
+               6FADE96A2254A6C200B838A4 /* UnusableTunnelDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnusableTunnelDetailViewController.swift; sourceTree = "<group>"; };
                6FB1017821C57DE600766195 /* MockTunnels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTunnels.swift; sourceTree = "<group>"; };
                6FB17945222FD5960018AE71 /* OnDemandWiFiControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnDemandWiFiControls.swift; sourceTree = "<group>"; };
                6FB1BD5D21D2607A00A991BF /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; };
                                6FCD99A821E0E0C700BA4C82 /* ButtonedDetailViewController.swift */,
                                6FCD99B021E0EDA900BA4C82 /* TunnelEditViewController.swift */,
                                6FDB6D12224A15BE00EE4BC3 /* LogViewController.swift */,
+                               6FADE96A2254A6C200B838A4 /* UnusableTunnelDetailViewController.swift */,
                        );
                        path = ViewController;
                        sourceTree = "<group>";
                                5F52D0BF21E3788900283CEA /* NSColor+Hex.swift in Sources */,
                                6FB1BDBE21D50F0200A991BF /* Logger.swift in Sources */,
                                6FB1BDBF21D50F0200A991BF /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
+                               6FADE96C2254B8C300B838A4 /* UnusableTunnelDetailViewController.swift in Sources */,
                                6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */,
                                6FB1BDC021D50F0200A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
                                6FBA101821D656000051C35F /* StatusMenu.swift in Sources */,
index c4e9cb158ed6cbb090dcf37216927897927d7a8b..5e9b6d521e3eb7aa233608d36db3dd218778347d 100644 (file)
 "macLogColumnTitleLogMessage" = "Log message";
 "macLogButtonTitleClose" = "Close";
 "macLogButtonTitleSave" = "Save…";
+
+// Mac unusable tunnel view
+
+"macUnusableTunnelMessage" = "The configuration for this tunnel cannot be found in the keychain.";
+"macUnusableTunnelInfo" = "In case this tunnel was created by another user, only that user can view, edit, or activate this tunnel.";
+"macUnusableTunnelButtonTitleDeleteTunnel" = "Delete tunnel";
index 8f4c87cec3f44d65f85f7ada423a555c4dace7dd..3b976f4c40072b04ef7681cb637251989252b522 100644 (file)
@@ -47,11 +47,18 @@ class TunnelsManager {
             var tunnelManagers = managers ?? []
             var refs: Set<Data> = []
             for (index, tunnelManager) in tunnelManagers.enumerated().reversed() {
-                let proto = tunnelManager.protocolConfiguration as? NETunnelProviderProtocol
-                if proto?.migrateConfigurationIfNeeded(called: tunnelManager.localizedDescription ?? "unknown") ?? false {
+                guard let proto = tunnelManager.protocolConfiguration as? NETunnelProviderProtocol else { continue }
+                if proto.migrateConfigurationIfNeeded(called: tunnelManager.localizedDescription ?? "unknown") {
                     tunnelManager.saveToPreferences { _ in }
                 }
-                if let ref = proto?.verifyConfigurationReference() {
+                #if os(iOS)
+                let passwordRef = proto.verifyConfigurationReference() ? proto.passwordReference : nil
+                #elseif os(macOS)
+                let passwordRef = proto.passwordReference // To handle multiple users in macOS, we skip verifying
+                #else
+                #error("Unimplemented")
+                #endif
+                if let ref = passwordRef {
                     refs.insert(ref)
                 } else {
                     tunnelManager.removeFromPreferences { _ in }
@@ -455,6 +462,10 @@ class TunnelContainer: NSObject {
         return tunnelProvider.tunnelConfiguration
     }
 
+    var isTunnelConfigurationAvailableInKeychain: Bool {
+        return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.verifyConfigurationReference() ?? false
+    }
+
     var onDemandOption: ActivateOnDemandOption {
         return ActivateOnDemandOption(from: tunnelProvider)
     }
index 18b8fcb71c6929ee5b883291a250b560cf5c9ce5..de41963e2a0abaff59a083bc4d2e496534f2eed9 100644 (file)
@@ -81,9 +81,23 @@ extension ManageTunnelsRootViewController: TunnelsListTableViewControllerDelegat
         assert(!tunnelIndices.isEmpty)
         if tunnelIndices.count == 1 {
             let tunnel = tunnelsManager.tunnel(at: tunnelIndices.first!)
-            let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
-            setTunnelDetailContentVC(tunnelDetailVC)
-            self.tunnelDetailVC = tunnelDetailVC
+            if tunnel.isTunnelConfigurationAvailableInKeychain {
+                let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
+                setTunnelDetailContentVC(tunnelDetailVC)
+                self.tunnelDetailVC = tunnelDetailVC
+            } else {
+                let unusableTunnelDetailVC: UnusableTunnelDetailViewController
+                if let unusableTunnelContentVC = tunnelDetailContentVC as? UnusableTunnelDetailViewController {
+                    unusableTunnelDetailVC = unusableTunnelContentVC
+                } else {
+                    unusableTunnelDetailVC = UnusableTunnelDetailViewController()
+                }
+                unusableTunnelDetailVC.onButtonClicked = { [weak tunnelsListVC] in
+                    tunnelsListVC?.handleRemoveTunnelAction()
+                }
+                setTunnelDetailContentVC(unusableTunnelDetailVC)
+                self.tunnelDetailVC = nil
+            }
         } else if tunnelIndices.count > 1 {
             let multiSelectionVC: ButtonedDetailViewController
             if let buttonedDetailVC = tunnelDetailContentVC as? ButtonedDetailViewController {
diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/UnusableTunnelDetailViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/UnusableTunnelDetailViewController.swift
new file mode 100644 (file)
index 0000000..612e8c1
--- /dev/null
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
+
+import Cocoa
+
+class UnusableTunnelDetailViewController: NSViewController {
+
+    var onButtonClicked: (() -> Void)?
+
+    let messageLabel: NSTextField = {
+        let text = tr("macUnusableTunnelMessage")
+        let boldFont = NSFont.boldSystemFont(ofSize: NSFont.systemFontSize)
+        let boldText = NSAttributedString(string: text, attributes: [.font: boldFont])
+        let label = NSTextField(labelWithAttributedString: boldText)
+        return label
+    }()
+
+    let infoLabel: NSTextField = {
+        let label = NSTextField(wrappingLabelWithString: tr("macUnusableTunnelInfo"))
+        return label
+    }()
+
+    let button: NSButton = {
+        let button = NSButton()
+        button.title = tr("macUnusableTunnelButtonTitleDeleteTunnel")
+        button.setButtonType(.momentaryPushIn)
+        button.bezelStyle = .rounded
+        return button
+    }()
+
+    init() {
+        super.init(nibName: nil, bundle: nil)
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    override func loadView() {
+
+        button.target = self
+        button.action = #selector(buttonClicked)
+
+        let margin: CGFloat = 20
+        let internalSpacing: CGFloat = 20
+        let buttonSpacing: CGFloat = 30
+        let stackView = NSStackView(views: [messageLabel, infoLabel, button])
+        stackView.orientation = .vertical
+        stackView.edgeInsets = NSEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
+        stackView.spacing = internalSpacing
+        stackView.setCustomSpacing(buttonSpacing, after: infoLabel)
+
+        let view = NSView()
+        view.addSubview(stackView)
+        stackView.translatesAutoresizingMaskIntoConstraints = false
+
+        NSLayoutConstraint.activate([
+            stackView.widthAnchor.constraint(equalToConstant: 360),
+            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
+            stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
+            view.widthAnchor.constraint(greaterThanOrEqualToConstant: 420),
+            view.heightAnchor.constraint(greaterThanOrEqualToConstant: 240)
+        ])
+
+        self.view = view
+    }
+
+    @objc func buttonClicked() {
+        onButtonClicked?()
+    }
+}