macOS: Better handling of tunnels created by another user
Previously, the tunnels just got deleted. Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
parent
0299c3929e
commit
9690365dd4
|
@ -49,9 +49,9 @@ extension NETunnelProviderProtocol {
|
||||||
Keychain.deleteReference(called: ref)
|
Keychain.deleteReference(called: ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyConfigurationReference() -> Data? {
|
func verifyConfigurationReference() -> Bool {
|
||||||
guard let ref = passwordReference else { return nil }
|
guard let ref = passwordReference else { return false }
|
||||||
return Keychain.verifyReference(called: ref) ? ref : nil
|
return Keychain.verifyReference(called: ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
|
|
|
@ -93,6 +93,7 @@
|
||||||
6F919EDB218C65C50023B400 /* wireguard_doc_logo_64x64.png in Resources */ = {isa = PBXBuildFile; fileRef = 6F919ED7218C65C50023B400 /* wireguard_doc_logo_64x64.png */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
6FB1017921C57DE600766195 /* MockTunnels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1017821C57DE600766195 /* MockTunnels.swift */; };
|
||||||
6FB17946222FD5960018AE71 /* OnDemandWiFiControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB17945222FD5960018AE71 /* OnDemandWiFiControls.swift */; };
|
6FB17946222FD5960018AE71 /* OnDemandWiFiControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB17945222FD5960018AE71 /* OnDemandWiFiControls.swift */; };
|
||||||
6FB1BD6021D2607A00A991BF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB1BD5F21D2607A00A991BF /* AppDelegate.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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; };
|
6FB1BD5D21D2607A00A991BF /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -646,6 +648,7 @@
|
||||||
6FCD99A821E0E0C700BA4C82 /* ButtonedDetailViewController.swift */,
|
6FCD99A821E0E0C700BA4C82 /* ButtonedDetailViewController.swift */,
|
||||||
6FCD99B021E0EDA900BA4C82 /* TunnelEditViewController.swift */,
|
6FCD99B021E0EDA900BA4C82 /* TunnelEditViewController.swift */,
|
||||||
6FDB6D12224A15BE00EE4BC3 /* LogViewController.swift */,
|
6FDB6D12224A15BE00EE4BC3 /* LogViewController.swift */,
|
||||||
|
6FADE96A2254A6C200B838A4 /* UnusableTunnelDetailViewController.swift */,
|
||||||
);
|
);
|
||||||
path = ViewController;
|
path = ViewController;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1281,6 +1284,7 @@
|
||||||
5F52D0BF21E3788900283CEA /* NSColor+Hex.swift in Sources */,
|
5F52D0BF21E3788900283CEA /* NSColor+Hex.swift in Sources */,
|
||||||
6FB1BDBE21D50F0200A991BF /* Logger.swift in Sources */,
|
6FB1BDBE21D50F0200A991BF /* Logger.swift in Sources */,
|
||||||
6FB1BDBF21D50F0200A991BF /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
6FB1BDBF21D50F0200A991BF /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
|
||||||
|
6FADE96C2254B8C300B838A4 /* UnusableTunnelDetailViewController.swift in Sources */,
|
||||||
6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */,
|
6FFACD2021E4D8D500E9A2A5 /* ParseError+WireGuardAppError.swift in Sources */,
|
||||||
6FB1BDC021D50F0200A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
6FB1BDC021D50F0200A991BF /* NETunnelProviderProtocol+Extension.swift in Sources */,
|
||||||
6FBA101821D656000051C35F /* StatusMenu.swift in Sources */,
|
6FBA101821D656000051C35F /* StatusMenu.swift in Sources */,
|
||||||
|
|
|
@ -398,3 +398,9 @@
|
||||||
"macLogColumnTitleLogMessage" = "Log message";
|
"macLogColumnTitleLogMessage" = "Log message";
|
||||||
"macLogButtonTitleClose" = "Close";
|
"macLogButtonTitleClose" = "Close";
|
||||||
"macLogButtonTitleSave" = "Save…";
|
"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";
|
||||||
|
|
|
@ -47,11 +47,18 @@ class TunnelsManager {
|
||||||
var tunnelManagers = managers ?? []
|
var tunnelManagers = managers ?? []
|
||||||
var refs: Set<Data> = []
|
var refs: Set<Data> = []
|
||||||
for (index, tunnelManager) in tunnelManagers.enumerated().reversed() {
|
for (index, tunnelManager) in tunnelManagers.enumerated().reversed() {
|
||||||
let proto = tunnelManager.protocolConfiguration as? NETunnelProviderProtocol
|
guard let proto = tunnelManager.protocolConfiguration as? NETunnelProviderProtocol else { continue }
|
||||||
if proto?.migrateConfigurationIfNeeded(called: tunnelManager.localizedDescription ?? "unknown") ?? false {
|
if proto.migrateConfigurationIfNeeded(called: tunnelManager.localizedDescription ?? "unknown") {
|
||||||
tunnelManager.saveToPreferences { _ in }
|
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)
|
refs.insert(ref)
|
||||||
} else {
|
} else {
|
||||||
tunnelManager.removeFromPreferences { _ in }
|
tunnelManager.removeFromPreferences { _ in }
|
||||||
|
@ -455,6 +462,10 @@ class TunnelContainer: NSObject {
|
||||||
return tunnelProvider.tunnelConfiguration
|
return tunnelProvider.tunnelConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isTunnelConfigurationAvailableInKeychain: Bool {
|
||||||
|
return (tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol)?.verifyConfigurationReference() ?? false
|
||||||
|
}
|
||||||
|
|
||||||
var onDemandOption: ActivateOnDemandOption {
|
var onDemandOption: ActivateOnDemandOption {
|
||||||
return ActivateOnDemandOption(from: tunnelProvider)
|
return ActivateOnDemandOption(from: tunnelProvider)
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,9 +81,23 @@ extension ManageTunnelsRootViewController: TunnelsListTableViewControllerDelegat
|
||||||
assert(!tunnelIndices.isEmpty)
|
assert(!tunnelIndices.isEmpty)
|
||||||
if tunnelIndices.count == 1 {
|
if tunnelIndices.count == 1 {
|
||||||
let tunnel = tunnelsManager.tunnel(at: tunnelIndices.first!)
|
let tunnel = tunnelsManager.tunnel(at: tunnelIndices.first!)
|
||||||
let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
|
if tunnel.isTunnelConfigurationAvailableInKeychain {
|
||||||
setTunnelDetailContentVC(tunnelDetailVC)
|
let tunnelDetailVC = TunnelDetailTableViewController(tunnelsManager: tunnelsManager, tunnel: tunnel)
|
||||||
self.tunnelDetailVC = tunnelDetailVC
|
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 {
|
} else if tunnelIndices.count > 1 {
|
||||||
let multiSelectionVC: ButtonedDetailViewController
|
let multiSelectionVC: ButtonedDetailViewController
|
||||||
if let buttonedDetailVC = tunnelDetailContentVC as? ButtonedDetailViewController {
|
if let buttonedDetailVC = tunnelDetailContentVC as? ButtonedDetailViewController {
|
||||||
|
|
|
@ -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?()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue