Merge branch 'mac-configuration-layout'

This commit is contained in:
Davide De Rosa 2021-01-15 00:45:54 +01:00
commit 92804acb10
8 changed files with 444 additions and 650 deletions

View File

@ -21,6 +21,8 @@
0E1D72B4213C118500BA1586 /* ConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */; }; 0E1D72B4213C118500BA1586 /* ConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1D72B3213C118500BA1586 /* ConfigurationViewController.swift */; };
0E24273A225950450064A1A3 /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E24273C225950450064A1A3 /* About.storyboard */; }; 0E24273A225950450064A1A3 /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E24273C225950450064A1A3 /* About.storyboard */; };
0E242742225956AC0064A1A3 /* DonationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E242741225956AC0064A1A3 /* DonationViewController.swift */; }; 0E242742225956AC0064A1A3 /* DonationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E242741225956AC0064A1A3 /* DonationViewController.swift */; };
0E294AA125AE2B0A00CB4908 /* Descriptible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E294A8225AE29D100CB4908 /* Descriptible.swift */; };
0E294AA225AE2B0B00CB4908 /* Descriptible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E294A8225AE29D100CB4908 /* Descriptible.swift */; };
0E2AC24522EC3AC10037B4B0 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 0E2AC24422EC3AC10037B4B0 /* Settings.bundle */; }; 0E2AC24522EC3AC10037B4B0 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 0E2AC24422EC3AC10037B4B0 /* Settings.bundle */; };
0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B493F20FCFF990094784C /* Theme+Titles.swift */; }; 0E2B494020FCFF990094784C /* Theme+Titles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B493F20FCFF990094784C /* Theme+Titles.swift */; };
0E2EB063236D8E1E0079DB53 /* AppConstants+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2EB062236D8E1E0079DB53 /* AppConstants+App.swift */; }; 0E2EB063236D8E1E0079DB53 /* AppConstants+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2EB062236D8E1E0079DB53 /* AppConstants+App.swift */; };
@ -367,6 +369,7 @@
0E23B4A12298559800304C30 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; 0E23B4A12298559800304C30 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
0E24273B225950450064A1A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/About.storyboard; sourceTree = "<group>"; }; 0E24273B225950450064A1A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/About.storyboard; sourceTree = "<group>"; };
0E242741225956AC0064A1A3 /* DonationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DonationViewController.swift; sourceTree = "<group>"; }; 0E242741225956AC0064A1A3 /* DonationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DonationViewController.swift; sourceTree = "<group>"; };
0E294A8225AE29D100CB4908 /* Descriptible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Descriptible.swift; sourceTree = "<group>"; };
0E2AC24422EC3AC10037B4B0 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; }; 0E2AC24422EC3AC10037B4B0 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
0E2B493F20FCFF990094784C /* Theme+Titles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Titles.swift"; sourceTree = "<group>"; }; 0E2B493F20FCFF990094784C /* Theme+Titles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Titles.swift"; sourceTree = "<group>"; };
0E2B494120FD16540094784C /* TransientStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransientStore.swift; sourceTree = "<group>"; }; 0E2B494120FD16540094784C /* TransientStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransientStore.swift; sourceTree = "<group>"; };
@ -969,6 +972,7 @@
children = ( children = (
0E57F63A20C83FC5008323CF /* iOS */, 0E57F63A20C83FC5008323CF /* iOS */,
0E569F58259F41690022DFB8 /* macOS */, 0E569F58259F41690022DFB8 /* macOS */,
0E294A8225AE29D100CB4908 /* Descriptible.swift */,
); );
path = App; path = App;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1889,6 +1893,7 @@
0E520320259F58BF00CBAB56 /* AppDelegate.swift in Sources */, 0E520320259F58BF00CBAB56 /* AppDelegate.swift in Sources */,
0E520344259F58FE00CBAB56 /* TrustedNetworksAddViewController.swift in Sources */, 0E520344259F58FE00CBAB56 /* TrustedNetworksAddViewController.swift in Sources */,
0E52033A259F58F500CBAB56 /* AccountViewController.swift in Sources */, 0E52033A259F58F500CBAB56 /* AccountViewController.swift in Sources */,
0E294AA225AE2B0B00CB4908 /* Descriptible.swift in Sources */,
0E520356259F590600CBAB56 /* PreferencesGeneralViewController.swift in Sources */, 0E520356259F590600CBAB56 /* PreferencesGeneralViewController.swift in Sources */,
0E520348259F58FE00CBAB56 /* MTUViewController.swift in Sources */, 0E520348259F58FE00CBAB56 /* MTUViewController.swift in Sources */,
0E52037E259F593B00CBAB56 /* SwiftGen+Segues.swift in Sources */, 0E52037E259F593B00CBAB56 /* SwiftGen+Segues.swift in Sources */,
@ -1986,6 +1991,7 @@
0ECC60DE2256B68A0020BEAC /* SwiftGen+Assets.swift in Sources */, 0ECC60DE2256B68A0020BEAC /* SwiftGen+Assets.swift in Sources */,
0E242742225956AC0064A1A3 /* DonationViewController.swift in Sources */, 0E242742225956AC0064A1A3 /* DonationViewController.swift in Sources */,
0ED38AEC2141260D0004D387 /* ConfigurationModificationDelegate.swift in Sources */, 0ED38AEC2141260D0004D387 /* ConfigurationModificationDelegate.swift in Sources */,
0E294AA125AE2B0A00CB4908 /* Descriptible.swift in Sources */,
0E776642229D0DAE0023FA76 /* Intents.intentdefinition in Sources */, 0E776642229D0DAE0023FA76 /* Intents.intentdefinition in Sources */,
0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */, 0ECEE45020E1182E00A6BB43 /* Theme+Cells.swift in Sources */,
0E6268942369AD0600355F75 /* PurchaseTableViewCell.swift in Sources */, 0E6268942369AD0600355F75 /* PurchaseTableViewCell.swift in Sources */,

View File

@ -0,0 +1,131 @@
//
// Descriptible.swift
// Passepartout
//
// Created by Davide De Rosa on 1/12/21.
// Copyright (c) 2021 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import Foundation
import TunnelKit
public protocol UIDescriptible {
var uiDescription: String { get }
}
extension String: UIDescriptible {
public var uiDescription: String {
return description
}
}
extension OpenVPN.Cipher: UIDescriptible {
public var uiDescription: String {
return description
}
}
extension OpenVPN.Digest: UIDescriptible {
public var uiDescription: String {
return description
}
}
extension OpenVPN.CompressionFraming: UIDescriptible {
public var uiDescription: String {
let V = L10n.Core.Configuration.Cells.self
switch self {
case .disabled:
return L10n.Core.Global.Values.disabled
case .compLZO:
return V.CompressionFraming.Value.lzo
case .compress:
return V.CompressionFraming.Value.compress
}
}
}
extension OpenVPN.CompressionAlgorithm: UIDescriptible {
public var uiDescription: String {
let V = L10n.Core.Configuration.Cells.self
switch self {
case .disabled:
return L10n.Core.Global.Values.disabled
case .LZO:
return V.CompressionAlgorithm.Value.lzo
case .other:
return V.CompressionAlgorithm.Value.other
}
}
}
extension OpenVPN.ConfigurationBuilder {
public var uiDescriptionForTLSWrap: String {
let V = L10n.Core.Configuration.Cells.self
if let strategy = tlsWrap?.strategy {
switch strategy {
case .auth:
return V.TlsWrapping.Value.auth
case .crypt:
return V.TlsWrapping.Value.crypt
}
} else {
return L10n.Core.Global.Values.disabled
}
}
public var uiDescriptionForKeepAlive: String {
let V = L10n.Core.Configuration.Cells.self
if let keepAlive = keepAliveInterval, keepAlive > 0 {
return V.KeepAlive.Value.seconds(Int(keepAlive))
} else {
return L10n.Core.Global.Values.disabled
}
}
public var uiDescriptionForClientCertificate: String {
let V = L10n.Core.Configuration.Cells.Client.Value.self
return (clientCertificate != nil) ? V.enabled : V.disabled
}
public var uiDescriptionForEKU: String {
let V = L10n.Core.Global.Values.self
return (checksEKU ?? false) ? V.enabled : V.disabled
}
public var uiDescriptionForRenegotiatesAfter: String {
let V = L10n.Core.Configuration.Cells.self
if let reneg = renegotiatesAfter, reneg > 0 {
return V.RenegotiationSeconds.Value.after(TimeInterval(reneg).localized)
} else {
return L10n.Core.Global.Values.disabled
}
}
public var uiDescriptionForRandomizeEndpoint: String {
let V = L10n.Core.Global.Values.self
return (randomizeEndpoint ?? false) ? V.enabled : V.disabled
}
}

View File

@ -62,9 +62,6 @@ class ConfigurationViewController: UIViewController, StrongTableHost {
model.add(.reset) model.add(.reset)
model.setHeader("", forSection: .reset) model.setHeader("", forSection: .reset)
} }
if !isServerPushed {
model.add(.tls)
}
// headers // headers
model.setHeader(L10n.Core.Configuration.Sections.Communication.header, forSection: .communication) model.setHeader(L10n.Core.Configuration.Sections.Communication.header, forSection: .communication)
@ -105,6 +102,10 @@ class ConfigurationViewController: UIViewController, StrongTableHost {
model.set(rows, forSection: .compression) model.set(rows, forSection: .compression)
} }
if !isServerPushed {
model.add(.tls)
}
rows = [] rows = []
if let _ = configuration.keepAliveInterval { if let _ = configuration.keepAliveInterval {
rows.append(.keepAlive) rows.append(.keepAlive)
@ -122,6 +123,9 @@ class ConfigurationViewController: UIViewController, StrongTableHost {
} else { } else {
model.add(.communication) model.add(.communication)
model.add(.compression) model.add(.compression)
if !isServerPushed {
model.add(.tls)
}
model.add(.other) model.add(.other)
model.set([.cipher, .digest], forSection: .communication) model.set([.cipher, .digest], forSection: .communication)
model.set([.compressionFraming, .compressionAlgorithm], forSection: .compression) model.set([.compressionFraming, .compressionAlgorithm], forSection: .compression)
@ -261,82 +265,60 @@ extension ConfigurationViewController: UITableViewDataSource, UITableViewDelegat
} }
cell.isTappable = isEditable cell.isTappable = isEditable
switch row { switch row {
case .cipher:
cell.leftText = V.Cipher.caption
cell.rightText = configuration.fallbackCipher.description
case .digest:
cell.leftText = V.Digest.caption
cell.rightText = configuration.fallbackDigest.description
case .compressionFraming:
cell.leftText = V.CompressionFraming.caption
cell.rightText = configuration.fallbackCompressionFraming.cellDescription
case .compressionAlgorithm:
cell.leftText = V.CompressionAlgorithm.caption
if let compressionAlgorithm = configuration.compressionAlgorithm {
cell.rightText = compressionAlgorithm.cellDescription
} else {
cell.rightText = L10n.Core.Global.Values.disabled
}
cell.isTappable = (configuration.compressionFraming != .disabled)
case .resetOriginal: case .resetOriginal:
cell.leftText = V.ResetOriginal.caption cell.leftText = V.ResetOriginal.caption
cell.applyAction(.current) cell.applyAction(.current)
case .cipher:
cell.leftText = V.Cipher.caption
cell.rightText = configuration.fallbackCipher.uiDescription
case .digest:
cell.leftText = V.Digest.caption
cell.rightText = configuration.fallbackDigest.uiDescription
case .compressionFraming:
cell.leftText = V.CompressionFraming.caption
cell.rightText = configuration.fallbackCompressionFraming.uiDescription
case .compressionAlgorithm:
cell.leftText = V.CompressionAlgorithm.caption
cell.rightText = configuration.fallbackCompressionAlgorithm.uiDescription
cell.isTappable = (configuration.compressionFraming != .disabled)
case .client: case .client:
cell.leftText = V.Client.caption cell.leftText = V.Client.caption
cell.rightText = (configuration.clientCertificate != nil) ? V.Client.Value.enabled : V.Client.Value.disabled cell.rightText = configuration.uiDescriptionForClientCertificate
cell.accessoryType = .none cell.accessoryType = .none
cell.isTappable = false cell.isTappable = false
case .tlsWrapping: case .tlsWrapping:
cell.leftText = V.TlsWrapping.caption cell.leftText = V.TlsWrapping.caption
if let strategy = configuration.tlsWrap?.strategy { cell.rightText = configuration.uiDescriptionForTLSWrap
switch strategy {
case .auth:
cell.rightText = V.TlsWrapping.Value.auth
case .crypt:
cell.rightText = V.TlsWrapping.Value.crypt
}
} else {
cell.rightText = L10n.Core.Global.Values.disabled
}
cell.accessoryType = .none cell.accessoryType = .none
cell.isTappable = false cell.isTappable = false
case .eku: case .eku:
cell.leftText = V.Eku.caption cell.leftText = V.Eku.caption
cell.rightText = (configuration.checksEKU ?? false) ? L10n.Core.Global.Values.enabled : L10n.Core.Global.Values.disabled cell.rightText = configuration.uiDescriptionForEKU
cell.accessoryType = .none cell.accessoryType = .none
cell.isTappable = false cell.isTappable = false
case .keepAlive: case .keepAlive:
cell.leftText = V.KeepAlive.caption cell.leftText = V.KeepAlive.caption
if let keepAlive = configuration.keepAliveInterval, keepAlive > 0 { cell.rightText = configuration.uiDescriptionForKeepAlive
cell.rightText = V.KeepAlive.Value.seconds(Int(keepAlive))
} else {
cell.rightText = L10n.Core.Global.Values.disabled
}
cell.accessoryType = .none cell.accessoryType = .none
cell.isTappable = false cell.isTappable = false
case .renegSeconds: case .renegSeconds:
cell.leftText = V.RenegotiationSeconds.caption cell.leftText = V.RenegotiationSeconds.caption
if let reneg = configuration.renegotiatesAfter, reneg > 0 { cell.rightText = configuration.uiDescriptionForRenegotiatesAfter
cell.rightText = V.RenegotiationSeconds.Value.after(TimeInterval(reneg).localized)
} else {
cell.rightText = L10n.Core.Global.Values.disabled
}
cell.accessoryType = .none cell.accessoryType = .none
cell.isTappable = false cell.isTappable = false
case .randomEndpoint: case .randomEndpoint:
cell.leftText = V.RandomEndpoint.caption cell.leftText = V.RandomEndpoint.caption
cell.rightText = (configuration.randomizeEndpoint ?? false) ? L10n.Core.Global.Values.enabled : L10n.Core.Global.Values.disabled cell.rightText = configuration.uiDescriptionForRandomizeEndpoint
cell.accessoryType = .none cell.accessoryType = .none
cell.isTappable = false cell.isTappable = false
} }
@ -366,7 +348,7 @@ extension ConfigurationViewController: UITableViewDataSource, UITableViewDelegat
vc.title = settingCell?.leftText vc.title = settingCell?.leftText
vc.options = options vc.options = options
vc.selectedOption = configuration.cipher vc.selectedOption = configuration.cipher
vc.descriptionBlock = { $0.description } vc.descriptionBlock = { $0.uiDescription }
vc.selectionBlock = { [weak self] in vc.selectionBlock = { [weak self] in
self?.configuration.cipher = $0 self?.configuration.cipher = $0
self?.popAndCheckRefresh() self?.popAndCheckRefresh()
@ -379,7 +361,7 @@ extension ConfigurationViewController: UITableViewDataSource, UITableViewDelegat
vc.title = settingCell?.leftText vc.title = settingCell?.leftText
vc.options = OpenVPN.Digest.available vc.options = OpenVPN.Digest.available
vc.selectedOption = configuration.digest vc.selectedOption = configuration.digest
vc.descriptionBlock = { $0.description } vc.descriptionBlock = { $0.uiDescription }
vc.selectionBlock = { [weak self] in vc.selectionBlock = { [weak self] in
self?.configuration.digest = $0 self?.configuration.digest = $0
self?.popAndCheckRefresh() self?.popAndCheckRefresh()
@ -392,7 +374,7 @@ extension ConfigurationViewController: UITableViewDataSource, UITableViewDelegat
vc.title = settingCell?.leftText vc.title = settingCell?.leftText
vc.options = OpenVPN.CompressionFraming.available vc.options = OpenVPN.CompressionFraming.available
vc.selectedOption = configuration.compressionFraming ?? .disabled vc.selectedOption = configuration.compressionFraming ?? .disabled
vc.descriptionBlock = { $0.cellDescription } vc.descriptionBlock = { $0.uiDescription }
vc.selectionBlock = { [weak self] in vc.selectionBlock = { [weak self] in
self?.configuration.compressionFraming = $0 self?.configuration.compressionFraming = $0
if $0 == .disabled { if $0 == .disabled {
@ -412,7 +394,7 @@ extension ConfigurationViewController: UITableViewDataSource, UITableViewDelegat
vc.title = settingCell?.leftText vc.title = settingCell?.leftText
vc.options = OpenVPN.CompressionAlgorithm.available vc.options = OpenVPN.CompressionAlgorithm.available
vc.selectedOption = configuration.compressionAlgorithm ?? .disabled vc.selectedOption = configuration.compressionAlgorithm ?? .disabled
vc.descriptionBlock = { $0.cellDescription } vc.descriptionBlock = { $0.uiDescription }
vc.selectionBlock = { [weak self] in vc.selectionBlock = { [weak self] in
self?.configuration.compressionAlgorithm = $0 self?.configuration.compressionAlgorithm = $0
self?.popAndCheckRefresh() self?.popAndCheckRefresh()
@ -438,37 +420,3 @@ extension ConfigurationViewController: UITableViewDataSource, UITableViewDelegat
delegate?.configuration(didUpdate: configuration.build()) delegate?.configuration(didUpdate: configuration.build())
} }
} }
// MARK: -
private extension OpenVPN.CompressionFraming {
var cellDescription: String {
let V = L10n.Core.Configuration.Cells.self
switch self {
case .disabled:
return L10n.Core.Global.Values.disabled
case .compLZO:
return V.CompressionFraming.Value.lzo
case .compress:
return V.CompressionFraming.Value.compress
}
}
}
private extension OpenVPN.CompressionAlgorithm {
var cellDescription: String {
let V = L10n.Core.Configuration.Cells.self
switch self {
case .disabled:
return L10n.Core.Global.Values.disabled
case .LZO:
return V.CompressionAlgorithm.Value.lzo
case .other:
return V.CompressionAlgorithm.Value.other
}
}
}

View File

@ -11,14 +11,14 @@
<objects> <objects>
<viewController title="CFG" id="2qK-xl-k6H" customClass="ConfigurationViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController"> <viewController title="CFG" id="2qK-xl-k6H" customClass="ConfigurationViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="wsW-4D-mhl"> <view key="view" id="wsW-4D-mhl">
<rect key="frame" x="0.0" y="0.0" width="480" height="562"/> <rect key="frame" x="0.0" y="0.0" width="600" height="480"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="ppQ-1F-X9m"> <customView translatesAutoresizingMaskIntoConstraints="NO" id="ppQ-1F-X9m">
<rect key="frame" x="20" y="20" width="440" height="532"/> <rect key="frame" x="20" y="20" width="560" height="450"/>
<subviews> <subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6YQ-CI-ar2" userLabel="PRS:"> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6YQ-CI-ar2" userLabel="PRS:">
<rect key="frame" x="58" y="504" width="33" height="16"/> <rect key="frame" x="58" y="422" width="33" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="PRS:" id="DTc-tO-b0T"> <textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="PRS:" id="DTc-tO-b0T">
<font key="font" usesAppearanceFont="YES"/> <font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@ -26,7 +26,7 @@
</textFieldCell> </textFieldCell>
</textField> </textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6q3-tL-hU7"> <popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6q3-tL-hU7">
<rect key="frame" x="96" y="498" width="177" height="25"/> <rect key="frame" x="96" y="416" width="78" height="25"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="e1N-3D-o07" id="1c6-o0-gyl"> <popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="e1N-3D-o07" id="1c6-o0-gyl">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="menu"/>
@ -42,353 +42,75 @@
<action selector="selectPreset:" target="2qK-xl-k6H" id="TMM-Bw-xiW"/> <action selector="selectPreset:" target="2qK-xl-k6H" id="TMM-Bw-xiW"/>
</connections> </connections>
</popUpButton> </popUpButton>
<box title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="noF-3X-SdU"> <scrollView autohidesScrollers="YES" horizontalLineScroll="17" horizontalPageScroll="10" verticalLineScroll="17" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hlf-Te-5lZ">
<rect key="frame" x="-3" y="374" width="446" height="108"/> <rect key="frame" x="0.0" y="0.0" width="560" height="400"/>
<view key="contentView" id="tOr-Oq-66f"> <clipView key="contentView" drawsBackground="NO" id="5Gc-VT-DJU">
<rect key="frame" x="3" y="3" width="440" height="90"/> <rect key="frame" x="1" y="1" width="558" height="398"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="wbi-ok-dqq"> <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="none" alternatingRowBackgroundColors="YES" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" id="Aev-6g-jOS">
<rect key="frame" x="0.0" y="20" width="440" height="50"/> <rect key="frame" x="0.0" y="0.0" width="558" height="398"/>
<subviews> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Wza-lZ-2pF"> <size key="intercellSpacing" width="17" height="0.0"/>
<rect key="frame" x="-2" y="32" width="194" height="16"/> <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="CPH:" id="aCv-le-jk6"> <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<font key="font" usesAppearanceFont="YES"/> <tableColumns>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <tableColumn identifier="Name" width="200" minWidth="40" maxWidth="1000" id="8JZ-Y9-rVB">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Text" id="McW-Hr-n5C" userLabel="Text Cell">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="INb-TX-8fh" userLabel="Cipher"> </tableColumn>
<rect key="frame" x="197" y="26" width="177" height="25"/> <tableColumn identifier="Value" width="200" minWidth="200" maxWidth="400" id="MdT-vb-PXp">
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="FIh-Qa-sei" id="DMQ-nI-EyV"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<popUpButtonCell key="dataCell" type="bevel" bezelStyle="regularSquare" alignment="left" lineBreakMode="truncatingTail" imageScaling="proportionallyDown" inset="2" preferredEdge="maxY" id="Ga8-do-B2O" userLabel="Value">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="menu"/>
<menu key="menu" id="9Yx-uh-bWy"> <menu key="menu" id="iGZ-hf-0qP"/>
<items>
<menuItem title="Item 1" state="on" id="FIh-Qa-sei"/>
<menuItem title="Item 2" id="9yg-gN-3po"/>
<menuItem title="Item 3" id="lN5-8d-Rny"/>
</items>
</menu>
</popUpButtonCell> </popUpButtonCell>
<connections> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<action selector="selectCipher:" target="2qK-xl-k6H" id="92r-RU-mam"/> </tableColumn>
</connections> </tableColumns>
</popUpButton> <connections>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NJ1-sv-GbC"> <outlet property="dataSource" destination="2qK-xl-k6H" id="wgC-Pw-qZl"/>
<rect key="frame" x="-2" y="2" width="194" height="16"/> <outlet property="delegate" destination="2qK-xl-k6H" id="hyi-T6-ufW"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="DIG:" id="guB-xk-qaO"> </connections>
<font key="font" usesAppearanceFont="YES"/> </tableView>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZHL-bq-BNN" userLabel="Auth">
<rect key="frame" x="197" y="-4" width="177" height="25"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="iaW-RE-Xam" id="Rbx-Zw-rpS">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="a9h-rV-W1O">
<items>
<menuItem title="Item 1" state="on" id="iaW-RE-Xam"/>
<menuItem title="Item 2" id="cmo-Lh-E96"/>
<menuItem title="Item 3" id="oXV-cg-Goe"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="selectDigest:" target="2qK-xl-k6H" id="OBq-na-RhS"/>
</connections>
</popUpButton>
</subviews>
<constraints>
<constraint firstItem="INb-TX-8fh" firstAttribute="top" secondItem="wbi-ok-dqq" secondAttribute="top" id="4Np-Wo-t90"/>
<constraint firstItem="INb-TX-8fh" firstAttribute="leading" secondItem="wbi-ok-dqq" secondAttribute="leading" constant="200" id="57e-IX-AsH"/>
<constraint firstItem="ZHL-bq-BNN" firstAttribute="leading" secondItem="NJ1-sv-GbC" secondAttribute="trailing" constant="10" id="5L1-oh-NwJ"/>
<constraint firstItem="Wza-lZ-2pF" firstAttribute="leading" secondItem="wbi-ok-dqq" secondAttribute="leading" id="AaE-h6-RED"/>
<constraint firstItem="ZHL-bq-BNN" firstAttribute="trailing" secondItem="INb-TX-8fh" secondAttribute="trailing" id="Bga-VI-xj4"/>
<constraint firstItem="ZHL-bq-BNN" firstAttribute="top" secondItem="INb-TX-8fh" secondAttribute="bottom" constant="10" id="Bj4-ql-Ggb"/>
<constraint firstItem="NJ1-sv-GbC" firstAttribute="leading" secondItem="wbi-ok-dqq" secondAttribute="leading" id="CZy-ul-R15"/>
<constraint firstItem="ZHL-bq-BNN" firstAttribute="leading" secondItem="INb-TX-8fh" secondAttribute="leading" id="Her-Nr-YDv"/>
<constraint firstItem="NJ1-sv-GbC" firstAttribute="centerY" secondItem="ZHL-bq-BNN" secondAttribute="centerY" id="RHt-sv-N7N"/>
<constraint firstItem="Wza-lZ-2pF" firstAttribute="centerY" secondItem="INb-TX-8fh" secondAttribute="centerY" id="Tt0-YG-t1V"/>
<constraint firstAttribute="bottom" secondItem="ZHL-bq-BNN" secondAttribute="bottom" id="Wqv-W3-mEW"/>
<constraint firstAttribute="trailing" secondItem="INb-TX-8fh" secondAttribute="trailing" constant="70" id="YaC-41-yA8"/>
<constraint firstItem="INb-TX-8fh" firstAttribute="leading" secondItem="Wza-lZ-2pF" secondAttribute="trailing" constant="10" id="aZb-nb-avD"/>
</constraints>
</customView>
</subviews> </subviews>
<constraints> <nil key="backgroundColor"/>
<constraint firstAttribute="trailing" secondItem="wbi-ok-dqq" secondAttribute="trailing" id="DAi-zB-GDq"/> </clipView>
<constraint firstItem="wbi-ok-dqq" firstAttribute="leading" secondItem="tOr-Oq-66f" secondAttribute="leading" id="Kke-q1-azT"/> <constraints>
<constraint firstAttribute="bottom" secondItem="wbi-ok-dqq" secondAttribute="bottom" constant="20" id="Xwq-W7-H3i"/> <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="400" id="6We-tM-yIE"/>
<constraint firstItem="wbi-ok-dqq" firstAttribute="top" secondItem="tOr-Oq-66f" secondAttribute="top" constant="20" id="e0V-A5-dfr"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="300" id="Y19-76-5gR"/>
</constraints> </constraints>
</view> <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="1ra-L9-tjJ">
</box> <rect key="frame" x="1" y="383" width="558" height="16"/>
<box title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="2Vl-8V-yr1"> <autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="-3" y="260" width="446" height="108"/> </scroller>
<view key="contentView" id="ExU-Sf-nr9"> <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="kWc-0a-AMk">
<rect key="frame" x="3" y="3" width="440" height="90"/> <rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask"/>
<subviews> </scroller>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="ru8-eQ-dp4"> </scrollView>
<rect key="frame" x="0.0" y="20" width="440" height="50"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mmi-Ge-dI1">
<rect key="frame" x="-2" y="32" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="FRM:" id="2dz-7I-sWy">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kNh-qP-ES2" userLabel="Framing">
<rect key="frame" x="197" y="26" width="227" height="25"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Hwl-mP-WGl" id="cuf-0Q-FHF">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="mgY-9I-oka">
<items>
<menuItem title="Item 1" state="on" id="Hwl-mP-WGl"/>
<menuItem title="Item 2" id="pF1-id-tgi"/>
<menuItem title="Item 3" id="ck3-RH-oKT"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="selectCompressionFraming:" target="2qK-xl-k6H" id="hZd-QK-uOe"/>
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nxB-Zq-fFA">
<rect key="frame" x="-2" y="2" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="ALG:" id="Goa-5C-xyk">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cYO-7e-w11" userLabel="Compression">
<rect key="frame" x="197" y="-4" width="227" height="25"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="DmS-8I-Tdx" id="guC-mt-SKM">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="oCc-Bq-hg0">
<items>
<menuItem title="Item 1" state="on" id="DmS-8I-Tdx"/>
<menuItem title="Item 2" id="HlN-XI-1bz"/>
<menuItem title="Item 3" id="Mvr-hG-dLq"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="selectCompressionAlgorithm:" target="2qK-xl-k6H" id="kIB-Tc-s7Z"/>
</connections>
</popUpButton>
</subviews>
<constraints>
<constraint firstItem="cYO-7e-w11" firstAttribute="leading" secondItem="nxB-Zq-fFA" secondAttribute="trailing" constant="10" id="2QW-tm-vef"/>
<constraint firstAttribute="trailing" secondItem="kNh-qP-ES2" secondAttribute="trailing" constant="20" id="BAw-Ta-gza"/>
<constraint firstItem="mmi-Ge-dI1" firstAttribute="leading" secondItem="ru8-eQ-dp4" secondAttribute="leading" id="GNB-bz-CaE"/>
<constraint firstItem="kNh-qP-ES2" firstAttribute="top" secondItem="ru8-eQ-dp4" secondAttribute="top" id="OMT-oF-KV5"/>
<constraint firstAttribute="bottom" secondItem="cYO-7e-w11" secondAttribute="bottom" id="bnE-cN-i9h"/>
<constraint firstItem="kNh-qP-ES2" firstAttribute="leading" secondItem="mmi-Ge-dI1" secondAttribute="trailing" constant="10" id="ikM-YT-z2X"/>
<constraint firstItem="kNh-qP-ES2" firstAttribute="width" secondItem="cYO-7e-w11" secondAttribute="width" id="ji1-FV-Jdc"/>
<constraint firstItem="cYO-7e-w11" firstAttribute="leading" secondItem="kNh-qP-ES2" secondAttribute="leading" id="oP4-W3-e3z"/>
<constraint firstItem="nxB-Zq-fFA" firstAttribute="centerY" secondItem="cYO-7e-w11" secondAttribute="centerY" id="oyD-Bb-O7W"/>
<constraint firstItem="mmi-Ge-dI1" firstAttribute="centerY" secondItem="kNh-qP-ES2" secondAttribute="centerY" id="pog-Ru-tKj"/>
<constraint firstItem="nxB-Zq-fFA" firstAttribute="leading" secondItem="ru8-eQ-dp4" secondAttribute="leading" id="s2E-tx-xyK"/>
<constraint firstItem="cYO-7e-w11" firstAttribute="trailing" secondItem="kNh-qP-ES2" secondAttribute="trailing" id="xnq-Q4-Cfc"/>
<constraint firstItem="cYO-7e-w11" firstAttribute="top" secondItem="kNh-qP-ES2" secondAttribute="bottom" constant="10" id="z6y-hQ-YyO"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="ru8-eQ-dp4" secondAttribute="trailing" id="FNG-xF-7Kc"/>
<constraint firstAttribute="bottom" secondItem="ru8-eQ-dp4" secondAttribute="bottom" constant="20" id="Tfo-SN-8H6"/>
<constraint firstItem="ru8-eQ-dp4" firstAttribute="leading" secondItem="ExU-Sf-nr9" secondAttribute="leading" id="pQT-ac-mKO"/>
<constraint firstItem="ru8-eQ-dp4" firstAttribute="top" secondItem="ExU-Sf-nr9" secondAttribute="top" constant="20" id="t2N-RM-8Ry"/>
</constraints>
</view>
</box>
<box title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="KeE-Mp-WiK">
<rect key="frame" x="-3" y="128" width="446" height="126"/>
<view key="contentView" id="0qP-8e-b4N">
<rect key="frame" x="3" y="3" width="440" height="108"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="k4w-ir-jOo">
<rect key="frame" x="-2" y="72" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="CC:" id="JSZ-IP-CzY">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Mwp-vH-RGb">
<rect key="frame" x="198" y="72" width="244" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="?" id="ctc-sg-824">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2UF-qr-7SD">
<rect key="frame" x="-2" y="46" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="WRAP:" id="clD-0x-oeV">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cen-L0-DEY">
<rect key="frame" x="198" y="46" width="244" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="?" id="zPw-xd-bR0">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mOZ-SE-bKj">
<rect key="frame" x="-2" y="20" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="EXT:" id="hFY-Kz-WiQ">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cxF-Cq-aDH">
<rect key="frame" x="198" y="20" width="244" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="?" id="NcP-Li-VaD">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="2UF-qr-7SD" firstAttribute="centerY" secondItem="cen-L0-DEY" secondAttribute="centerY" id="6q0-RF-X3k"/>
<constraint firstItem="2UF-qr-7SD" firstAttribute="trailing" secondItem="k4w-ir-jOo" secondAttribute="trailing" id="FSz-Um-qKu"/>
<constraint firstItem="cen-L0-DEY" firstAttribute="trailing" secondItem="Mwp-vH-RGb" secondAttribute="trailing" id="MGg-5D-5h3"/>
<constraint firstItem="mOZ-SE-bKj" firstAttribute="leading" secondItem="k4w-ir-jOo" secondAttribute="leading" id="NDP-4p-hAq"/>
<constraint firstItem="2UF-qr-7SD" firstAttribute="leading" secondItem="k4w-ir-jOo" secondAttribute="leading" id="U84-T1-U1m"/>
<constraint firstItem="cxF-Cq-aDH" firstAttribute="leading" secondItem="cen-L0-DEY" secondAttribute="leading" id="UxD-iW-h0c"/>
<constraint firstItem="Mwp-vH-RGb" firstAttribute="leading" secondItem="k4w-ir-jOo" secondAttribute="trailing" constant="10" id="XkZ-QI-PAq"/>
<constraint firstItem="k4w-ir-jOo" firstAttribute="leading" secondItem="0qP-8e-b4N" secondAttribute="leading" id="aUz-t1-Daj"/>
<constraint firstItem="cxF-Cq-aDH" firstAttribute="top" secondItem="cen-L0-DEY" secondAttribute="bottom" constant="10" id="bQZ-b9-746"/>
<constraint firstItem="mOZ-SE-bKj" firstAttribute="centerY" secondItem="cxF-Cq-aDH" secondAttribute="centerY" id="cQV-ta-xmO"/>
<constraint firstItem="cxF-Cq-aDH" firstAttribute="trailing" secondItem="cen-L0-DEY" secondAttribute="trailing" id="ern-Yz-wcM"/>
<constraint firstItem="k4w-ir-jOo" firstAttribute="centerY" secondItem="Mwp-vH-RGb" secondAttribute="centerY" id="fBZ-85-RTU"/>
<constraint firstItem="mOZ-SE-bKj" firstAttribute="trailing" secondItem="k4w-ir-jOo" secondAttribute="trailing" id="gdx-oK-hc4"/>
<constraint firstItem="cen-L0-DEY" firstAttribute="leading" secondItem="Mwp-vH-RGb" secondAttribute="leading" id="gon-M7-U9P"/>
<constraint firstAttribute="trailing" secondItem="Mwp-vH-RGb" secondAttribute="trailing" id="hQV-vH-As8"/>
<constraint firstAttribute="bottom" secondItem="cxF-Cq-aDH" secondAttribute="bottom" constant="20" id="lfm-jr-WmS"/>
<constraint firstItem="Mwp-vH-RGb" firstAttribute="top" secondItem="0qP-8e-b4N" secondAttribute="top" constant="20" id="w0H-X0-Fft"/>
<constraint firstItem="cen-L0-DEY" firstAttribute="top" secondItem="Mwp-vH-RGb" secondAttribute="bottom" constant="10" id="wNv-Hf-u0X"/>
</constraints>
</view>
</box>
<box title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="4Ni-cD-Fiu">
<rect key="frame" x="-3" y="-4" width="446" height="126"/>
<view key="contentView" id="Vdt-eK-je3">
<rect key="frame" x="3" y="3" width="440" height="108"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="agX-gP-R4K">
<rect key="frame" x="-2" y="72" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="KA:" id="DP8-o3-EpO">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="B8P-6Q-8ON">
<rect key="frame" x="198" y="72" width="244" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="?" id="QvG-xF-c1R">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Pfk-Cu-ORW">
<rect key="frame" x="-2" y="46" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="RENEG:" id="MGm-Zc-Hk6">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="WGv-ya-8sf">
<rect key="frame" x="198" y="46" width="244" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="?" id="7aY-Rq-NmI">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Hn8-0q-BbI">
<rect key="frame" x="-2" y="20" width="194" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="RAND:" id="Aql-zV-xga">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="c24-Qe-6KM">
<rect key="frame" x="198" y="20" width="244" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="?" id="0Bm-Fc-faF">
<font key="font" metaFont="systemBold"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="WGv-ya-8sf" firstAttribute="trailing" secondItem="B8P-6Q-8ON" secondAttribute="trailing" id="0lw-Pd-BYx"/>
<constraint firstItem="agX-gP-R4K" firstAttribute="leading" secondItem="Vdt-eK-je3" secondAttribute="leading" id="4Qh-a8-Xlf"/>
<constraint firstItem="agX-gP-R4K" firstAttribute="centerY" secondItem="B8P-6Q-8ON" secondAttribute="centerY" id="9Re-ts-VYh"/>
<constraint firstItem="Hn8-0q-BbI" firstAttribute="centerY" secondItem="c24-Qe-6KM" secondAttribute="centerY" id="Cni-jI-tfE"/>
<constraint firstItem="c24-Qe-6KM" firstAttribute="trailing" secondItem="WGv-ya-8sf" secondAttribute="trailing" id="DQS-ne-kDq"/>
<constraint firstItem="WGv-ya-8sf" firstAttribute="top" secondItem="B8P-6Q-8ON" secondAttribute="bottom" constant="10" id="Fu4-0n-guZ"/>
<constraint firstAttribute="bottom" secondItem="c24-Qe-6KM" secondAttribute="bottom" constant="20" id="JVj-Aj-Uo0"/>
<constraint firstItem="Pfk-Cu-ORW" firstAttribute="leading" secondItem="agX-gP-R4K" secondAttribute="leading" id="KeG-WG-HTP"/>
<constraint firstAttribute="trailing" secondItem="B8P-6Q-8ON" secondAttribute="trailing" id="Lop-sd-rHb"/>
<constraint firstItem="WGv-ya-8sf" firstAttribute="leading" secondItem="B8P-6Q-8ON" secondAttribute="leading" id="Mkj-3m-NPU"/>
<constraint firstItem="Pfk-Cu-ORW" firstAttribute="centerY" secondItem="WGv-ya-8sf" secondAttribute="centerY" id="OpO-7r-Jxn"/>
<constraint firstItem="c24-Qe-6KM" firstAttribute="leading" secondItem="WGv-ya-8sf" secondAttribute="leading" id="RCe-Sa-0wz"/>
<constraint firstItem="c24-Qe-6KM" firstAttribute="top" secondItem="WGv-ya-8sf" secondAttribute="bottom" constant="10" id="Yl7-um-3Ba"/>
<constraint firstItem="Hn8-0q-BbI" firstAttribute="trailing" secondItem="agX-gP-R4K" secondAttribute="trailing" id="Yrt-4y-JKr"/>
<constraint firstItem="Hn8-0q-BbI" firstAttribute="leading" secondItem="agX-gP-R4K" secondAttribute="leading" id="eT8-8S-vb8"/>
<constraint firstItem="Pfk-Cu-ORW" firstAttribute="trailing" secondItem="agX-gP-R4K" secondAttribute="trailing" id="iM8-KB-jbu"/>
<constraint firstItem="B8P-6Q-8ON" firstAttribute="leading" secondItem="agX-gP-R4K" secondAttribute="trailing" constant="10" id="keF-H0-SsG"/>
<constraint firstItem="B8P-6Q-8ON" firstAttribute="top" secondItem="Vdt-eK-je3" secondAttribute="top" constant="20" id="x9w-PT-AYQ"/>
</constraints>
</view>
</box>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstAttribute="trailing" secondItem="KeE-Mp-WiK" secondAttribute="trailing" id="5h6-Mo-rj9"/> <constraint firstAttribute="trailing" secondItem="Hlf-Te-5lZ" secondAttribute="trailing" id="3f6-Kf-hGd"/>
<constraint firstItem="2Vl-8V-yr1" firstAttribute="leading" secondItem="ppQ-1F-X9m" secondAttribute="leading" id="8lX-nC-JeU"/> <constraint firstAttribute="bottom" secondItem="Hlf-Te-5lZ" secondAttribute="bottom" id="JWl-Ym-x2N"/>
<constraint firstAttribute="trailing" secondItem="2Vl-8V-yr1" secondAttribute="trailing" id="Buk-he-dbg"/>
<constraint firstItem="4Ni-cD-Fiu" firstAttribute="leading" secondItem="ppQ-1F-X9m" secondAttribute="leading" id="Jzp-aX-E99"/>
<constraint firstItem="KeE-Mp-WiK" firstAttribute="top" secondItem="2Vl-8V-yr1" secondAttribute="bottom" constant="10" id="LLG-8Q-lXt"/>
<constraint firstItem="KeE-Mp-WiK" firstAttribute="leading" secondItem="ppQ-1F-X9m" secondAttribute="leading" id="LyH-Oj-gmv"/>
<constraint firstAttribute="bottom" secondItem="4Ni-cD-Fiu" secondAttribute="bottom" id="MXf-KP-eQV"/>
<constraint firstItem="6q3-tL-hU7" firstAttribute="width" relation="greaterThanOrEqual" secondItem="INb-TX-8fh" secondAttribute="width" id="NeY-9Q-Qye"/>
<constraint firstItem="noF-3X-SdU" firstAttribute="leading" secondItem="ppQ-1F-X9m" secondAttribute="leading" id="OWZ-xn-ZH1"/>
<constraint firstAttribute="trailing" secondItem="4Ni-cD-Fiu" secondAttribute="trailing" id="OgW-4M-aPJ"/>
<constraint firstItem="Mwp-vH-RGb" firstAttribute="leading" secondItem="INb-TX-8fh" secondAttribute="leading" id="RLz-KV-Duu"/>
<constraint firstItem="2Vl-8V-yr1" firstAttribute="top" secondItem="noF-3X-SdU" secondAttribute="bottom" constant="10" id="Tcj-au-tSn"/>
<constraint firstItem="6q3-tL-hU7" firstAttribute="leading" secondItem="6YQ-CI-ar2" secondAttribute="trailing" constant="10" id="V3W-Ns-ckL"/> <constraint firstItem="6q3-tL-hU7" firstAttribute="leading" secondItem="6YQ-CI-ar2" secondAttribute="trailing" constant="10" id="V3W-Ns-ckL"/>
<constraint firstAttribute="trailing" secondItem="noF-3X-SdU" secondAttribute="trailing" id="W2X-yg-RuM"/>
<constraint firstItem="6q3-tL-hU7" firstAttribute="top" secondItem="ppQ-1F-X9m" secondAttribute="top" constant="10" id="c7j-Ky-bjK"/> <constraint firstItem="6q3-tL-hU7" firstAttribute="top" secondItem="ppQ-1F-X9m" secondAttribute="top" constant="10" id="c7j-Ky-bjK"/>
<constraint firstItem="Hlf-Te-5lZ" firstAttribute="top" secondItem="6q3-tL-hU7" secondAttribute="bottom" constant="20" id="eku-c6-Z8b"/>
<constraint firstItem="6YQ-CI-ar2" firstAttribute="centerY" secondItem="6q3-tL-hU7" secondAttribute="centerY" id="eq6-dG-xVV"/> <constraint firstItem="6YQ-CI-ar2" firstAttribute="centerY" secondItem="6q3-tL-hU7" secondAttribute="centerY" id="eq6-dG-xVV"/>
<constraint firstItem="6YQ-CI-ar2" firstAttribute="leading" secondItem="ppQ-1F-X9m" secondAttribute="leading" constant="60" id="j0w-hw-ijL"/> <constraint firstItem="6YQ-CI-ar2" firstAttribute="leading" secondItem="ppQ-1F-X9m" secondAttribute="leading" constant="60" id="j0w-hw-ijL"/>
<constraint firstItem="agX-gP-R4K" firstAttribute="trailing" secondItem="k4w-ir-jOo" secondAttribute="trailing" id="nGY-dv-WNx"/> <constraint firstItem="Hlf-Te-5lZ" firstAttribute="leading" secondItem="ppQ-1F-X9m" secondAttribute="leading" id="lXE-Ru-lGG"/>
<constraint firstItem="noF-3X-SdU" firstAttribute="top" secondItem="6q3-tL-hU7" secondAttribute="bottom" constant="20" id="pvz-Mk-OQE"/>
<constraint firstItem="4Ni-cD-Fiu" firstAttribute="top" secondItem="KeE-Mp-WiK" secondAttribute="bottom" constant="10" id="tyT-wQ-1wE"/>
<constraint firstItem="kNh-qP-ES2" firstAttribute="leading" secondItem="INb-TX-8fh" secondAttribute="leading" id="zR5-QN-8TG"/>
</constraints> </constraints>
</customView> </customView>
</subviews> </subviews>
@ -400,32 +122,9 @@
</constraints> </constraints>
</view> </view>
<connections> <connections>
<outlet property="boxCommunication" destination="noF-3X-SdU" id="jly-Jj-Nfl"/>
<outlet property="boxCompression" destination="2Vl-8V-yr1" id="K8w-6i-Tr7"/>
<outlet property="boxOther" destination="4Ni-cD-Fiu" id="59l-KR-9S3"/>
<outlet property="boxTLS" destination="KeE-Mp-WiK" id="wAj-gU-lEo"/>
<outlet property="labelCipherCaption" destination="Wza-lZ-2pF" id="W1E-JF-SgF"/>
<outlet property="labelClientCertificate" destination="Mwp-vH-RGb" id="XAr-N6-McZ"/>
<outlet property="labelClientCertificateCaption" destination="k4w-ir-jOo" id="g0N-52-yol"/>
<outlet property="labelCompressionAlgorithmCaption" destination="nxB-Zq-fFA" id="AxR-9T-uyA"/>
<outlet property="labelCompressionFramingCaption" destination="mmi-Ge-dI1" id="WKI-il-elO"/>
<outlet property="labelDigestCaption" destination="NJ1-sv-GbC" id="0VW-ly-gCN"/>
<outlet property="labelExtendedVerification" destination="cxF-Cq-aDH" id="HL2-BU-Nwp"/>
<outlet property="labelExtendedVerificationCaption" destination="mOZ-SE-bKj" id="D0X-e1-Dv3"/>
<outlet property="labelKeepAlive" destination="B8P-6Q-8ON" id="P1q-HQ-Vbx"/>
<outlet property="labelKeepAliveCaption" destination="agX-gP-R4K" id="NH8-Up-ka2"/>
<outlet property="labelPresetCaption" destination="6YQ-CI-ar2" id="1sd-n3-S0l"/> <outlet property="labelPresetCaption" destination="6YQ-CI-ar2" id="1sd-n3-S0l"/>
<outlet property="labelRandomizeEndpoint" destination="c24-Qe-6KM" id="mu5-se-9YF"/>
<outlet property="labelRandomizeEndpointCaption" destination="Hn8-0q-BbI" id="bBe-9z-jct"/>
<outlet property="labelRenegotiation" destination="WGv-ya-8sf" id="Ylz-SE-bcO"/>
<outlet property="labelRenegotiationCaption" destination="Pfk-Cu-ORW" id="WFm-AW-lz9"/>
<outlet property="labelWrapping" destination="cen-L0-DEY" id="mhp-lU-STE"/>
<outlet property="labelWrappingCaption" destination="2UF-qr-7SD" id="PJq-Vi-d6U"/>
<outlet property="popupCipher" destination="INb-TX-8fh" id="E6p-Xt-QrG"/>
<outlet property="popupCompressionAlgorithm" destination="cYO-7e-w11" id="iyd-Jt-iYW"/>
<outlet property="popupCompressionFraming" destination="kNh-qP-ES2" id="sRv-Ol-b0O"/>
<outlet property="popupDigest" destination="ZHL-bq-BNN" id="xQM-oM-sSd"/>
<outlet property="popupPreset" destination="6q3-tL-hU7" id="ajK-7f-xck"/> <outlet property="popupPreset" destination="6q3-tL-hU7" id="ajK-7f-xck"/>
<outlet property="tableConfiguration" destination="Aev-6g-jOS" id="Yt9-bg-iU1"/>
</connections> </connections>
</viewController> </viewController>
<customObject id="Nh8-KC-KyH" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> <customObject id="Nh8-KC-KyH" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>

View File

@ -128,6 +128,18 @@ extension NSImage {
} }
} }
extension NSMenu {
static func withDescriptibles(_ list: [UIDescriptible]) -> NSMenu {
let menu = NSMenu()
for o in list {
let item = NSMenuItem(title: o.uiDescription, action: nil, keyEquivalent: "")
item.representedObject = o
menu.addItem(item)
}
return menu
}
}
extension String { extension String {
var asCaption: String { var asCaption: String {
return "\(self):" return "\(self):"

View File

@ -28,57 +28,17 @@ import PassepartoutCore
import TunnelKit import TunnelKit
class ConfigurationViewController: NSViewController, ProfileCustomization { class ConfigurationViewController: NSViewController, ProfileCustomization {
private struct Columns {
static let name = NSUserInterfaceItemIdentifier("Name")
static let value = NSUserInterfaceItemIdentifier("Value")
}
@IBOutlet private weak var labelPresetCaption: NSTextField! @IBOutlet private weak var labelPresetCaption: NSTextField!
@IBOutlet private weak var popupPreset: NSPopUpButton! @IBOutlet private weak var popupPreset: NSPopUpButton!
@IBOutlet private weak var boxCommunication: NSBox! @IBOutlet private weak var tableConfiguration: NSTableView!
@IBOutlet private weak var labelCipherCaption: NSTextField!
@IBOutlet private weak var popupCipher: NSPopUpButton!
@IBOutlet private weak var labelDigestCaption: NSTextField!
@IBOutlet private weak var popupDigest: NSPopUpButton!
@IBOutlet private weak var boxCompression: NSBox!
@IBOutlet private weak var labelCompressionFramingCaption: NSTextField!
@IBOutlet private weak var popupCompressionFraming: NSPopUpButton!
@IBOutlet private weak var labelCompressionAlgorithmCaption: NSTextField!
@IBOutlet private weak var popupCompressionAlgorithm: NSPopUpButton!
@IBOutlet private weak var boxTLS: NSBox!
@IBOutlet private weak var labelClientCertificateCaption: NSTextField!
@IBOutlet private weak var labelClientCertificate: NSTextField!
@IBOutlet private weak var labelWrappingCaption: NSTextField!
@IBOutlet private weak var labelWrapping: NSTextField!
@IBOutlet private weak var labelExtendedVerificationCaption: NSTextField!
@IBOutlet private weak var labelExtendedVerification: NSTextField!
@IBOutlet private weak var boxOther: NSBox!
@IBOutlet private weak var labelKeepAliveCaption: NSTextField!
@IBOutlet private weak var labelKeepAlive: NSTextField!
@IBOutlet private weak var labelRenegotiationCaption: NSTextField!
@IBOutlet private weak var labelRenegotiation: NSTextField!
@IBOutlet private weak var labelRandomizeEndpointCaption: NSTextField!
@IBOutlet private weak var labelRandomizeEndpoint: NSTextField!
private lazy var allPresets: [InfrastructurePreset] = { private lazy var allPresets: [InfrastructurePreset] = {
guard let providerProfile = profile as? ProviderConnectionProfile else { guard let providerProfile = profile as? ProviderConnectionProfile else {
@ -100,6 +60,21 @@ class ConfigurationViewController: NSViewController, ProfileCustomization {
} }
private var configuration = OpenVPN.ConfigurationBuilder() private var configuration = OpenVPN.ConfigurationBuilder()
private let rows: [RowType] = [
.cipher,
.digest,
.compressionFraming,
.compressionAlgorithm,
.client,
.tlsWrapping,
.eku,
.keepAlive,
.renegSeconds,
.randomEndpoint
]
private var rowMenus: [RowType: NSMenu] = [:]
// MARK: ProfileCustomization // MARK: ProfileCustomization
@ -118,119 +93,62 @@ class ConfigurationViewController: NSViewController, ProfileCustomization {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
let V = L10n.Core.Configuration.Cells.self
labelPresetCaption.stringValue = L10n.Core.Service.Cells.Provider.Preset.caption.asCaption labelPresetCaption.stringValue = L10n.Core.Service.Cells.Provider.Preset.caption.asCaption
popupPreset.removeAllItems() popupPreset.removeAllItems()
if !allPresets.isEmpty { if !allPresets.isEmpty {
for preset in allPresets { for preset in allPresets {
popupPreset.addItem(withTitle: preset.name) popupPreset.addItem(withTitle: preset.name)
} }
popupCipher.isEnabled = false
popupDigest.isEnabled = false
popupCompressionFraming.isEnabled = false
popupCompressionAlgorithm.isEnabled = false
} else { } else {
popupPreset.addItem(withTitle: L10n.Core.Global.Values.default) popupPreset.addItem(withTitle: L10n.Core.Global.Values.default)
popupPreset.isEnabled = false popupPreset.isEnabled = false
} }
boxCommunication.title = L10n.Core.Configuration.Sections.Communication.header
boxCompression.title = L10n.Core.Configuration.Sections.Compression.header
boxTLS.title = L10n.Core.Configuration.Sections.Tls.header
boxOther.title = L10n.Core.Configuration.Sections.Other.header
labelCipherCaption.stringValue = V.Cipher.caption.asCaption
labelDigestCaption.stringValue = V.Digest.caption.asCaption
labelCompressionFramingCaption.stringValue = V.CompressionFraming.caption.asCaption
labelCompressionAlgorithmCaption.stringValue = V.CompressionAlgorithm.caption.asCaption
labelClientCertificateCaption.stringValue = V.Client.caption.asCaption
labelWrappingCaption.stringValue = V.TlsWrapping.caption.asCaption
labelExtendedVerificationCaption.stringValue = V.Eku.caption.asCaption
labelKeepAliveCaption.stringValue = V.KeepAlive.caption.asCaption
labelRenegotiationCaption.stringValue = V.RenegotiationSeconds.caption.asCaption
labelRandomizeEndpointCaption.stringValue = V.RandomEndpoint.caption.asCaption
popupCipher.removeAllItems()
popupDigest.removeAllItems()
popupCompressionFraming.removeAllItems()
popupCompressionAlgorithm.removeAllItems()
var cipherOptions: [OpenVPN.Cipher] = configuration.dataCiphers ?? []
if !cipherOptions.isEmpty {
if let cipher = configuration.cipher, !cipherOptions.contains(cipher) {
cipherOptions.append(cipher)
}
} else {
cipherOptions.append(contentsOf: OpenVPN.Cipher.available)
}
for cipher in cipherOptions {
popupCipher.addItem(withTitle: cipher.rawValue)
}
for digest in OpenVPN.Digest.available {
popupDigest.addItem(withTitle: digest.rawValue)
}
for framing in OpenVPN.CompressionFraming.available {
popupCompressionFraming.addItem(withTitle: framing.itemDescription)
}
for algorithm in OpenVPN.CompressionAlgorithm.available {
popupCompressionAlgorithm.addItem(withTitle: algorithm.itemDescription)
}
reloadModel() reloadModel()
} }
private func reloadModel() { private func reloadModel() {
let V = L10n.Core.Configuration.Cells.self
if let index = allPresets.firstIndex(where: { $0.id == preset?.id }) { if let index = allPresets.firstIndex(where: { $0.id == preset?.id }) {
popupPreset.selectItem(at: index) popupPreset.selectItem(at: index)
} }
if let index = OpenVPN.Cipher.available.firstIndex(of: configuration.fallbackCipher) { var availableCiphers: [OpenVPN.Cipher]
popupCipher.selectItem(at: index) let availableDigests: [OpenVPN.Digest]
} let availableCF: [OpenVPN.CompressionFraming]
if let index = OpenVPN.Digest.available.firstIndex(of: configuration.fallbackDigest) { let availableCA: [OpenVPN.CompressionAlgorithm]
popupDigest.selectItem(at: index) if let _ = profile as? HostConnectionProfile {
} availableCiphers = configuration.dataCiphers ?? []
if let index = OpenVPN.CompressionFraming.available.firstIndex(of: configuration.compressionFraming ?? .disabled) { if !availableCiphers.isEmpty {
popupCompressionFraming.selectItem(at: index) if let cipher = configuration.cipher, !availableCiphers.contains(cipher) {
} availableCiphers.append(cipher)
if let index = OpenVPN.CompressionAlgorithm.available.firstIndex(of: configuration.compressionAlgorithm ?? .disabled) { }
popupCompressionAlgorithm.selectItem(at: index) } else {
availableCiphers.append(contentsOf: OpenVPN.Cipher.available)
}
availableDigests = OpenVPN.Digest.available
availableCF = OpenVPN.CompressionFraming.available
availableCA = OpenVPN.CompressionAlgorithm.available
} else {
availableCiphers = [configuration.fallbackCipher]
availableDigests = [configuration.fallbackDigest]
availableCF = [configuration.fallbackCompressionFraming]
availableCA = [configuration.fallbackCompressionAlgorithm]
} }
// enforce item constraints // editable
selectCompressionFraming(nil) rowMenus[.cipher] = NSMenu.withDescriptibles(availableCiphers)
selectCompressionAlgorithm(nil) rowMenus[.digest] = NSMenu.withDescriptibles(availableDigests)
rowMenus[.compressionFraming] = NSMenu.withDescriptibles(availableCF)
labelClientCertificate.stringValue = (configuration.clientCertificate != nil) ? V.Client.Value.enabled : V.Client.Value.disabled rowMenus[.compressionAlgorithm] = NSMenu.withDescriptibles(availableCA)
if let strategy = configuration.tlsWrap?.strategy {
switch strategy { // single-option menus (unselectable)
case .auth: rowMenus[.client] = NSMenu.withDescriptibles([configuration.uiDescriptionForClientCertificate])
labelWrapping.stringValue = V.TlsWrapping.Value.auth rowMenus[.tlsWrapping] = NSMenu.withDescriptibles([configuration.uiDescriptionForTLSWrap])
rowMenus[.eku] = NSMenu.withDescriptibles([configuration.uiDescriptionForEKU])
case .crypt: rowMenus[.keepAlive] = NSMenu.withDescriptibles([configuration.uiDescriptionForKeepAlive])
labelWrapping.stringValue = V.TlsWrapping.Value.crypt rowMenus[.renegSeconds] = NSMenu.withDescriptibles([configuration.uiDescriptionForRenegotiatesAfter])
} rowMenus[.randomEndpoint] = NSMenu.withDescriptibles([configuration.uiDescriptionForRandomizeEndpoint])
} else {
labelWrapping.stringValue = L10n.Core.Global.Values.disabled
}
labelExtendedVerification.stringValue = (configuration.checksEKU ?? false) ? L10n.Core.Global.Values.enabled : L10n.Core.Global.Values.disabled
if let keepAlive = configuration.keepAliveInterval, keepAlive > 0 {
labelKeepAlive.stringValue = V.KeepAlive.Value.seconds(Int(keepAlive))
} else {
labelKeepAlive.stringValue = L10n.Core.Global.Values.disabled
}
if let reneg = configuration.renegotiatesAfter, reneg > 0 {
labelRenegotiation.stringValue = V.RenegotiationSeconds.Value.after(TimeInterval(reneg).localized)
} else {
labelRenegotiation.stringValue = L10n.Core.Global.Values.disabled
}
labelRandomizeEndpoint.stringValue = (configuration.randomizeEndpoint ?? false) ? L10n.Core.Global.Values.enabled : L10n.Core.Global.Values.disabled
} }
// MARK: Actions // MARK: Actions
@IBAction private func selectPreset(_ sender: Any?) { @IBAction private func selectPreset(_ sender: Any?) {
@ -238,73 +156,153 @@ class ConfigurationViewController: NSViewController, ProfileCustomization {
self.preset = preset self.preset = preset
reloadModel() reloadModel()
delegate?.profileCustomization(self, didUpdatePreset: preset) delegate?.profileCustomization(self, didUpdatePreset: preset)
tableConfiguration.reloadData()
} }
}
@IBAction private func selectCipher(_ sender: Any?) { extension ConfigurationViewController: NSTableViewDataSource, NSTableViewDelegate {
configuration.cipher = OpenVPN.Cipher.available[popupCipher.indexOfSelectedItem] enum RowType: Int {
delegate?.profileCustomization(self, didUpdateConfiguration: configuration) // case resetOriginal
}
@IBAction private func selectDigest(_ sender: Any?) { case cipher
configuration.digest = OpenVPN.Digest.available[popupDigest.indexOfSelectedItem]
delegate?.profileCustomization(self, didUpdateConfiguration: configuration) case digest
case compressionFraming
case compressionAlgorithm
case client
case tlsWrapping
case eku
case keepAlive
case renegSeconds
case randomEndpoint
} }
@IBAction private func selectCompressionFraming(_ sender: Any?) { func numberOfRows(in tableView: NSTableView) -> Int {
return rows.count
// if framing is disabled, disable algorithm
if popupCompressionFraming.indexOfSelectedItem == 0 {
popupCompressionAlgorithm.selectItem(at: 0)
}
configuration.compressionFraming = OpenVPN.CompressionFraming.available[popupCompressionFraming.indexOfSelectedItem]
configuration.compressionAlgorithm = OpenVPN.CompressionAlgorithm.available[popupCompressionAlgorithm.indexOfSelectedItem]
delegate?.profileCustomization(self, didUpdateConfiguration: configuration)
} }
@IBAction private func selectCompressionAlgorithm(_ sender: Any?) { func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
// if framing is disabled and algorithm is not disabled, enable --comp-lzo framing
if popupCompressionFraming.indexOfSelectedItem == 0 && popupCompressionAlgorithm.indexOfSelectedItem != 0 {
popupCompressionFraming.selectItem(at: 1)
}
configuration.compressionFraming = OpenVPN.CompressionFraming.available[popupCompressionFraming.indexOfSelectedItem]
configuration.compressionAlgorithm = OpenVPN.CompressionAlgorithm.available[popupCompressionAlgorithm.indexOfSelectedItem]
delegate?.profileCustomization(self, didUpdateConfiguration: configuration)
}
}
// MARK: -
private extension OpenVPN.CompressionFraming {
var itemDescription: String {
let V = L10n.Core.Configuration.Cells.self let V = L10n.Core.Configuration.Cells.self
switch self { let rowObject = rows[row]
case .disabled:
return L10n.Core.Global.Values.disabled
case .compLZO:
return V.CompressionFraming.Value.lzo
case .compress:
return V.CompressionFraming.Value.compress
}
}
}
private extension OpenVPN.CompressionAlgorithm { switch tableColumn?.identifier {
var itemDescription: String { case Columns.name:
let V = L10n.Core.Configuration.Cells.self switch rowObject {
switch self { case .cipher:
case .disabled: return V.Cipher.caption
return L10n.Core.Global.Values.disabled
case .digest:
return V.Digest.caption
case .compressionFraming:
return V.CompressionFraming.caption
case .compressionAlgorithm:
return V.CompressionAlgorithm.caption
case .client:
return V.Client.caption
case .tlsWrapping:
return V.TlsWrapping.caption
case .eku:
return V.Eku.caption
case .keepAlive:
return V.KeepAlive.caption
case .renegSeconds:
return V.RenegotiationSeconds.caption
case .LZO: case .randomEndpoint:
return V.CompressionAlgorithm.Value.lzo return V.RandomEndpoint.caption
}
case .other: case Columns.value:
return V.CompressionAlgorithm.Value.other guard let menu = rowMenus[rowObject], let cell = tableColumn?.dataCell(forRow: row) as? NSPopUpButtonCell else {
return nil
}
cell.menu = menu
cell.imageDimsWhenDisabled = false
if menu.numberOfItems > 1 {
cell.arrowPosition = .arrowAtBottom
cell.isEnabled = true
} else {
cell.arrowPosition = .noArrow
cell.isEnabled = false
}
switch rowObject {
case .cipher:
return menu.indexOfItem(withRepresentedObject: configuration.fallbackCipher)
case .digest:
return menu.indexOfItem(withRepresentedObject: configuration.fallbackDigest)
case .compressionFraming:
return menu.indexOfItem(withRepresentedObject: configuration.fallbackCompressionFraming)
case .compressionAlgorithm:
return menu.indexOfItem(withRepresentedObject: configuration.fallbackCompressionAlgorithm)
default:
return 0
}
default:
break
}
return nil
}
func tableView(_ tableView: NSTableView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, row: Int) {
switch tableColumn?.identifier {
case Columns.value:
let rowObject = rows[row]
guard let menu = rowMenus[rowObject], let optionIndex = object as? Int else {
return
}
let optionObject = menu.item(at: optionIndex)?.representedObject
switch rowObject {
case .cipher:
configuration.cipher = optionObject as? OpenVPN.Cipher
case .digest:
configuration.digest = optionObject as? OpenVPN.Digest
case .compressionFraming:
guard let option = optionObject as? OpenVPN.CompressionFraming else {
return
}
configuration.compressionFraming = option
if option == .disabled {
configuration.compressionAlgorithm = .disabled
}
case .compressionAlgorithm:
guard let option = optionObject as? OpenVPN.CompressionAlgorithm else {
return
}
if configuration.compressionFraming == .disabled && option != .disabled {
configuration.compressionFraming = .compLZO
}
configuration.compressionAlgorithm = option
default:
break
}
delegate?.profileCustomization(self, didUpdateConfiguration: configuration)
default:
break
} }
} }
} }

View File

@ -8,7 +8,7 @@ $tunnelkit_specs = ['Protocols/OpenVPN', 'Extra/LZO']
def shared_pods def shared_pods
#pod_version $tunnelkit_name, $tunnelkit_specs, '~> 3.1.0' #pod_version $tunnelkit_name, $tunnelkit_specs, '~> 3.1.0'
pod_git $tunnelkit_name, $tunnelkit_specs, 'c15d6f5' pod_git $tunnelkit_name, $tunnelkit_specs, 'e388842'
#pod_path $tunnelkit_name, $tunnelkit_specs, '..' #pod_path $tunnelkit_name, $tunnelkit_specs, '..'
pod 'SSZipArchive' pod 'SSZipArchive'
pod 'Kvitto', :git => 'https://github.com/keeshux/Kvitto', :branch => 'enable-macos-spec' pod 'Kvitto', :git => 'https://github.com/keeshux/Kvitto', :branch => 'enable-macos-spec'

View File

@ -52,8 +52,8 @@ DEPENDENCIES:
- Kvitto (from `https://github.com/keeshux/Kvitto`, branch `enable-macos-spec`) - Kvitto (from `https://github.com/keeshux/Kvitto`, branch `enable-macos-spec`)
- MBProgressHUD - MBProgressHUD
- SSZipArchive - SSZipArchive
- TunnelKit/Extra/LZO (from `https://github.com/passepartoutvpn/tunnelkit`, commit `c15d6f5`) - TunnelKit/Extra/LZO (from `https://github.com/passepartoutvpn/tunnelkit`, commit `e388842`)
- TunnelKit/Protocols/OpenVPN (from `https://github.com/passepartoutvpn/tunnelkit`, commit `c15d6f5`) - TunnelKit/Protocols/OpenVPN (from `https://github.com/passepartoutvpn/tunnelkit`, commit `e388842`)
SPEC REPOS: SPEC REPOS:
https://github.com/cocoapods/specs.git: https://github.com/cocoapods/specs.git:
@ -71,7 +71,7 @@ EXTERNAL SOURCES:
:branch: enable-macos-spec :branch: enable-macos-spec
:git: https://github.com/keeshux/Kvitto :git: https://github.com/keeshux/Kvitto
TunnelKit: TunnelKit:
:commit: c15d6f5 :commit: e388842
:git: https://github.com/passepartoutvpn/tunnelkit :git: https://github.com/passepartoutvpn/tunnelkit
CHECKOUT OPTIONS: CHECKOUT OPTIONS:
@ -82,7 +82,7 @@ CHECKOUT OPTIONS:
:commit: e263fcd1f40a6a482a0f1e424ba98009c4ad2b96 :commit: e263fcd1f40a6a482a0f1e424ba98009c4ad2b96
:git: https://github.com/keeshux/Kvitto :git: https://github.com/keeshux/Kvitto
TunnelKit: TunnelKit:
:commit: c15d6f5 :commit: e388842
:git: https://github.com/passepartoutvpn/tunnelkit :git: https://github.com/passepartoutvpn/tunnelkit
SPEC CHECKSUMS: SPEC CHECKSUMS:
@ -95,6 +95,6 @@ SPEC CHECKSUMS:
SwiftyBeaver: 2e8acd6fc90c6d0a27055867a290794926d57c02 SwiftyBeaver: 2e8acd6fc90c6d0a27055867a290794926d57c02
TunnelKit: 2a6aadea2d772a2760b153aee27d1c334c9ca6db TunnelKit: 2a6aadea2d772a2760b153aee27d1c334c9ca6db
PODFILE CHECKSUM: 9751a898e23369673b1dfb0c7c7fde9834a55d53 PODFILE CHECKSUM: d6449ccbaad5d2ca50f6a27a651baaa17ef9db1a
COCOAPODS: 1.10.0 COCOAPODS: 1.10.0