aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopesh Chander <roop@roopc.net>2019-04-03 16:32:12 +0530
committerRoopesh Chander <roop@roopc.net>2019-04-03 19:04:12 +0530
commit9690365dd430000059780d8b40a82783ccffe1d3 (patch)
treed2e2c6b023357800305b2676e8cb87843e1294ed
parentiOS: Log view: Make log text selectable (diff)
downloadwireguard-apple-9690365dd430000059780d8b40a82783ccffe1d3.tar.xz
wireguard-apple-9690365dd430000059780d8b40a82783ccffe1d3.zip
macOS: Better handling of tunnels created by another user
Previously, the tunnels just got deleted. Signed-off-by: Roopesh Chander <roop@roopc.net>
-rw-r--r--WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift6
-rw-r--r--WireGuard/WireGuard.xcodeproj/project.pbxproj4
-rw-r--r--WireGuard/WireGuard/Base.lproj/Localizable.strings6
-rw-r--r--WireGuard/WireGuard/Tunnel/TunnelsManager.swift17
-rw-r--r--WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift20
-rw-r--r--WireGuard/WireGuard/UI/macOS/ViewController/UnusableTunnelDetailViewController.swift71
6 files changed, 115 insertions, 9 deletions
diff --git a/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift b/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift
index e3da61a..856df1f 100644
--- a/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift
+++ b/WireGuard/Shared/Model/NETunnelProviderProtocol+Extension.swift
@@ -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
diff --git a/WireGuard/WireGuard.xcodeproj/project.pbxproj b/WireGuard/WireGuard.xcodeproj/project.pbxproj
index 9ae6f0f..a7ceac9 100644
--- a/WireGuard/WireGuard.xcodeproj/project.pbxproj
+++ b/WireGuard/WireGuard.xcodeproj/project.pbxproj
@@ -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 */; };
@@ -342,6 +343,7 @@
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; };
@@ -646,6 +648,7 @@
6FCD99A821E0E0C700BA4C82 /* ButtonedDetailViewController.swift */,
6FCD99B021E0EDA900BA4C82 /* TunnelEditViewController.swift */,
6FDB6D12224A15BE00EE4BC3 /* LogViewController.swift */,
+ 6FADE96A2254A6C200B838A4 /* UnusableTunnelDetailViewController.swift */,
);
path = ViewController;
sourceTree = "<group>";
@@ -1281,6 +1284,7 @@
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 */,
diff --git a/WireGuard/WireGuard/Base.lproj/Localizable.strings b/WireGuard/WireGuard/Base.lproj/Localizable.strings
index c4e9cb1..5e9b6d5 100644
--- a/WireGuard/WireGuard/Base.lproj/Localizable.strings
+++ b/WireGuard/WireGuard/Base.lproj/Localizable.strings
@@ -398,3 +398,9 @@
"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";
diff --git a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
index 8f4c87c..3b976f4 100644
--- a/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
+++ b/WireGuard/WireGuard/Tunnel/TunnelsManager.swift
@@ -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)
}
diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift
index 18b8fcb..de41963 100644
--- a/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift
+++ b/WireGuard/WireGuard/UI/macOS/ViewController/ManageTunnelsRootViewController.swift
@@ -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
index 0000000..612e8c1
--- /dev/null
+++ b/WireGuard/WireGuard/UI/macOS/ViewController/UnusableTunnelDetailViewController.swift
@@ -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?()
+ }
+}