Implement DNS protocol in network settings
Hide HTTPS/TLS before iOS 14 and macOS 11. Fixes #91
This commit is contained in:
parent
7e4a0cdbfd
commit
7763e368b9
|
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support `--data-ciphers` from OpenVPN 2.5 [tunnelkit#193](https://github.com/passepartoutvpn/tunnelkit/issues/193)
|
- Support `--data-ciphers` from OpenVPN 2.5 [tunnelkit#193](https://github.com/passepartoutvpn/tunnelkit/issues/193)
|
||||||
|
- Support DNS over HTTPS/TLS in "Network settings". [#91](https://github.com/passepartoutvpn/passepartout-apple/issues/91)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ import Convenience
|
||||||
private let log = SwiftyBeaver.self
|
private let log = SwiftyBeaver.self
|
||||||
|
|
||||||
private enum FieldTag: Int {
|
private enum FieldTag: Int {
|
||||||
|
case dnsCustom = 50
|
||||||
|
|
||||||
case dnsAddress = 100
|
case dnsAddress = 100
|
||||||
|
|
||||||
case dnsDomain = 200
|
case dnsDomain = 200
|
||||||
|
@ -76,7 +78,14 @@ class NetworkSettingsViewController: UITableViewController {
|
||||||
sections.append(.manualGateway)
|
sections.append(.manualGateway)
|
||||||
}
|
}
|
||||||
if networkChoices.dns != .server {
|
if networkChoices.dns != .server {
|
||||||
sections.append(.manualDNSServers)
|
sections.append(.manualDNSProtocol)
|
||||||
|
switch networkSettings.dnsProtocol {
|
||||||
|
case .https, .tls:
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
sections.append(.manualDNSServers)
|
||||||
|
}
|
||||||
sections.append(.manualDNSDomains)
|
sections.append(.manualDNSDomains)
|
||||||
}
|
}
|
||||||
if networkChoices.proxy != .server {
|
if networkChoices.proxy != .server {
|
||||||
|
@ -100,6 +109,16 @@ class NetworkSettingsViewController: UITableViewController {
|
||||||
model.set([.gatewayIPv4, .gatewayIPv6], forSection: .manualGateway)
|
model.set([.gatewayIPv4, .gatewayIPv6], forSection: .manualGateway)
|
||||||
model.set([.mtuBytes], forSection: .manualMTU)
|
model.set([.mtuBytes], forSection: .manualMTU)
|
||||||
|
|
||||||
|
var dnsProtocolRows: [RowType] = [.dnsProtocol]
|
||||||
|
switch networkSettings.dnsProtocol {
|
||||||
|
case .https, .tls:
|
||||||
|
dnsProtocolRows.append(.dnsCustom)
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
model.set(dnsProtocolRows, forSection: .manualDNSProtocol)
|
||||||
|
|
||||||
var dnsServers: [RowType] = Array(repeating: .dnsAddress, count: networkSettings.dnsServers?.count ?? 0)
|
var dnsServers: [RowType] = Array(repeating: .dnsAddress, count: networkSettings.dnsServers?.count ?? 0)
|
||||||
if networkChoices.dns == .manual {
|
if networkChoices.dns == .manual {
|
||||||
dnsServers.append(.dnsAddAddress)
|
dnsServers.append(.dnsAddAddress)
|
||||||
|
@ -122,11 +141,10 @@ class NetworkSettingsViewController: UITableViewController {
|
||||||
model.set(proxyRows, forSection: .manualProxy)
|
model.set(proxyRows, forSection: .manualProxy)
|
||||||
|
|
||||||
// refine sections before add (DNS is tricky)
|
// refine sections before add (DNS is tricky)
|
||||||
|
model.setHeader(L10n.Core.NetworkSettings.Dns.title, forSection: .manualDNSProtocol)
|
||||||
if !dnsServers.isEmpty {
|
if !dnsServers.isEmpty {
|
||||||
model.setHeader(L10n.Core.NetworkSettings.Dns.title, forSection: .manualDNSServers)
|
|
||||||
} else if !dnsDomains.isEmpty {
|
} else if !dnsDomains.isEmpty {
|
||||||
sections.removeAll { $0 == .manualDNSServers }
|
sections.removeAll { $0 == .manualDNSServers }
|
||||||
model.setHeader(L10n.Core.NetworkSettings.Dns.title, forSection: .manualDNSDomains)
|
|
||||||
} else {
|
} else {
|
||||||
sections.removeAll { $0 == .manualDNSServers }
|
sections.removeAll { $0 == .manualDNSServers }
|
||||||
sections.removeAll { $0 == .manualDNSDomains }
|
sections.removeAll { $0 == .manualDNSDomains }
|
||||||
|
@ -241,7 +259,21 @@ class NetworkSettingsViewController: UITableViewController {
|
||||||
|
|
||||||
let text = field.text ?? ""
|
let text = field.text ?? ""
|
||||||
|
|
||||||
if field.tag >= FieldTag.dnsAddress.rawValue && field.tag < FieldTag.dnsDomain.rawValue {
|
if field.tag == FieldTag.dnsCustom.rawValue {
|
||||||
|
switch networkSettings.dnsProtocol {
|
||||||
|
case .https:
|
||||||
|
guard let string = field.text, let url = URL(string: string) else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
networkSettings.dnsHTTPSURL = url
|
||||||
|
|
||||||
|
case .tls:
|
||||||
|
networkSettings.dnsTLSServerName = field.text
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if field.tag >= FieldTag.dnsAddress.rawValue && field.tag < FieldTag.dnsDomain.rawValue {
|
||||||
let i = field.tag - FieldTag.dnsAddress.rawValue
|
let i = field.tag - FieldTag.dnsAddress.rawValue
|
||||||
if let _ = networkSettings.dnsServers {
|
if let _ = networkSettings.dnsServers {
|
||||||
networkSettings.dnsServers?[i] = text
|
networkSettings.dnsServers?[i] = text
|
||||||
|
@ -304,6 +336,8 @@ extension NetworkSettingsViewController {
|
||||||
|
|
||||||
case manualGateway
|
case manualGateway
|
||||||
|
|
||||||
|
case manualDNSProtocol
|
||||||
|
|
||||||
case manualDNSServers
|
case manualDNSServers
|
||||||
|
|
||||||
case manualDNSDomains
|
case manualDNSDomains
|
||||||
|
@ -326,6 +360,10 @@ extension NetworkSettingsViewController {
|
||||||
|
|
||||||
case gatewayIPv6
|
case gatewayIPv6
|
||||||
|
|
||||||
|
case dnsProtocol
|
||||||
|
|
||||||
|
case dnsCustom
|
||||||
|
|
||||||
case dnsAddress
|
case dnsAddress
|
||||||
|
|
||||||
case dnsAddAddress
|
case dnsAddAddress
|
||||||
|
@ -409,6 +447,34 @@ extension NetworkSettingsViewController {
|
||||||
cell.isOn = networkSettings.gatewayPolicies?.contains(.IPv6) ?? false
|
cell.isOn = networkSettings.gatewayPolicies?.contains(.IPv6) ?? false
|
||||||
return cell
|
return cell
|
||||||
|
|
||||||
|
case .dnsProtocol:
|
||||||
|
let cell = Cells.setting.dequeue(from: tableView, for: indexPath)
|
||||||
|
cell.leftText = L10n.Core.Global.Captions.protocol
|
||||||
|
cell.rightText = (networkSettings.dnsProtocol ?? .fallback)?.description
|
||||||
|
return cell
|
||||||
|
|
||||||
|
case .dnsCustom:
|
||||||
|
let cell = Cells.field.dequeue(from: tableView, for: indexPath)
|
||||||
|
cell.caption = nil
|
||||||
|
cell.field.tag = FieldTag.dnsCustom.rawValue
|
||||||
|
switch networkSettings.dnsProtocol {
|
||||||
|
case .https:
|
||||||
|
cell.field.placeholder = AppConstants.Placeholders.dohURL
|
||||||
|
cell.field.text = networkSettings.dnsHTTPSURL?.absoluteString
|
||||||
|
|
||||||
|
case .tls:
|
||||||
|
cell.field.placeholder = AppConstants.Placeholders.dotServerName
|
||||||
|
cell.field.text = networkSettings.dnsTLSServerName
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cell.field.clearButtonMode = .always
|
||||||
|
cell.field.keyboardType = .asciiCapable
|
||||||
|
cell.captionWidth = 0.0
|
||||||
|
cell.delegate = self
|
||||||
|
return cell
|
||||||
|
|
||||||
case .dnsAddress:
|
case .dnsAddress:
|
||||||
let i = indexPath.row - Offsets.dnsAddress
|
let i = indexPath.row - Offsets.dnsAddress
|
||||||
|
|
||||||
|
@ -579,6 +645,24 @@ extension NetworkSettingsViewController {
|
||||||
}
|
}
|
||||||
navigationController?.pushViewController(vc, animated: true)
|
navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
|
case .dnsProtocol:
|
||||||
|
let vc = SingleOptionViewController<DNSProtocol>()
|
||||||
|
vc.applyTint(.current)
|
||||||
|
vc.title = (cell as? SettingTableViewCell)?.leftText
|
||||||
|
if #available(iOS 14, macOS 11, *) {
|
||||||
|
vc.options = [.plain, .https, .tls]
|
||||||
|
} else {
|
||||||
|
vc.options = [.plain]
|
||||||
|
}
|
||||||
|
vc.descriptionBlock = { $0.description }
|
||||||
|
|
||||||
|
vc.selectedOption = networkSettings.dnsProtocol ?? .fallback
|
||||||
|
vc.selectionBlock = { [weak self] in
|
||||||
|
self?.networkSettings.dnsProtocol = $0
|
||||||
|
self?.navigationController?.popViewController(animated: true)
|
||||||
|
}
|
||||||
|
navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
case .dnsAddAddress:
|
case .dnsAddAddress:
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
|
|
||||||
|
|
|
@ -136,14 +136,14 @@
|
||||||
<objects>
|
<objects>
|
||||||
<viewController title="DNS" id="mbI-Io-BZh" userLabel="DNS" customClass="DNSViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
|
<viewController title="DNS" id="mbI-Io-BZh" userLabel="DNS" customClass="DNSViewController" customModule="Passepartout" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<view key="view" id="We2-9p-1Vt">
|
<view key="view" id="We2-9p-1Vt">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="520" height="400"/>
|
<rect key="frame" x="0.0" y="0.0" width="514" height="440"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Zao-dc-fzq">
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Zao-dc-fzq">
|
||||||
<rect key="frame" x="0.0" y="20" width="500" height="360"/>
|
<rect key="frame" x="0.0" y="20" width="494" height="400"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bFA-yD-Roy">
|
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bFA-yD-Roy">
|
||||||
<rect key="frame" x="147" y="336" width="247" height="25"/>
|
<rect key="frame" x="147" y="376" width="247" height="25"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="240" id="euy-38-pqL"/>
|
<constraint firstAttribute="width" constant="240" id="euy-38-pqL"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
@ -163,28 +163,74 @@
|
||||||
</connections>
|
</connections>
|
||||||
</popUpButton>
|
</popUpButton>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Zfd-mA-qV9">
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Zfd-mA-qV9">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="500" height="330"/>
|
<rect key="frame" x="0.0" y="0.0" width="494" height="370"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
|
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CSz-iK-Imy">
|
||||||
|
<rect key="frame" x="147" y="346" width="247" height="25"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="width" constant="240" id="2y9-wd-q0g"/>
|
||||||
|
</constraints>
|
||||||
|
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="210-ZR-L2J" id="KD6-ly-ONG">
|
||||||
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="menu"/>
|
||||||
|
<menu key="menu" id="Kvm-gz-uaS">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Item 1" state="on" id="210-ZR-L2J"/>
|
||||||
|
<menuItem title="Item 2" id="sVf-le-KwE"/>
|
||||||
|
<menuItem title="Item 3" id="VbS-Rk-gsh"/>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</popUpButtonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="pickProtocol:" target="mbI-Io-BZh" id="ik0-nd-ODu"/>
|
||||||
|
</connections>
|
||||||
|
</popUpButton>
|
||||||
|
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="oRM-XY-fH6">
|
||||||
|
<rect key="frame" x="150" y="309" width="344" height="21"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="pa5-Wv-hRq">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="L6f-kb-mEG">
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="L6f-kb-mEG">
|
||||||
<rect key="frame" x="150" y="170" width="350" height="160"/>
|
<rect key="frame" x="150" y="170" width="344" height="160"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="160" id="zCq-d8-x9i"/>
|
<constraint firstAttribute="height" constant="160" id="zCq-d8-x9i"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</customView>
|
</customView>
|
||||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Baa-Z1-JJJ">
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Baa-Z1-JJJ">
|
||||||
<rect key="frame" x="150" y="0.0" width="350" height="160"/>
|
<rect key="frame" x="150" y="0.0" width="344" height="160"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="160" id="BTk-TZ-Dat"/>
|
<constraint firstAttribute="height" constant="160" id="BTk-TZ-Dat"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</customView>
|
</customView>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ef3-Zx-nCS">
|
||||||
|
<rect key="frame" x="-2" y="352" width="144" height="16"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="PROTO" id="lpP-C3-tYW">
|
||||||
|
<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>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="bottom" secondItem="Baa-Z1-JJJ" secondAttribute="bottom" id="DZf-vr-lkr"/>
|
<constraint firstItem="CSz-iK-Imy" firstAttribute="top" secondItem="Zfd-mA-qV9" secondAttribute="top" id="0rT-Xa-fsr"/>
|
||||||
|
<constraint firstItem="CSz-iK-Imy" firstAttribute="leading" secondItem="Baa-Z1-JJJ" secondAttribute="leading" id="4NK-b5-pOE"/>
|
||||||
|
<constraint firstItem="ef3-Zx-nCS" firstAttribute="leading" secondItem="Zfd-mA-qV9" secondAttribute="leading" id="9hc-Mm-7v7"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="Baa-Z1-JJJ" secondAttribute="trailing" id="Kc3-oq-1nC"/>
|
<constraint firstAttribute="trailing" secondItem="Baa-Z1-JJJ" secondAttribute="trailing" id="Kc3-oq-1nC"/>
|
||||||
<constraint firstItem="Baa-Z1-JJJ" firstAttribute="leading" secondItem="L6f-kb-mEG" secondAttribute="leading" id="OAq-vY-0dj"/>
|
<constraint firstItem="Baa-Z1-JJJ" firstAttribute="leading" secondItem="L6f-kb-mEG" secondAttribute="leading" id="OAq-vY-0dj"/>
|
||||||
|
<constraint firstItem="ef3-Zx-nCS" firstAttribute="centerY" secondItem="CSz-iK-Imy" secondAttribute="centerY" id="PLm-Ng-tlW"/>
|
||||||
|
<constraint firstItem="oRM-XY-fH6" firstAttribute="trailing" secondItem="L6f-kb-mEG" secondAttribute="trailing" id="U5i-6g-z66"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="L6f-kb-mEG" secondAttribute="trailing" id="Ufy-l9-JnV"/>
|
<constraint firstAttribute="trailing" secondItem="L6f-kb-mEG" secondAttribute="trailing" id="Ufy-l9-JnV"/>
|
||||||
<constraint firstItem="L6f-kb-mEG" firstAttribute="top" secondItem="Zfd-mA-qV9" secondAttribute="top" id="ht1-Z0-GZL"/>
|
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="CSz-iK-Imy" secondAttribute="trailing" id="Z6g-uk-L7s"/>
|
||||||
|
<constraint firstItem="L6f-kb-mEG" firstAttribute="top" secondItem="CSz-iK-Imy" secondAttribute="bottom" constant="20" id="Z8n-Jh-qIx"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="Baa-Z1-JJJ" secondAttribute="bottom" id="ciR-fE-0Bj"/>
|
||||||
|
<constraint firstItem="Baa-Z1-JJJ" firstAttribute="top" secondItem="oRM-XY-fH6" secondAttribute="bottom" priority="250" constant="10" id="ljr-hl-Iip"/>
|
||||||
|
<constraint firstItem="CSz-iK-Imy" firstAttribute="leading" secondItem="ef3-Zx-nCS" secondAttribute="trailing" constant="10" id="nOE-xl-CUa"/>
|
||||||
<constraint firstItem="Baa-Z1-JJJ" firstAttribute="top" secondItem="L6f-kb-mEG" secondAttribute="bottom" constant="10" id="qwn-Pc-7xS"/>
|
<constraint firstItem="Baa-Z1-JJJ" firstAttribute="top" secondItem="L6f-kb-mEG" secondAttribute="bottom" constant="10" id="qwn-Pc-7xS"/>
|
||||||
|
<constraint firstItem="oRM-XY-fH6" firstAttribute="leading" secondItem="L6f-kb-mEG" secondAttribute="leading" id="wE8-Cr-8A8"/>
|
||||||
|
<constraint firstItem="oRM-XY-fH6" firstAttribute="top" secondItem="L6f-kb-mEG" secondAttribute="top" id="xUI-3F-09L"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</customView>
|
</customView>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
@ -209,9 +255,14 @@
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<connections>
|
<connections>
|
||||||
|
<outlet property="constraintAddressesBottom" destination="qwn-Pc-7xS" id="f8K-7g-9N2"/>
|
||||||
<outlet property="constraintChoiceBottom" destination="0mN-72-zeu" id="Lf7-4v-Gae"/>
|
<outlet property="constraintChoiceBottom" destination="0mN-72-zeu" id="Lf7-4v-Gae"/>
|
||||||
|
<outlet property="constraintCustomBottom" destination="ljr-hl-Iip" id="JQK-dK-cqy"/>
|
||||||
<outlet property="constraintSettingsTop" destination="ymz-zd-mjc" id="sN1-KM-hgC"/>
|
<outlet property="constraintSettingsTop" destination="ymz-zd-mjc" id="sN1-KM-hgC"/>
|
||||||
|
<outlet property="labelDNSProtocol" destination="ef3-Zx-nCS" id="nec-BT-J2J"/>
|
||||||
<outlet property="popupChoice" destination="bFA-yD-Roy" id="lYe-Ho-P0K"/>
|
<outlet property="popupChoice" destination="bFA-yD-Roy" id="lYe-Ho-P0K"/>
|
||||||
|
<outlet property="popupDNSProtocol" destination="CSz-iK-Imy" id="gIh-zq-W3E"/>
|
||||||
|
<outlet property="textDNSCustom" destination="oRM-XY-fH6" id="rmb-Ue-MZR"/>
|
||||||
<outlet property="viewDNSAddresses" destination="L6f-kb-mEG" id="cbb-T7-MeD"/>
|
<outlet property="viewDNSAddresses" destination="L6f-kb-mEG" id="cbb-T7-MeD"/>
|
||||||
<outlet property="viewDNSDomains" destination="Baa-Z1-JJJ" id="msU-UP-bJZ"/>
|
<outlet property="viewDNSDomains" destination="Baa-Z1-JJJ" id="msU-UP-bJZ"/>
|
||||||
<outlet property="viewSettings" destination="Zfd-mA-qV9" id="831-9h-AXu"/>
|
<outlet property="viewSettings" destination="Zfd-mA-qV9" id="831-9h-AXu"/>
|
||||||
|
@ -219,7 +270,7 @@
|
||||||
</viewController>
|
</viewController>
|
||||||
<customObject id="Gxf-Bl-2bj" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="Gxf-Bl-2bj" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="579" y="2339"/>
|
<point key="canvasLocation" x="631" y="2362"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--Service View Controller-->
|
<!--Service View Controller-->
|
||||||
<scene sceneID="5Tf-QF-BT2">
|
<scene sceneID="5Tf-QF-BT2">
|
||||||
|
|
|
@ -5,11 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## 1.14.0 (2021-01-08)
|
## Unreleased
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Country flags in provider infrastructure menu.
|
- Country flags in provider infrastructure menu.
|
||||||
|
- Support DNS over HTTPS/TLS in "Network settings". [#91](https://github.com/passepartoutvpn/passepartout-apple/issues/91)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -25,32 +25,35 @@
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
import PassepartoutCore
|
import PassepartoutCore
|
||||||
|
import TunnelKit
|
||||||
|
|
||||||
class DNSViewController: NSViewController, ProfileCustomization {
|
class DNSViewController: NSViewController, ProfileCustomization {
|
||||||
private struct Templates {
|
|
||||||
static let server = "0.0.0.0"
|
|
||||||
|
|
||||||
static let domain = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBOutlet private weak var popupChoice: NSPopUpButton!
|
@IBOutlet private weak var popupChoice: NSPopUpButton!
|
||||||
|
|
||||||
@IBOutlet private weak var viewSettings: NSView!
|
@IBOutlet private weak var viewSettings: NSView!
|
||||||
|
|
||||||
|
@IBOutlet private weak var textDNSCustom: NSTextField!
|
||||||
|
|
||||||
@IBOutlet private weak var viewDNSAddresses: NSView!
|
@IBOutlet private weak var viewDNSAddresses: NSView!
|
||||||
|
|
||||||
@IBOutlet private weak var viewDNSDomains: NSView!
|
@IBOutlet private weak var viewDNSDomains: NSView!
|
||||||
|
|
||||||
|
@IBOutlet private weak var labelDNSProtocol: NSTextField!
|
||||||
|
|
||||||
|
@IBOutlet private weak var popupDNSProtocol: NSPopUpButton!
|
||||||
|
|
||||||
@IBOutlet private var constraintChoiceBottom: NSLayoutConstraint!
|
@IBOutlet private var constraintChoiceBottom: NSLayoutConstraint!
|
||||||
|
|
||||||
@IBOutlet private var constraintSettingsTop: NSLayoutConstraint!
|
@IBOutlet private var constraintSettingsTop: NSLayoutConstraint!
|
||||||
|
|
||||||
|
@IBOutlet private var constraintCustomBottom: NSLayoutConstraint!
|
||||||
|
|
||||||
|
@IBOutlet private var constraintAddressesBottom: NSLayoutConstraint!
|
||||||
|
|
||||||
private lazy var tableDNSDomains: TextTableView = .get()
|
private lazy var tableDNSDomains: TextTableView = .get()
|
||||||
|
|
||||||
private lazy var tableDNSAddresses: TextTableView = .get()
|
private lazy var tableDNSAddresses: TextTableView = .get()
|
||||||
|
|
||||||
private lazy var choices = NetworkChoice.choices(for: profile)
|
|
||||||
|
|
||||||
private lazy var currentChoice = profile?.networkChoices?.dns ?? ProfileNetworkChoices.with(profile: profile).dns
|
private lazy var currentChoice = profile?.networkChoices?.dns ?? ProfileNetworkChoices.with(profile: profile).dns
|
||||||
|
|
||||||
private lazy var clientNetworkSettings = profile?.clientNetworkSettings
|
private lazy var clientNetworkSettings = profile?.clientNetworkSettings
|
||||||
|
@ -66,6 +69,8 @@ class DNSViewController: NSViewController, ProfileCustomization {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
labelDNSProtocol.stringValue = L10n.Core.Global.Captions.protocol.asCaption
|
||||||
|
|
||||||
tableDNSAddresses.title = L10n.App.NetworkSettings.Dns.Cells.Addresses.title.asCaption
|
tableDNSAddresses.title = L10n.App.NetworkSettings.Dns.Cells.Addresses.title.asCaption
|
||||||
viewDNSAddresses.addSubview(tableDNSAddresses)
|
viewDNSAddresses.addSubview(tableDNSAddresses)
|
||||||
tableDNSAddresses.translatesAutoresizingMaskIntoConstraints = false
|
tableDNSAddresses.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
@ -89,31 +94,80 @@ class DNSViewController: NSViewController, ProfileCustomization {
|
||||||
loadSettings(from: currentChoice)
|
loadSettings(from: currentChoice)
|
||||||
|
|
||||||
popupChoice.removeAllItems()
|
popupChoice.removeAllItems()
|
||||||
for choice in choices {
|
popupDNSProtocol.removeAllItems()
|
||||||
popupChoice.addItem(withTitle: choice.description)
|
let menuChoice = NSMenu()
|
||||||
|
var indexOfChoice = 0
|
||||||
|
for (i, choice) in NetworkChoice.choices(for: profile).enumerated() {
|
||||||
|
let item = NSMenuItem(title: choice.description, action: nil, keyEquivalent: "")
|
||||||
|
item.representedObject = choice
|
||||||
|
menuChoice.addItem(item)
|
||||||
if choice == currentChoice {
|
if choice == currentChoice {
|
||||||
popupChoice.selectItem(at: popupChoice.numberOfItems - 1)
|
indexOfChoice = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tableDNSAddresses.rowTemplate = Templates.server
|
popupChoice.menu = menuChoice
|
||||||
tableDNSDomains.rowTemplate = Templates.domain
|
tableDNSAddresses.rowTemplate = AppConstants.Placeholders.dnsAddress
|
||||||
|
tableDNSDomains.rowTemplate = AppConstants.Placeholders.dnsDomain
|
||||||
|
let menuProtocol = NSMenu()
|
||||||
|
var availableProtocols: [DNSProtocol] = [.plain]
|
||||||
|
if #available(iOS 14, macOS 11, *) {
|
||||||
|
availableProtocols.append(.https)
|
||||||
|
availableProtocols.append(.tls)
|
||||||
|
}
|
||||||
|
var indexOfDNSProtocol = 0
|
||||||
|
for (i, proto) in availableProtocols.enumerated() {
|
||||||
|
let item = NSMenuItem(title: proto.description, action: nil, keyEquivalent: "")
|
||||||
|
item.representedObject = proto
|
||||||
|
menuProtocol.addItem(item)
|
||||||
|
if proto == networkSettings.dnsProtocol {
|
||||||
|
indexOfDNSProtocol = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
popupChoice.menu = menuChoice
|
||||||
|
popupChoice.selectItem(at: indexOfChoice)
|
||||||
|
popupDNSProtocol.menu = menuProtocol
|
||||||
|
popupDNSProtocol.selectItem(at: indexOfDNSProtocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Actions
|
// MARK: Actions
|
||||||
|
|
||||||
@IBAction private func pickChoice(_ sender: Any?) {
|
@IBAction private func pickChoice(_ sender: Any?) {
|
||||||
let choice = choices[popupChoice.indexOfSelectedItem]
|
guard let choice = popupChoice.selectedItem?.representedObject as? NetworkChoice else {
|
||||||
|
return
|
||||||
|
}
|
||||||
loadSettings(from: choice)
|
loadSettings(from: choice)
|
||||||
|
|
||||||
delegate?.profileCustomization(self, didUpdateDNS: choice, withManualSettings: networkSettings)
|
delegate?.profileCustomization(self, didUpdateDNS: choice, withManualSettings: networkSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBAction private func pickProtocol(_ sender: Any?) {
|
||||||
|
guard let choice = popupChoice.selectedItem?.representedObject as? NetworkChoice else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let proto = popupDNSProtocol.selectedItem?.representedObject as? DNSProtocol else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
networkSettings.dnsProtocol = proto
|
||||||
|
updateProtocolVisibility()
|
||||||
|
|
||||||
|
delegate?.profileCustomization(self, didUpdateDNS: choice, withManualSettings: networkSettings)
|
||||||
|
}
|
||||||
|
|
||||||
func commitManualSettings() {
|
func commitManualSettings() {
|
||||||
guard currentChoice == .manual else {
|
guard currentChoice == .manual else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
view.endEditing()
|
view.endEditing()
|
||||||
networkSettings.dnsServers = tableDNSAddresses.rows
|
switch networkSettings.dnsProtocol {
|
||||||
|
case .https:
|
||||||
|
networkSettings.dnsHTTPSURL = URL(string: textDNSCustom.stringValue)
|
||||||
|
|
||||||
|
case .tls:
|
||||||
|
networkSettings.dnsTLSServerName = textDNSCustom.stringValue
|
||||||
|
|
||||||
|
default:
|
||||||
|
networkSettings.dnsServers = tableDNSAddresses.rows
|
||||||
|
}
|
||||||
networkSettings.dnsSearchDomains = tableDNSDomains.rows
|
networkSettings.dnsSearchDomains = tableDNSDomains.rows
|
||||||
|
|
||||||
delegate?.profileCustomization(self, didUpdateDNS: .manual, withManualSettings: networkSettings)
|
delegate?.profileCustomization(self, didUpdateDNS: .manual, withManualSettings: networkSettings)
|
||||||
|
@ -145,5 +199,30 @@ class DNSViewController: NSViewController, ProfileCustomization {
|
||||||
constraintChoiceBottom.priority = isServer ? .defaultHigh : .defaultLow
|
constraintChoiceBottom.priority = isServer ? .defaultHigh : .defaultLow
|
||||||
constraintSettingsTop.priority = isServer ? .defaultLow : .defaultHigh
|
constraintSettingsTop.priority = isServer ? .defaultLow : .defaultHigh
|
||||||
viewSettings.isHidden = isServer
|
viewSettings.isHidden = isServer
|
||||||
|
|
||||||
|
updateProtocolVisibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateProtocolVisibility() {
|
||||||
|
let isCustom: Bool
|
||||||
|
switch networkSettings.dnsProtocol {
|
||||||
|
case .https:
|
||||||
|
isCustom = true
|
||||||
|
textDNSCustom.placeholderString = AppConstants.Placeholders.dohURL
|
||||||
|
textDNSCustom.stringValue = networkSettings.dnsHTTPSURL?.absoluteString ?? ""
|
||||||
|
|
||||||
|
case .tls:
|
||||||
|
isCustom = true
|
||||||
|
textDNSCustom.placeholderString = AppConstants.Placeholders.dotServerName
|
||||||
|
textDNSCustom.stringValue = networkSettings.dnsTLSServerName ?? ""
|
||||||
|
|
||||||
|
default:
|
||||||
|
isCustom = false
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintCustomBottom.priority = isCustom ? .defaultHigh : .defaultLow
|
||||||
|
constraintAddressesBottom.priority = isCustom ? .defaultLow : .defaultHigh
|
||||||
|
textDNSCustom.isHidden = !isCustom
|
||||||
|
viewDNSAddresses.isHidden = isCustom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,8 +201,11 @@ extension ProfileCustomizationContainerViewController: ProfileCustomizationDeleg
|
||||||
|
|
||||||
func profileCustomization(_ profileCustomization: ProfileCustomization, didUpdateDNS choice: NetworkChoice, withManualSettings newSettings: ProfileNetworkSettings) {
|
func profileCustomization(_ profileCustomization: ProfileCustomization, didUpdateDNS choice: NetworkChoice, withManualSettings newSettings: ProfileNetworkSettings) {
|
||||||
pendingChoices?.dns = choice
|
pendingChoices?.dns = choice
|
||||||
pendingManualNetworkSettings.dnsSearchDomains = newSettings.dnsSearchDomains
|
pendingManualNetworkSettings.dnsProtocol = newSettings.dnsProtocol
|
||||||
|
pendingManualNetworkSettings.dnsHTTPSURL = newSettings.dnsHTTPSURL
|
||||||
|
pendingManualNetworkSettings.dnsTLSServerName = newSettings.dnsTLSServerName
|
||||||
pendingManualNetworkSettings.dnsServers = newSettings.dnsServers
|
pendingManualNetworkSettings.dnsServers = newSettings.dnsServers
|
||||||
|
pendingManualNetworkSettings.dnsSearchDomains = newSettings.dnsSearchDomains
|
||||||
}
|
}
|
||||||
|
|
||||||
func profileCustomization(_ profileCustomization: ProfileCustomization, didUpdateProxy choice: NetworkChoice, withManualSettings newSettings: ProfileNetworkSettings) {
|
func profileCustomization(_ profileCustomization: ProfileCustomization, didUpdateProxy choice: NetworkChoice, withManualSettings newSettings: ProfileNetworkSettings) {
|
||||||
|
|
|
@ -79,6 +79,7 @@ class ProxyViewController: NSViewController, ProfileCustomization {
|
||||||
tableProxyBypass.leftAnchor.constraint(equalTo: viewProxyBypass.leftAnchor),
|
tableProxyBypass.leftAnchor.constraint(equalTo: viewProxyBypass.leftAnchor),
|
||||||
tableProxyBypass.rightAnchor.constraint(equalTo: viewProxyBypass.rightAnchor),
|
tableProxyBypass.rightAnchor.constraint(equalTo: viewProxyBypass.rightAnchor),
|
||||||
])
|
])
|
||||||
|
tableProxyBypass.rowTemplate = Templates.bypass
|
||||||
|
|
||||||
loadSettings(from: currentChoice)
|
loadSettings(from: currentChoice)
|
||||||
|
|
||||||
|
@ -89,7 +90,6 @@ class ProxyViewController: NSViewController, ProfileCustomization {
|
||||||
popupChoice.selectItem(at: popupChoice.numberOfItems - 1)
|
popupChoice.selectItem(at: popupChoice.numberOfItems - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tableProxyBypass.rowTemplate = Templates.bypass
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Actions
|
// MARK: Actions
|
||||||
|
|
|
@ -268,6 +268,22 @@ public class AppConstants {
|
||||||
public static let api = githubRaw(repo: "api")
|
public static let api = githubRaw(repo: "api")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct Placeholders {
|
||||||
|
public static let empty = ""
|
||||||
|
|
||||||
|
public static let address = "0.0.0.0"
|
||||||
|
|
||||||
|
public static let hostname = "example.com"
|
||||||
|
|
||||||
|
public static let dohURL = "https://example.com/dns-query"
|
||||||
|
|
||||||
|
public static let dotServerName = hostname
|
||||||
|
|
||||||
|
public static let dnsAddress = address
|
||||||
|
|
||||||
|
public static let dnsDomain = empty
|
||||||
|
}
|
||||||
|
|
||||||
public struct Credits {
|
public struct Credits {
|
||||||
public static let author = "Davide De Rosa"
|
public static let author = "Davide De Rosa"
|
||||||
|
|
||||||
|
|
|
@ -75,8 +75,14 @@ public class ProfileNetworkSettings: Codable, CustomStringConvertible {
|
||||||
|
|
||||||
public var gatewayPolicies: [OpenVPN.RoutingPolicy]?
|
public var gatewayPolicies: [OpenVPN.RoutingPolicy]?
|
||||||
|
|
||||||
|
public var dnsProtocol: DNSProtocol?
|
||||||
|
|
||||||
public var dnsServers: [String]?
|
public var dnsServers: [String]?
|
||||||
|
|
||||||
|
public var dnsHTTPSURL: URL?
|
||||||
|
|
||||||
|
public var dnsTLSServerName: String?
|
||||||
|
|
||||||
public var dnsSearchDomains: [String]?
|
public var dnsSearchDomains: [String]?
|
||||||
|
|
||||||
public var proxyAddress: String?
|
public var proxyAddress: String?
|
||||||
|
@ -102,8 +108,11 @@ public class ProfileNetworkSettings: Codable, CustomStringConvertible {
|
||||||
|
|
||||||
public init(from configuration: OpenVPN.Configuration) {
|
public init(from configuration: OpenVPN.Configuration) {
|
||||||
gatewayPolicies = configuration.routingPolicies
|
gatewayPolicies = configuration.routingPolicies
|
||||||
dnsSearchDomains = configuration.searchDomains
|
dnsProtocol = configuration.dnsProtocol
|
||||||
dnsServers = configuration.dnsServers
|
dnsServers = configuration.dnsServers
|
||||||
|
dnsHTTPSURL = configuration.dnsHTTPSURL
|
||||||
|
dnsTLSServerName = configuration.dnsTLSServerName
|
||||||
|
dnsSearchDomains = configuration.searchDomains
|
||||||
proxyAddress = configuration.httpProxy?.address
|
proxyAddress = configuration.httpProxy?.address
|
||||||
proxyPort = configuration.httpProxy?.port
|
proxyPort = configuration.httpProxy?.port
|
||||||
proxyAutoConfigurationURL = configuration.proxyAutoConfigurationURL
|
proxyAutoConfigurationURL = configuration.proxyAutoConfigurationURL
|
||||||
|
@ -123,8 +132,11 @@ public class ProfileNetworkSettings: Codable, CustomStringConvertible {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func copyDNS(from settings: ProfileNetworkSettings) {
|
public func copyDNS(from settings: ProfileNetworkSettings) {
|
||||||
dnsSearchDomains = settings.dnsSearchDomains
|
dnsProtocol = settings.dnsProtocol
|
||||||
dnsServers = settings.dnsServers?.filter { !$0.isEmpty }
|
dnsServers = settings.dnsServers?.filter { !$0.isEmpty }
|
||||||
|
dnsHTTPSURL = settings.dnsHTTPSURL
|
||||||
|
dnsTLSServerName = settings.dnsTLSServerName
|
||||||
|
dnsSearchDomains = settings.dnsSearchDomains
|
||||||
}
|
}
|
||||||
|
|
||||||
public func copyProxy(from settings: ProfileNetworkSettings) {
|
public func copyProxy(from settings: ProfileNetworkSettings) {
|
||||||
|
@ -143,7 +155,7 @@ public class ProfileNetworkSettings: Codable, CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
let comps: [String] = [
|
let comps: [String] = [
|
||||||
"gw: \(gatewayPolicies?.description ?? "")",
|
"gw: \(gatewayPolicies?.description ?? "")",
|
||||||
"dns: {domains: \(dnsSearchDomains?.description ?? "[]"), servers: \(dnsServers?.description ?? "[]")}",
|
"dns: {protocol: \(dnsProtocol ?? .fallback), https: \(dnsHTTPSURL?.absoluteString ?? ""), tls: \(dnsTLSServerName?.description ?? ""), servers: \(dnsServers?.description ?? "[]"), domains: \(dnsSearchDomains?.description ?? "[]")}",
|
||||||
"proxy: {address: \(proxyAddress ?? ""), port: \(proxyPort?.description ?? ""), PAC: \(proxyAutoConfigurationURL?.absoluteString ?? ""), bypass: \(proxyBypassDomains?.description ?? "[]")}",
|
"proxy: {address: \(proxyAddress ?? ""), port: \(proxyPort?.description ?? ""), PAC: \(proxyAutoConfigurationURL?.absoluteString ?? ""), bypass: \(proxyBypassDomains?.description ?? "[]")}",
|
||||||
"mtu: {bytes: \(mtuBytes?.description ?? "default")}"
|
"mtu: {bytes: \(mtuBytes?.description ?? "default")}"
|
||||||
]
|
]
|
||||||
|
@ -171,11 +183,17 @@ extension OpenVPN.ConfigurationBuilder {
|
||||||
break
|
break
|
||||||
|
|
||||||
case .server:
|
case .server:
|
||||||
|
dnsProtocol = nil
|
||||||
dnsServers = nil
|
dnsServers = nil
|
||||||
|
dnsHTTPSURL = nil
|
||||||
|
dnsTLSServerName = nil
|
||||||
searchDomains = nil
|
searchDomains = nil
|
||||||
|
|
||||||
case .manual:
|
case .manual:
|
||||||
|
dnsProtocol = settings.dnsProtocol
|
||||||
dnsServers = settings.dnsServers?.filter { !$0.isEmpty }
|
dnsServers = settings.dnsServers?.filter { !$0.isEmpty }
|
||||||
|
dnsHTTPSURL = settings.dnsHTTPSURL
|
||||||
|
dnsTLSServerName = settings.dnsTLSServerName
|
||||||
searchDomains = settings.dnsSearchDomains
|
searchDomains = settings.dnsSearchDomains
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
Podfile
2
Podfile
|
@ -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, 'e388842'
|
pod_git $tunnelkit_name, $tunnelkit_specs, '5014e65'
|
||||||
#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'
|
||||||
|
|
10
Podfile.lock
10
Podfile.lock
|
@ -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 `e388842`)
|
- TunnelKit/Extra/LZO (from `https://github.com/passepartoutvpn/tunnelkit`, commit `5014e65`)
|
||||||
- TunnelKit/Protocols/OpenVPN (from `https://github.com/passepartoutvpn/tunnelkit`, commit `e388842`)
|
- TunnelKit/Protocols/OpenVPN (from `https://github.com/passepartoutvpn/tunnelkit`, commit `5014e65`)
|
||||||
|
|
||||||
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: e388842
|
:commit: '5014e65'
|
||||||
: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: e388842
|
:commit: '5014e65'
|
||||||
: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: d6449ccbaad5d2ca50f6a27a651baaa17ef9db1a
|
PODFILE CHECKSUM: 90f34e726cde9553212321b6f95cd79f284e0dca
|
||||||
|
|
||||||
COCOAPODS: 1.10.0
|
COCOAPODS: 1.10.0
|
||||||
|
|
Loading…
Reference in New Issue