macOS: Exclude private IPs

This commit is contained in:
Roopesh Chander 2019-02-16 18:25:17 +05:30
parent 549f5de700
commit 226911715c
3 changed files with 61 additions and 0 deletions

View File

@ -547,6 +547,14 @@ class TunnelViewModel {
} }
} }
func asWgQuickConfig() -> String? {
let saveResult = save()
if case .saved(let tunnelConfiguration) = saveResult {
return tunnelConfiguration.asWgQuickConfig()
}
return nil
}
@discardableResult @discardableResult
func applyConfiguration(other: TunnelConfiguration) -> Changes { func applyConfiguration(other: TunnelConfiguration) -> Changes {
// Replaces current data with data from other TunnelConfiguration, ignoring any changes in peer ordering. // Replaces current data with data from other TunnelConfiguration, ignoring any changes in peer ordering.

View File

@ -9,6 +9,7 @@ class ConfTextView: NSTextView {
@objc dynamic var hasError: Bool = false @objc dynamic var hasError: Bool = false
@objc dynamic var privateKeyString: String? @objc dynamic var privateKeyString: String?
@objc dynamic var singlePeerAllowedIPs: [String]?
override var string: String { override var string: String {
didSet { didSet {
@ -52,6 +53,13 @@ class ConfTextView: NSTextView {
} }
} }
func setConfText(_ text: String) {
let fullTextRange = NSRange(location: 0, length: (string as NSString).length)
if shouldChangeText(in: fullTextRange, replacementString: text) {
replaceCharacters(in: fullTextRange, with: text)
didChangeText()
}
}
} }
extension ConfTextView: NSTextViewDelegate { extension ConfTextView: NSTextViewDelegate {
@ -64,6 +72,10 @@ extension ConfTextView: NSTextViewDelegate {
if privateKeyString != confTextStorage.privateKeyString { if privateKeyString != confTextStorage.privateKeyString {
privateKeyString = confTextStorage.privateKeyString privateKeyString = confTextStorage.privateKeyString
} }
let updatedSinglePeerAllowedIPs = confTextStorage.hasOnePeer && !confTextStorage.hasError ? confTextStorage.lastOnePeerAllowedIPs : nil
if singlePeerAllowedIPs != updatedSinglePeerAllowedIPs {
singlePeerAllowedIPs = updatedSinglePeerAllowedIPs
}
needsDisplay = true needsDisplay = true
} }

View File

@ -56,6 +56,14 @@ class TunnelEditViewController: NSViewController {
return scrollView return scrollView
}() }()
let excludePrivateIPsCheckbox: NSButton = {
let checkbox = NSButton()
checkbox.title = tr("tunnelPeerExcludePrivateIPs")
checkbox.setButtonType(.switch)
checkbox.state = .off
return checkbox
}()
let discardButton: NSButton = { let discardButton: NSButton = {
let button = NSButton() let button = NSButton()
button.title = tr("macEditDiscard") button.title = tr("macEditDiscard")
@ -86,6 +94,7 @@ class TunnelEditViewController: NSViewController {
var privateKeyObservationToken: AnyObject? var privateKeyObservationToken: AnyObject?
var hasErrorObservationToken: AnyObject? var hasErrorObservationToken: AnyObject?
var singlePeerAllowedIPsObservationToken: AnyObject?
init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer?) { init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer?) {
self.tunnelsManager = tunnelsManager self.tunnelsManager = tunnelsManager
@ -111,6 +120,8 @@ class TunnelEditViewController: NSViewController {
} else { } else {
selectedActivateOnDemandOption = .none selectedActivateOnDemandOption = .none
} }
let singlePeer = tunnelConfiguration.peers.count == 1 ? tunnelConfiguration.peers.first : nil
updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: singlePeer?.allowedIPs.map { $0.stringRepresentation })
} else { } else {
// Creating a new tunnel // Creating a new tunnel
let privateKey = Curve25519.generatePrivateKey() let privateKey = Curve25519.generatePrivateKey()
@ -133,6 +144,9 @@ class TunnelEditViewController: NSViewController {
hasErrorObservationToken = textView.observe(\.hasError) { [weak saveButton] textView, _ in hasErrorObservationToken = textView.observe(\.hasError) { [weak saveButton] textView, _ in
saveButton?.isEnabled = !textView.hasError saveButton?.isEnabled = !textView.hasError
} }
singlePeerAllowedIPsObservationToken = textView.observe(\.singlePeerAllowedIPs) { [weak self] textView, _ in
self?.updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: textView.singlePeerAllowedIPs)
}
onDemandRow.valueOptions = activateOnDemandOptions.map { TunnelViewModel.activateOnDemandOptionText(for: $0) } onDemandRow.valueOptions = activateOnDemandOptions.map { TunnelViewModel.activateOnDemandOptionText(for: $0) }
onDemandRow.selectedOptionIndex = activateOnDemandOptions.firstIndex(of: selectedActivateOnDemandOption)! onDemandRow.selectedOptionIndex = activateOnDemandOptions.firstIndex(of: selectedActivateOnDemandOption)!
@ -149,6 +163,9 @@ class TunnelEditViewController: NSViewController {
discardButton.target = self discardButton.target = self
discardButton.action = #selector(handleDiscardAction) discardButton.action = #selector(handleDiscardAction)
excludePrivateIPsCheckbox.target = self
excludePrivateIPsCheckbox.action = #selector(excludePrivateIPsCheckboxToggled(sender:))
let margin: CGFloat = 20 let margin: CGFloat = 20
let internalSpacing: CGFloat = 10 let internalSpacing: CGFloat = 10
@ -159,6 +176,7 @@ class TunnelEditViewController: NSViewController {
let buttonRowStackView = NSStackView() let buttonRowStackView = NSStackView()
buttonRowStackView.setViews([discardButton, saveButton], in: .trailing) buttonRowStackView.setViews([discardButton, saveButton], in: .trailing)
buttonRowStackView.addView(excludePrivateIPsCheckbox, in: .leading)
buttonRowStackView.orientation = .horizontal buttonRowStackView.orientation = .horizontal
buttonRowStackView.spacing = internalSpacing buttonRowStackView.spacing = internalSpacing
@ -237,4 +255,27 @@ class TunnelEditViewController: NSViewController {
delegate?.tunnelEditingCancelled() delegate?.tunnelEditingCancelled()
dismiss(self) dismiss(self)
} }
func updateExcludePrivateIPsVisibility(singlePeerAllowedIPs: [String]?) {
let shouldAllowExcludePrivateIPsControl: Bool
let excludePrivateIPsValue: Bool
if let singlePeerAllowedIPs = singlePeerAllowedIPs {
(shouldAllowExcludePrivateIPsControl, excludePrivateIPsValue) = TunnelViewModel.PeerData.excludePrivateIPsFieldStates(isSinglePeer: true, allowedIPs: Set<String>(singlePeerAllowedIPs))
} else {
(shouldAllowExcludePrivateIPsControl, excludePrivateIPsValue) = TunnelViewModel.PeerData.excludePrivateIPsFieldStates(isSinglePeer: false, allowedIPs: Set<String>())
}
excludePrivateIPsCheckbox.isHidden = !shouldAllowExcludePrivateIPsControl
excludePrivateIPsCheckbox.state = excludePrivateIPsValue ? .on : .off
}
@objc func excludePrivateIPsCheckboxToggled(sender: AnyObject?) {
guard let excludePrivateIPsCheckbox = sender as? NSButton else { return }
guard let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: textView.string, called: nameRow.value) else { return }
let isOn = excludePrivateIPsCheckbox.state == .on
let tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnelConfiguration)
tunnelViewModel.peersData.first?.excludePrivateIPsValueChanged(isOn: isOn, dnsServers: tunnelViewModel.interfaceData[.dns])
if let modifiedConfig = tunnelViewModel.asWgQuickConfig() {
textView.setConfText(modifiedConfig)
}
}
} }