Create cross-platform SwiftUI Demo

- Autogen apps/extensions Info.plist
- Avoid . in bundle identifiers of extensions
- Normalize demo version
- Beware of extension runpath
- Drop host app

Closes #399
This commit is contained in:
Davide De Rosa 2023-12-16 20:50:39 +01:00
parent 4849ab39ff
commit a353050af1
No known key found for this signature in database
GPG Key ID: A48836171C759F5E
57 changed files with 1630 additions and 2693 deletions

View File

@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for Apple TV. [#337](https://github.com/passepartoutvpn/tunnelkit/issues/337)
- Attach user data to VPN configuration. [#400](https://github.com/passepartoutvpn/tunnelkit/pull/400)
### Changed
- Demo rewritten in SwiftUI. [#399](https://github.com/passepartoutvpn/tunnelkit/issues/399)
## 6.2.0 (2023-12-14)
### Changed

View File

@ -2,26 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>TunnelKitDemoTunnel</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>5.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
@ -29,7 +9,5 @@
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
</dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) 2023 Davide De Rosa. All rights reserved.</string>
</dict>
</plist>

View File

@ -28,6 +28,23 @@ import TunnelKitCore
import TunnelKitOpenVPN
import TunnelKitWireGuard
#if os(macOS)
let appGroup = "DTDYD63ZX9.group.com.algoritmico.TunnelKit.Demo"
private let bundleComponent = "macos"
#elseif os(iOS)
let appGroup = "group.com.algoritmico.TunnelKit.Demo"
private let bundleComponent = "ios"
#else
let appGroup = "group.com.algoritmico.TunnelKit.Demo"
private let bundleComponent = "tvos"
#endif
enum TunnelIdentifier {
static let openVPN = "com.algoritmico.\(bundleComponent).TunnelKit.Demo.OpenVPN-Tunnel"
static let wireGuard = "com.algoritmico.\(bundleComponent).TunnelKit.Demo.WireGuard-Tunnel"
}
extension OpenVPN {
struct DemoConfiguration {
static let ca = OpenVPN.CryptoContainer(pem: """

View File

@ -1,8 +1,8 @@
//
// AppDelegate.swift
// DemoApp.swift
// Demo
//
// Created by Davide De Rosa on 10/15/17.
// Created by Davide De Rosa on 12/16/23.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
@ -23,25 +23,13 @@
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import Cocoa
import SwiftyBeaver
import SwiftUI
private let log = SwiftyBeaver.self
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let logDestination = ConsoleDestination()
logDestination.minLevel = .debug
logDestination.format = "$DHH:mm:ss$d $L $N.$F:$l - $M"
log.addDestination(logDestination)
// Insert code here to initialize your application
@main
struct DemoApp: App {
var body: some Scene {
WindowGroup {
DemoView()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}

View File

@ -0,0 +1,82 @@
//
// DemoView.swift
// Demo
//
// Created by Davide De Rosa on 12/16/23.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import SwiftUI
import TunnelKitCore
import TunnelKitManager
struct DemoView: View {
private let vpn = NetworkExtensionVPN()
private let keychain = Keychain(group: appGroup)
private let notifier = Notifier()
@State private var vpnStatus: VPNStatus = .disconnected
var body: some View {
TabView {
OpenVPNView(vpn: vpn, vpnStatus: vpnStatus, keychain: keychain)
.tabItem {
Text("OpenVPN")
}
WireGuardView(vpn: vpn, vpnStatus: vpnStatus)
.tabItem {
Text("WireGuard")
}
}
.task {
notifier.didChange = didChangeStatus
notifier.registerNotifications()
await vpn.prepare()
}
}
}
private extension DemoView {
private func didChangeStatus(_ vpnStatus: VPNStatus) {
self.vpnStatus = vpnStatus
}
}
extension VPNStatus {
func actionText(for vpnStatus: VPNStatus) -> String {
switch vpnStatus {
case .connected, .connecting:
return "Disconnect"
case .disconnected:
return "Connect"
case .disconnecting:
return "Disconnecting"
}
}
}
#Preview {
DemoView()
}

View File

@ -0,0 +1,70 @@
//
// Notifier.swift
// Demo
//
// Created by Davide De Rosa on 12/16/23.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import Foundation
import TunnelKitManager
final class Notifier {
var didChange: ((VPNStatus) -> Void)?
private var didRegister = false
init() {
//
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func registerNotifications() {
guard !didRegister else {
return
}
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNStatusDidChange(notification:)),
name: VPNNotification.didChangeStatus,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNDidFail(notification:)),
name: VPNNotification.didFail,
object: nil
)
didRegister = true
}
@objc private func VPNStatusDidChange(notification: Notification) {
let vpnStatus = notification.vpnStatus
print("VPNStatusDidChange: \(vpnStatus)")
didChange?(vpnStatus)
}
@objc private func VPNDidFail(notification: Notification) {
print("VPNStatusDidFail: \(notification.vpnError.localizedDescription)")
}
}

View File

@ -0,0 +1,126 @@
//
// OpenVPNView.swift
// Demo
//
// Created by Davide De Rosa on 12/16/23.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import SwiftUI
import TunnelKitOpenVPN
import TunnelKitManager
struct OpenVPNView: View {
let vpn: NetworkExtensionVPN
let vpnStatus: VPNStatus
let keychain: Keychain
@State private var server = "nl-free-50"
@State private var domain = "protonvpn.net"
@State private var portText = "80"
@State private var username = ""
@State private var password = ""
var body: some View {
List {
formView
buttonView
}
}
}
private extension OpenVPNView {
var formView: some View {
Section {
TextField("Server", text: $server)
TextField("Domain", text: $domain)
TextField("Port", text: $portText)
TextField("Username", text: $username)
TextField("Password", text: $password)
}
}
var buttonView: some View {
Section {
Button(vpnStatus.actionText(for: vpnStatus)) {
switch vpnStatus {
case .disconnected:
connect()
case .connected, .connecting, .disconnecting:
disconnect()
}
}
}
}
func connect() {
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
let port = UInt16(portText)!
let credentials = OpenVPN.Credentials(username, password)
var builder = OpenVPN.DemoConfiguration.make(params: .init(
title: "TunnelKit.OpenVPN",
appGroup: appGroup,
hostname: hostname,
port: port,
socketType: .udp
))
builder.username = credentials.username
let passwordReference: Data
do {
passwordReference = try keychain.set(password: credentials.password, for: credentials.username, context: TunnelIdentifier.openVPN)
} catch {
print("Keychain failure: \(error)")
return
}
let cfg = builder
Task {
var extra = NetworkExtensionExtra()
extra.passwordReference = passwordReference
try await vpn.reconnect(
TunnelIdentifier.openVPN,
configuration: cfg,
extra: extra,
after: .seconds(2)
)
}
}
func disconnect() {
Task {
await vpn.disconnect()
}
}
}
#Preview {
OpenVPNView(vpn: NetworkExtensionVPN(),
vpnStatus: .disconnected,
keychain: Keychain(group: appGroup))
}

View File

@ -0,0 +1,112 @@
//
// WireGuardView.swift
// Demo
//
// Created by Davide De Rosa on 12/16/23.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import SwiftUI
import TunnelKitManager
import TunnelKitWireGuard
struct WireGuardView: View {
let vpn: NetworkExtensionVPN
let vpnStatus: VPNStatus
@State private var clientPrivateKey = ""
@State private var clientAddress = "192.168.30.2/32"
@State private var serverPublicKey = ""
@State private var serverAddress = ""
@State private var serverPort = ""
var body: some View {
List {
formView
buttonView
}
}
}
private extension WireGuardView {
var formView: some View {
Section {
TextField("Client private key", text: $clientPrivateKey)
TextField("Client address", text: $clientAddress)
TextField("Server public key", text: $serverPublicKey)
TextField("Server address", text: $serverAddress)
TextField("Server port", text: $serverPort)
}
}
var buttonView: some View {
Section {
Button(vpnStatus.actionText(for: vpnStatus)) {
switch vpnStatus {
case .disconnected:
connect()
case .connected, .connecting, .disconnecting:
disconnect()
}
}
}
}
func connect() {
guard let cfg = WireGuard.DemoConfiguration.make(params: .init(
title: "TunnelKit.WireGuard",
appGroup: appGroup,
clientPrivateKey: clientPrivateKey,
clientAddress: clientAddress,
serverPublicKey: serverPublicKey,
serverAddress: serverAddress,
serverPort: serverPort
)) else {
print("Configuration incomplete")
return
}
Task {
try await vpn.reconnect(
TunnelIdentifier.wireGuard,
configuration: cfg,
extra: nil,
after: .seconds(2)
)
}
}
func disconnect() {
Task {
await vpn.disconnect()
}
}
}
#Preview {
WireGuardView(vpn: NetworkExtensionVPN(),
vpnStatus: .disconnected)
}

View File

@ -1,68 +0,0 @@
//
// AppDelegate.swift
// Demo
//
// Created by Davide De Rosa on 2/11/17.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import NetworkExtension
import SwiftyBeaver
private let log = SwiftyBeaver.self
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let logDestination = ConsoleDestination()
logDestination.minLevel = .debug
logDestination.format = "$DHH:mm:ss$d $L $N.$F:$l - $M"
log.addDestination(logDestination)
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

View File

@ -1,322 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="26T-Cw-BJR">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Wire Guard View Controller-->
<scene sceneID="nUZ-T3-AkK">
<objects>
<viewController id="b1w-nH-Bgg" customClass="WireGuardViewController" customModule="TunnelKitDemo_iOS" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="YGc-BB-45n"/>
<viewControllerLayoutGuide type="bottom" id="Rh4-AH-xlg"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="yMG-68-KNY">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dJK-qq-9T9">
<rect key="frame" x="0.0" y="44" width="375" height="623"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="dIW-lB-7WF">
<rect key="frame" x="20" y="128" width="335" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet" secureTextEntry="YES"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="IeJ-5Y-kdR">
<rect key="frame" x="20" y="74" width="335" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="NL5-P8-ffu">
<rect key="frame" x="20" y="182" width="245" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="neV-25-hSD">
<rect key="frame" x="275" y="182" width="80" height="34"/>
<constraints>
<constraint firstAttribute="width" constant="80" id="yDW-rv-uJL"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="IeJ-5Y-kdR" firstAttribute="leading" secondItem="dIW-lB-7WF" secondAttribute="leading" id="O2S-h8-CCf"/>
<constraint firstItem="dIW-lB-7WF" firstAttribute="top" secondItem="IeJ-5Y-kdR" secondAttribute="bottom" constant="20" id="cuT-Ax-tG2"/>
<constraint firstItem="neV-25-hSD" firstAttribute="centerY" secondItem="NL5-P8-ffu" secondAttribute="centerY" id="kYa-bZ-Zcu"/>
<constraint firstItem="neV-25-hSD" firstAttribute="leading" secondItem="NL5-P8-ffu" secondAttribute="trailing" constant="10" id="m0M-df-psQ"/>
<constraint firstItem="NL5-P8-ffu" firstAttribute="top" secondItem="dIW-lB-7WF" secondAttribute="bottom" constant="20" id="rZe-1R-kkn"/>
<constraint firstItem="IeJ-5Y-kdR" firstAttribute="trailing" secondItem="dIW-lB-7WF" secondAttribute="trailing" id="vhb-Lu-oGq"/>
</constraints>
</view>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="ilf-E0-oHx">
<rect key="frame" x="20" y="64" width="335" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Qvn-sk-hgq">
<rect key="frame" x="20" y="280" width="175" height="70"/>
<fontDescription key="fontDescription" type="system" pointSize="48"/>
<state key="normal" title="Connect"/>
<connections>
<action selector="connectionClicked:" destination="BYZ-38-t0r" eventType="touchUpInside" id="9zR-rY-dbb"/>
<action selector="connectionClicked:" destination="b1w-nH-Bgg" eventType="touchUpInside" id="S1R-FS-6pE"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="ilf-E0-oHx" secondAttribute="trailing" constant="20" id="4kR-Vq-VaE"/>
<constraint firstItem="neV-25-hSD" firstAttribute="trailing" secondItem="ilf-E0-oHx" secondAttribute="trailing" id="9ix-OI-Xs8"/>
<constraint firstItem="IeJ-5Y-kdR" firstAttribute="trailing" secondItem="ilf-E0-oHx" secondAttribute="trailing" id="GtB-dJ-eSM"/>
<constraint firstItem="NL5-P8-ffu" firstAttribute="leading" secondItem="ilf-E0-oHx" secondAttribute="leading" id="JVf-BM-EE5"/>
<constraint firstItem="Qvn-sk-hgq" firstAttribute="leading" secondItem="NL5-P8-ffu" secondAttribute="leading" id="MT8-V0-fRl"/>
<constraint firstItem="IeJ-5Y-kdR" firstAttribute="top" secondItem="ilf-E0-oHx" secondAttribute="bottom" constant="20" id="NsQ-7Z-5Wg"/>
<constraint firstItem="Rh4-AH-xlg" firstAttribute="top" secondItem="dJK-qq-9T9" secondAttribute="bottom" id="PL0-AU-ktf"/>
<constraint firstItem="dJK-qq-9T9" firstAttribute="leading" secondItem="yMG-68-KNY" secondAttribute="leading" id="Rmv-Oh-00v"/>
<constraint firstAttribute="trailing" secondItem="dJK-qq-9T9" secondAttribute="trailing" id="Tod-2R-cCt"/>
<constraint firstItem="dIW-lB-7WF" firstAttribute="leading" secondItem="ilf-E0-oHx" secondAttribute="leading" id="YD7-ZD-fCT"/>
<constraint firstItem="ilf-E0-oHx" firstAttribute="top" secondItem="YGc-BB-45n" secondAttribute="bottom" constant="20" id="afY-J4-d2k"/>
<constraint firstItem="ilf-E0-oHx" firstAttribute="leading" secondItem="yMG-68-KNY" secondAttribute="leading" constant="20" id="g8h-Jz-0oQ"/>
<constraint firstItem="IeJ-5Y-kdR" firstAttribute="leading" secondItem="ilf-E0-oHx" secondAttribute="leading" id="lLd-HB-IXI"/>
<constraint firstItem="Qvn-sk-hgq" firstAttribute="top" secondItem="NL5-P8-ffu" secondAttribute="bottom" constant="20" id="p7g-zX-vBF"/>
<constraint firstItem="dIW-lB-7WF" firstAttribute="trailing" secondItem="ilf-E0-oHx" secondAttribute="trailing" id="rLo-kl-jUg"/>
<constraint firstItem="dJK-qq-9T9" firstAttribute="top" secondItem="YGc-BB-45n" secondAttribute="bottom" id="tQl-FY-23s"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="bbk-hQ-5N6"/>
<connections>
<outlet property="buttonConnection" destination="Qvn-sk-hgq" id="nWL-K1-VGY"/>
<outlet property="textAddress" destination="ilf-E0-oHx" id="2ej-fm-Bop"/>
<outlet property="textClientPrivateKey" destination="IeJ-5Y-kdR" id="eTK-WO-g4M"/>
<outlet property="textServerAddress" destination="NL5-P8-ffu" id="S6t-eV-M8h"/>
<outlet property="textServerPort" destination="neV-25-hSD" id="IeB-M1-cEt"/>
<outlet property="textServerPublicKey" destination="dIW-lB-7WF" id="aGG-DX-bTk"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0Er-HZ-cLv" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="140" y="863"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="msq-sC-Gx0">
<objects>
<navigationController id="26T-Cw-BJR" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="WTG-Q2-AEi">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="oPT-bs-cQ9" kind="relationship" relationship="rootViewController" id="ljP-y1-Mde"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="uh4-Vj-Jlw" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1516" y="411"/>
</scene>
<!--TunnelKit-->
<scene sceneID="yt7-nG-u2w">
<objects>
<tableViewController id="oPT-bs-cQ9" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" id="mcO-tP-Zgf">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<sections>
<tableViewSection id="NMC-O0-zXz">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="N8j-VD-UD4" style="IBUITableViewCellStyleDefault" id="IFH-Qn-oXj">
<rect key="frame" x="0.0" y="44.5" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="IFH-Qn-oXj" id="DGt-4C-TmV">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="OpenVPN" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="N8j-VD-UD4">
<rect key="frame" x="16" y="0.0" width="325.5" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="BYZ-38-t0r" kind="show" id="UUt-jB-TTT"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="gst-1a-WPM" style="IBUITableViewCellStyleDefault" id="rX5-QA-nhj">
<rect key="frame" x="0.0" y="88" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="rX5-QA-nhj" id="evF-dj-ePY">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="WireGuard" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="gst-1a-WPM">
<rect key="frame" x="16" y="0.0" width="325.5" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="b1w-nH-Bgg" kind="show" id="2BK-GQ-yWH"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="oPT-bs-cQ9" id="epg-kz-wgw"/>
<outlet property="delegate" destination="oPT-bs-cQ9" id="ETI-HH-zua"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="TunnelKit" id="Nrl-LP-Alb"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Qkt-Qp-9ol" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-726" y="411"/>
</scene>
<!--OpenVPN View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="OpenVPNViewController" customModule="TunnelKitDemo_iOS" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="bc6-yT-aty">
<rect key="frame" x="20" y="226" width="335" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet" secureTextEntry="YES"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="ONL-vF-iUY">
<rect key="frame" x="20" y="64" width="335" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="dQS-Ma-dYP">
<rect key="frame" x="20" y="172" width="335" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="XwE-sE-aPN">
<rect key="frame" x="20" y="118" width="245" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7LH-tE-it9">
<rect key="frame" x="275" y="118" width="80" height="34"/>
<constraints>
<constraint firstAttribute="width" constant="80" id="aWP-Ug-b9B"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Teo-8d-LYJ">
<rect key="frame" x="20" y="280" width="276" height="70"/>
<fontDescription key="fontDescription" type="system" pointSize="48"/>
<state key="normal" title="Connect"/>
<connections>
<action selector="connectionClicked:" destination="BYZ-38-t0r" eventType="touchUpInside" id="gmm-j5-8Zz"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="TCP" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sA4-W9-jxo">
<rect key="frame" x="312" y="280" width="37.5" height="24"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="WZf-S5-SqC">
<rect key="frame" x="306" y="319" width="51" height="31"/>
<connections>
<action selector="tcpClicked:" destination="BYZ-38-t0r" eventType="valueChanged" id="ZJI-Jw-pow"/>
</connections>
</switch>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6dU-fF-FSg">
<rect key="frame" x="20" y="350" width="335" height="41"/>
<fontDescription key="fontDescription" type="system" pointSize="24"/>
<state key="normal" title="See log"/>
<connections>
<action selector="displayLog" destination="BYZ-38-t0r" eventType="touchUpInside" id="0ZH-zK-igi"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="UNN-CR-rdr">
<rect key="frame" x="20" y="411" width="335" height="236"/>
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
<fontDescription key="fontDescription" name="CourierNewPSMT" family="Courier New" pointSize="17"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="UNN-CR-rdr" firstAttribute="top" secondItem="6dU-fF-FSg" secondAttribute="bottom" constant="20" id="03h-H3-dSN"/>
<constraint firstItem="7LH-tE-it9" firstAttribute="centerY" secondItem="XwE-sE-aPN" secondAttribute="centerY" id="0wJ-c9-Gcy"/>
<constraint firstItem="Teo-8d-LYJ" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" constant="20" id="2uM-A3-gZl"/>
<constraint firstItem="dQS-Ma-dYP" firstAttribute="leading" secondItem="bc6-yT-aty" secondAttribute="leading" id="3Ra-eC-A82"/>
<constraint firstItem="bc6-yT-aty" firstAttribute="top" secondItem="dQS-Ma-dYP" secondAttribute="bottom" constant="20" id="C2Y-oZ-jdP"/>
<constraint firstItem="WZf-S5-SqC" firstAttribute="bottom" secondItem="Teo-8d-LYJ" secondAttribute="bottom" id="HGt-O3-p5F"/>
<constraint firstItem="ONL-vF-iUY" firstAttribute="trailing" secondItem="bc6-yT-aty" secondAttribute="trailing" id="OS0-Uz-cCz"/>
<constraint firstItem="6dU-fF-FSg" firstAttribute="leading" secondItem="Teo-8d-LYJ" secondAttribute="leading" id="P9y-bj-2tC"/>
<constraint firstItem="WZf-S5-SqC" firstAttribute="leading" secondItem="Teo-8d-LYJ" secondAttribute="trailing" constant="10" id="QqJ-GR-aGp"/>
<constraint firstItem="XwE-sE-aPN" firstAttribute="top" secondItem="ONL-vF-iUY" secondAttribute="bottom" constant="20" id="XvO-b0-4Pl"/>
<constraint firstItem="UNN-CR-rdr" firstAttribute="trailing" secondItem="bc6-yT-aty" secondAttribute="trailing" id="Zep-Ze-DNM"/>
<constraint firstItem="UNN-CR-rdr" firstAttribute="leading" secondItem="bc6-yT-aty" secondAttribute="leading" id="Zix-pG-8bU"/>
<constraint firstItem="6dU-fF-FSg" firstAttribute="trailing" secondItem="WZf-S5-SqC" secondAttribute="trailing" id="a7z-pJ-hKf"/>
<constraint firstAttribute="trailing" secondItem="bc6-yT-aty" secondAttribute="trailing" constant="20" id="cR0-Np-zTX"/>
<constraint firstItem="dQS-Ma-dYP" firstAttribute="trailing" secondItem="bc6-yT-aty" secondAttribute="trailing" id="eNP-iD-wgR"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="UNN-CR-rdr" secondAttribute="bottom" constant="20" id="efh-iS-51K"/>
<constraint firstItem="XwE-sE-aPN" firstAttribute="leading" secondItem="ONL-vF-iUY" secondAttribute="leading" id="fJB-38-JYZ"/>
<constraint firstItem="sA4-W9-jxo" firstAttribute="top" secondItem="Teo-8d-LYJ" secondAttribute="top" id="grl-36-NDr"/>
<constraint firstItem="ONL-vF-iUY" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="20" id="lNh-0d-b3b"/>
<constraint firstItem="dQS-Ma-dYP" firstAttribute="top" secondItem="XwE-sE-aPN" secondAttribute="bottom" constant="20" id="lxB-za-cHQ"/>
<constraint firstItem="7LH-tE-it9" firstAttribute="leading" secondItem="XwE-sE-aPN" secondAttribute="trailing" constant="10" id="oYJ-8E-Ieq"/>
<constraint firstItem="6dU-fF-FSg" firstAttribute="top" secondItem="Teo-8d-LYJ" secondAttribute="bottom" id="pAc-Ee-Ryj"/>
<constraint firstItem="Teo-8d-LYJ" firstAttribute="top" secondItem="bc6-yT-aty" secondAttribute="bottom" constant="20" id="qnB-Iz-Gbp"/>
<constraint firstItem="ONL-vF-iUY" firstAttribute="leading" secondItem="bc6-yT-aty" secondAttribute="leading" id="sez-Cv-mp9"/>
<constraint firstItem="bc6-yT-aty" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" constant="20" id="tZc-ru-OTc"/>
<constraint firstItem="7LH-tE-it9" firstAttribute="trailing" secondItem="ONL-vF-iUY" secondAttribute="trailing" id="tlD-XS-qwO"/>
<constraint firstItem="sA4-W9-jxo" firstAttribute="centerX" secondItem="WZf-S5-SqC" secondAttribute="centerX" id="v80-dG-aB7"/>
<constraint firstAttribute="trailing" secondItem="WZf-S5-SqC" secondAttribute="trailing" constant="20" id="wMy-Qf-9Bi"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="YgB-QB-eLJ"/>
<connections>
<outlet property="buttonConnection" destination="Teo-8d-LYJ" id="evE-2I-13A"/>
<outlet property="switchTCP" destination="WZf-S5-SqC" id="UyR-J2-iX0"/>
<outlet property="textDomain" destination="XwE-sE-aPN" id="byL-Ai-eAD"/>
<outlet property="textLog" destination="UNN-CR-rdr" id="a9o-b3-nHT"/>
<outlet property="textPassword" destination="bc6-yT-aty" id="y4O-yE-C7B"/>
<outlet property="textPort" destination="7LH-tE-it9" id="KhW-ql-oN9"/>
<outlet property="textServer" destination="ONL-vF-iUY" id="To8-yq-phE"/>
<outlet property="textUsername" destination="dQS-Ma-dYP" id="2Ew-4O-QqC"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="140" y="137.18140929535232"/>
</scene>
</scenes>
<resources>
<systemColor name="groupTableViewBackgroundColor">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -1,196 +0,0 @@
//
// OpenVPNViewController.swift
// Demo
//
// Created by Davide De Rosa on 2/11/17.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import TunnelKitCore
import TunnelKitManager
import TunnelKitOpenVPN
private let appGroup = "group.com.algoritmico.TunnelKit.Demo"
private let tunnelIdentifier = "com.algoritmico.ios.TunnelKit.Demo.OpenVPN.Tunnel"
class OpenVPNViewController: UIViewController {
@IBOutlet var textUsername: UITextField!
@IBOutlet var textPassword: UITextField!
@IBOutlet var textServer: UITextField!
@IBOutlet var textDomain: UITextField!
@IBOutlet var textPort: UITextField!
@IBOutlet var switchTCP: UISwitch!
@IBOutlet var buttonConnection: UIButton!
@IBOutlet var textLog: UITextView!
private let vpn = NetworkExtensionVPN()
private var vpnStatus: VPNStatus = .disconnected
private let keychain = Keychain(group: appGroup)
private var cfg: OpenVPN.ProviderConfiguration?
override func viewDidLoad() {
super.viewDidLoad()
textServer.text = "nl-free-50"
textDomain.text = "protonvpn.net"
textPort.text = "80"
switchTCP.isOn = false
textUsername.text = ""
textPassword.text = ""
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNStatusDidChange(notification:)),
name: VPNNotification.didChangeStatus,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNDidFail(notification:)),
name: VPNNotification.didFail,
object: nil
)
Task {
await vpn.prepare()
}
// testFetchRef()
}
@IBAction func connectionClicked(_ sender: Any) {
switch vpnStatus {
case .disconnected:
connect()
case .connected, .connecting, .disconnecting:
disconnect()
}
}
@IBAction func tcpClicked(_ sender: Any) {
}
func connect() {
let server = textServer.text!
let domain = textDomain.text!
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
let port = UInt16(textPort.text!)!
let socketType: SocketType = switchTCP.isOn ? .tcp : .udp
let credentials = OpenVPN.Credentials(textUsername.text!, textPassword.text!)
cfg = OpenVPN.DemoConfiguration.make(params: .init(
title: "TunnelKit.OpenVPN",
appGroup: appGroup,
hostname: hostname,
port: port,
socketType: socketType
))
cfg?.username = credentials.username
let passwordReference: Data
do {
passwordReference = try keychain.set(password: credentials.password, for: credentials.username, context: tunnelIdentifier)
} catch {
print("Keychain failure: \(error)")
return
}
Task {
var extra = NetworkExtensionExtra()
extra.passwordReference = passwordReference
try await vpn.reconnect(
tunnelIdentifier,
configuration: cfg!,
extra: extra,
after: .seconds(2)
)
}
}
func disconnect() {
Task {
await vpn.disconnect()
}
}
@IBAction func displayLog() {
guard let cfg = cfg else {
return
}
guard let url = cfg.urlForDebugLog else {
return
}
textLog.text = try? String(contentsOf: url)
}
func updateButton() {
switch vpnStatus {
case .connected, .connecting:
buttonConnection.setTitle("Disconnect", for: .normal)
case .disconnected:
buttonConnection.setTitle("Connect", for: .normal)
case .disconnecting:
buttonConnection.setTitle("Disconnecting", for: .normal)
}
}
@objc private func VPNStatusDidChange(notification: Notification) {
vpnStatus = notification.vpnStatus
print("VPNStatusDidChange: \(vpnStatus)")
updateButton()
}
@objc private func VPNDidFail(notification: Notification) {
print("VPNStatusDidFail: \(notification.vpnError.localizedDescription)")
}
// private func testFetchRef() {
// let keychain = Keychain(group: appGroup)
// let username = "foo"
// let password = "bar"
//
// guard let ref = try? keychain.set(password: password, for: username, context: tunnelIdentifier) else {
// print("Couldn't set password")
// return
// }
// guard let fetchedPassword = try? Keychain.password(forReference: ref) else {
// print("Couldn't fetch password")
// return
// }
//
// print("\(username) -> \(password)")
// print("\(username) -> \(fetchedPassword)")
// }
}

View File

@ -1,148 +0,0 @@
//
// WireGuardViewController.swift
// Demo
//
// Created by Davide De Rosa on 11/22/21.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import TunnelKitManager
import TunnelKitWireGuard
private let appGroup = "group.com.algoritmico.TunnelKit.Demo"
private let tunnelIdentifier = "com.algoritmico.ios.TunnelKit.Demo.WireGuard.Tunnel"
class WireGuardViewController: UIViewController {
@IBOutlet var textClientPrivateKey: UITextField!
@IBOutlet var textAddress: UITextField!
@IBOutlet var textServerPublicKey: UITextField!
@IBOutlet var textServerAddress: UITextField!
@IBOutlet var textServerPort: UITextField!
@IBOutlet var buttonConnection: UIButton!
private let vpn = NetworkExtensionVPN()
private var vpnStatus: VPNStatus = .disconnected
override func viewDidLoad() {
super.viewDidLoad()
textClientPrivateKey.placeholder = "client private key"
textAddress.placeholder = "client address"
textServerPublicKey.placeholder = "server public key"
textServerAddress.placeholder = "server address"
textServerPort.placeholder = "server port"
textAddress.text = "192.168.30.2/32"
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNStatusDidChange(notification:)),
name: VPNNotification.didChangeStatus,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNDidFail(notification:)),
name: VPNNotification.didFail,
object: nil
)
Task {
await vpn.prepare()
}
}
@IBAction func connectionClicked(_ sender: Any) {
switch vpnStatus {
case .disconnected:
connect()
case .connected, .connecting, .disconnecting:
disconnect()
}
}
func connect() {
let clientPrivateKey = textClientPrivateKey.text!
let clientAddress = textAddress.text!
let serverPublicKey = textServerPublicKey.text!
let serverAddress = textServerAddress.text!
let serverPort = textServerPort.text!
guard let cfg = WireGuard.DemoConfiguration.make(params: .init(
title: "TunnelKit.WireGuard",
appGroup: appGroup,
clientPrivateKey: clientPrivateKey,
clientAddress: clientAddress,
serverPublicKey: serverPublicKey,
serverAddress: serverAddress,
serverPort: serverPort
)) else {
print("Configuration incomplete")
return
}
Task {
try await vpn.reconnect(
tunnelIdentifier,
configuration: cfg,
extra: nil,
after: .seconds(2)
)
}
}
func disconnect() {
Task {
await vpn.disconnect()
}
}
func updateButton() {
switch vpnStatus {
case .connected, .connecting:
buttonConnection.setTitle("Disconnect", for: .normal)
case .disconnected:
buttonConnection.setTitle("Connect", for: .normal)
case .disconnecting:
buttonConnection.setTitle("Disconnecting", for: .normal)
}
}
@objc private func VPNStatusDidChange(notification: Notification) {
vpnStatus = notification.vpnStatus
print("VPNStatusDidChange: \(notification.vpnStatus)")
updateButton()
}
@objc private func VPNDidFail(notification: Notification) {
print("VPNStatusDidFail: \(notification.vpnError.localizedDescription)")
}
}

View File

@ -1,937 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19455"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="TunnelKitDemo" id="1Xt-HY-uBw" userLabel="TunnelKitDemo">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="TunnelKitDemo" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About TunnelKitDemo" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide TunnelKitDemo" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit TunnelKitDemo" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
<connections>
<action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
<items>
<menuItem title="Font" id="Gi5-1S-RQB">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
<connections>
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
<connections>
<action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
<menuItem title="Kern" id="jBQ-r6-VK2">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
<items>
<menuItem title="Use Default" id="GUa-eO-cwY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
</connections>
</menuItem>
<menuItem title="Use None" id="cDB-IK-hbR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="46P-cB-AYj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="ogc-rX-tC1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="o6e-r0-MWq">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
<items>
<menuItem title="Use Default" id="agt-UL-0e3">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
</connections>
</menuItem>
<menuItem title="Use None" id="J7y-lM-qPV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
</connections>
</menuItem>
<menuItem title="Use All" id="xQD-1f-W4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="OaQ-X3-Vso">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
<items>
<menuItem title="Use Default" id="3Om-Ey-2VK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="Rqc-34-cIF">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="I0S-gh-46l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
</connections>
</menuItem>
<menuItem title="Raise" id="2h7-ER-AoG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
</connections>
</menuItem>
<menuItem title="Lower" id="1tx-W0-xDw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
<connections>
<action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="Fal-I4-PZk">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="d9c-me-L2H">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
<connections>
<action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
<connections>
<action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
</connections>
</menuItem>
<menuItem title="Justify" id="J5U-5w-g23">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
<connections>
<action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
<menuItem title="Writing Direction" id="H1b-Si-o9J">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
<items>
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="YGs-j5-SAR">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
</connections>
</menuItem>
<menuItem id="Lbh-J2-qVU">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
</connections>
</menuItem>
<menuItem id="jFq-tB-4Kx">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="Nop-cj-93Q">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
</connections>
</menuItem>
<menuItem id="BgM-ve-c93">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
</connections>
</menuItem>
<menuItem id="RB4-Sm-HuC">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
<menuItem title="Show Ruler" id="vLm-3I-IUL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleSidebar:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
</connections>
</menuItem>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="TunnelKitDemo Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="TunnelKitDemo_macOS" customModuleProvider="target"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-662" y="-582"/>
</scene>
<!--Window Controller-->
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
<window key="window" title="TunnelKit" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="480"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
</connections>
</window>
<connections>
<segue destination="Ph7-kL-etv" kind="relationship" relationship="window.shadowedContentViewController" id="J86-FA-iJb"/>
</connections>
</windowController>
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-656" y="-222"/>
</scene>
<!--Tab View Controller-->
<scene sceneID="ygq-sG-3Ln">
<objects>
<tabViewController selectedTabViewItemIndex="0" id="Ph7-kL-etv" sceneMemberID="viewController">
<tabViewItems>
<tabViewItem id="p9v-bL-mqr"/>
<tabViewItem id="Ocn-Fg-u0t"/>
</tabViewItems>
<tabView key="tabView" type="noTabsNoBorder" id="iR8-80-79B">
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
<autoresizingMask key="autoresizingMask"/>
<font key="font" metaFont="message"/>
<connections>
<outlet property="delegate" destination="Ph7-kL-etv" id="E0r-Ol-Xr3"/>
</connections>
</tabView>
<connections>
<outlet property="tabView" destination="iR8-80-79B" id="GQL-C9-54d"/>
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="tabItems" id="EL7-V7-Rli"/>
<segue destination="veh-JO-i63" kind="relationship" relationship="tabItems" id="bXX-lO-UXd"/>
</connections>
</tabViewController>
<customObject id="eeQ-AU-wde" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-656" y="404"/>
</scene>
<!--WireGuard-->
<scene sceneID="Gpw-y6-EY1">
<objects>
<viewController title="WireGuard" id="veh-JO-i63" customClass="WireGuardViewController" customModule="TunnelKitDemo_macOS" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="dOb-bH-xlV">
<rect key="frame" x="0.0" y="0.0" width="480" height="182"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="rq1-jz-XJV">
<rect key="frame" x="20" y="20" width="440" height="142"/>
<subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="uR4-9E-kLl">
<rect key="frame" x="0.0" y="121" width="440" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="JRs-jT-MUr">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nk0-nl-iaW">
<rect key="frame" x="0.0" y="90" width="440" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="KgL-In-jV9">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KGQ-ny-X4s">
<rect key="frame" x="0.0" y="59" width="440" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="i7u-Xh-TAb">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2qO-tT-LCY">
<rect key="frame" x="0.0" y="28" width="312" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="XR9-No-Udo">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Tiq-ap-zD3">
<rect key="frame" x="-7" y="-7" width="454" height="32"/>
<buttonCell key="cell" type="push" title="Connect" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Mx7-Fy-SJ6">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="connectionClicked:" target="veh-JO-i63" id="7yr-xP-5NW"/>
</connections>
</button>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0SZ-mT-ekY">
<rect key="frame" x="320" y="28" width="120" height="21"/>
<constraints>
<constraint firstAttribute="width" constant="120" id="Y6G-q2-muW"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="zL3-gF-dTw">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="0SZ-mT-ekY" secondAttribute="trailing" id="3ib-83-Fzq"/>
<constraint firstItem="Tiq-ap-zD3" firstAttribute="top" secondItem="2qO-tT-LCY" secondAttribute="bottom" constant="8" symbolic="YES" id="6CE-7C-VeP"/>
<constraint firstItem="Tiq-ap-zD3" firstAttribute="leading" secondItem="rq1-jz-XJV" secondAttribute="leading" id="8l4-c3-88J"/>
<constraint firstItem="2qO-tT-LCY" firstAttribute="top" secondItem="KGQ-ny-X4s" secondAttribute="bottom" constant="10" symbolic="YES" id="A49-xG-MpP"/>
<constraint firstItem="0SZ-mT-ekY" firstAttribute="centerY" secondItem="2qO-tT-LCY" secondAttribute="centerY" id="EKs-iy-CXT"/>
<constraint firstItem="0SZ-mT-ekY" firstAttribute="leading" secondItem="2qO-tT-LCY" secondAttribute="trailing" constant="8" symbolic="YES" id="EVP-mS-GXl"/>
<constraint firstAttribute="trailing" secondItem="KGQ-ny-X4s" secondAttribute="trailing" id="I2q-zJ-6dl"/>
<constraint firstItem="uR4-9E-kLl" firstAttribute="leading" secondItem="rq1-jz-XJV" secondAttribute="leading" id="K90-IM-FOm"/>
<constraint firstItem="2qO-tT-LCY" firstAttribute="leading" secondItem="rq1-jz-XJV" secondAttribute="leading" id="LHr-Ar-Ap5"/>
<constraint firstAttribute="trailing" secondItem="nk0-nl-iaW" secondAttribute="trailing" id="ei2-ya-hZT"/>
<constraint firstItem="nk0-nl-iaW" firstAttribute="leading" secondItem="rq1-jz-XJV" secondAttribute="leading" id="few-oS-Tyc"/>
<constraint firstItem="uR4-9E-kLl" firstAttribute="top" secondItem="rq1-jz-XJV" secondAttribute="top" id="fjG-U6-4v1"/>
<constraint firstAttribute="bottom" secondItem="Tiq-ap-zD3" secondAttribute="bottom" id="gEg-rf-8Ii"/>
<constraint firstItem="KGQ-ny-X4s" firstAttribute="top" secondItem="nk0-nl-iaW" secondAttribute="bottom" constant="10" symbolic="YES" id="gbO-Lm-2lv"/>
<constraint firstAttribute="trailing" secondItem="uR4-9E-kLl" secondAttribute="trailing" id="ikN-Ft-JeC"/>
<constraint firstItem="nk0-nl-iaW" firstAttribute="top" secondItem="uR4-9E-kLl" secondAttribute="bottom" constant="10" symbolic="YES" id="pri-94-Pto"/>
<constraint firstItem="KGQ-ny-X4s" firstAttribute="leading" secondItem="rq1-jz-XJV" secondAttribute="leading" id="q6z-Cn-J3z"/>
<constraint firstAttribute="trailing" secondItem="Tiq-ap-zD3" secondAttribute="trailing" id="yKA-nb-XUR"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="rq1-jz-XJV" firstAttribute="leading" secondItem="dOb-bH-xlV" secondAttribute="leading" constant="20" symbolic="YES" id="SRf-9v-bqS"/>
<constraint firstAttribute="trailing" secondItem="rq1-jz-XJV" secondAttribute="trailing" constant="20" symbolic="YES" id="Tuh-wz-3pJ"/>
<constraint firstAttribute="bottom" secondItem="rq1-jz-XJV" secondAttribute="bottom" constant="20" symbolic="YES" id="Zn8-xp-J3m"/>
<constraint firstItem="rq1-jz-XJV" firstAttribute="top" secondItem="dOb-bH-xlV" secondAttribute="top" constant="20" symbolic="YES" id="gRO-l8-uod"/>
</constraints>
</view>
<connections>
<outlet property="buttonConnection" destination="Tiq-ap-zD3" id="lXt-h5-V0q"/>
<outlet property="textAddress" destination="uR4-9E-kLl" id="gFs-K9-BS6"/>
<outlet property="textClientPrivateKey" destination="nk0-nl-iaW" id="cdn-Vz-28s"/>
<outlet property="textServerAddress" destination="2qO-tT-LCY" id="1tc-22-pSB"/>
<outlet property="textServerPort" destination="0SZ-mT-ekY" id="xnt-oV-11k"/>
<outlet property="textServerPublicKey" destination="KGQ-ny-X4s" id="o26-MI-51j"/>
</connections>
</viewController>
<customObject id="jiZ-E1-ajD" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1" y="521"/>
</scene>
<!--OpenVPN-->
<scene sceneID="hIz-AP-VOD">
<objects>
<viewController title="OpenVPN" id="XfG-lQ-9wD" customClass="OpenVPNViewController" customModule="TunnelKitDemo_macOS" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
<rect key="frame" x="0.0" y="0.0" width="480" height="140"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="i3T-uV-wV3">
<rect key="frame" x="20" y="99" width="100" height="21"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="15v-2e-tlT"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="qXL-ZI-P0P">
<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>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LIN-Ps-ANN">
<rect key="frame" x="140" y="99" width="230" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="1ir-yf-OCa">
<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>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="P4h-p9-zCb">
<rect key="frame" x="390" y="99" width="70" height="21"/>
<constraints>
<constraint firstAttribute="width" constant="70" id="Cba-GL-f5a"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="nYd-Lk-W7w">
<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>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sFz-8v-h8e">
<rect key="frame" x="20" y="60" width="210" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="ljE-Uv-5Le">
<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>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="et1-VP-AGe">
<rect key="frame" x="250" y="60" width="210" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="0sQ-3n-XfE">
<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>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nd2-H7-u7j">
<rect key="frame" x="13" y="13" width="454" height="32"/>
<buttonCell key="cell" type="push" title="Connect" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bKB-ql-HWr">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="connectionClicked:" target="XfG-lQ-9wD" id="Wxi-t1-Xkk"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="et1-VP-AGe" firstAttribute="width" secondItem="sFz-8v-h8e" secondAttribute="width" id="4Gv-dj-kcY"/>
<constraint firstItem="nd2-H7-u7j" firstAttribute="top" secondItem="sFz-8v-h8e" secondAttribute="bottom" constant="20" id="5q8-DS-aIh"/>
<constraint firstItem="et1-VP-AGe" firstAttribute="leading" secondItem="sFz-8v-h8e" secondAttribute="trailing" constant="20" id="9Mq-Mv-kga"/>
<constraint firstAttribute="trailing" secondItem="P4h-p9-zCb" secondAttribute="trailing" constant="20" id="Drw-b1-BNu"/>
<constraint firstItem="et1-VP-AGe" firstAttribute="top" secondItem="sFz-8v-h8e" secondAttribute="top" id="EEi-XF-PFd"/>
<constraint firstItem="nd2-H7-u7j" firstAttribute="leading" secondItem="sFz-8v-h8e" secondAttribute="leading" id="JxD-ho-4hD"/>
<constraint firstItem="LIN-Ps-ANN" firstAttribute="top" secondItem="i3T-uV-wV3" secondAttribute="top" id="KJu-xG-JnJ"/>
<constraint firstItem="nd2-H7-u7j" firstAttribute="trailing" secondItem="et1-VP-AGe" secondAttribute="trailing" id="Mwb-AU-hUO"/>
<constraint firstItem="et1-VP-AGe" firstAttribute="trailing" secondItem="P4h-p9-zCb" secondAttribute="trailing" id="Rbb-6h-w4w"/>
<constraint firstItem="P4h-p9-zCb" firstAttribute="leading" secondItem="LIN-Ps-ANN" secondAttribute="trailing" constant="20" id="Rge-dl-vui"/>
<constraint firstItem="i3T-uV-wV3" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="20" id="Xha-4o-0rg"/>
<constraint firstItem="sFz-8v-h8e" firstAttribute="top" secondItem="i3T-uV-wV3" secondAttribute="bottom" constant="18" id="bRU-rq-aRR"/>
<constraint firstItem="LIN-Ps-ANN" firstAttribute="leading" secondItem="i3T-uV-wV3" secondAttribute="trailing" constant="20" id="cDe-a1-OxC"/>
<constraint firstItem="i3T-uV-wV3" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="20" id="ndO-I5-v8j"/>
<constraint firstItem="sFz-8v-h8e" firstAttribute="leading" secondItem="i3T-uV-wV3" secondAttribute="leading" id="o5w-BS-zO3"/>
<constraint firstItem="P4h-p9-zCb" firstAttribute="top" secondItem="LIN-Ps-ANN" secondAttribute="top" id="qhX-g7-cF2"/>
<constraint firstAttribute="bottom" secondItem="nd2-H7-u7j" secondAttribute="bottom" constant="20" id="tku-oH-p9N"/>
</constraints>
</view>
<connections>
<outlet property="buttonConnection" destination="nd2-H7-u7j" id="nV5-a5-qvm"/>
<outlet property="textDomain" destination="LIN-Ps-ANN" id="1dX-5K-li3"/>
<outlet property="textPassword" destination="et1-VP-AGe" id="Vae-qT-ZLy"/>
<outlet property="textPort" destination="P4h-p9-zCb" id="p0u-oI-Snm"/>
<outlet property="textServer" destination="i3T-uV-wV3" id="oeC-EZ-BPe"/>
<outlet property="textUsername" destination="sFz-8v-h8e" id="Dte-NJ-cMr"/>
</connections>
</viewController>
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1" y="193"/>
</scene>
</scenes>
</document>

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.productivity</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) 2023 Davide De Rosa. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -1,177 +0,0 @@
//
// OpenVPNViewController.swift
// Demo
//
// Created by Davide De Rosa on 10/15/17.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import Cocoa
import TunnelKitCore
import TunnelKitManager
import TunnelKitOpenVPN
private let appGroup = "DTDYD63ZX9.group.com.algoritmico.TunnelKit.Demo"
private let tunnelIdentifier = "com.algoritmico.macos.TunnelKit.Demo.OpenVPN.Tunnel"
class OpenVPNViewController: NSViewController {
@IBOutlet var textUsername: NSTextField!
@IBOutlet var textPassword: NSTextField!
@IBOutlet var textServer: NSTextField!
@IBOutlet var textDomain: NSTextField!
@IBOutlet var textPort: NSTextField!
@IBOutlet var buttonConnection: NSButton!
private let vpn = NetworkExtensionVPN()
private var vpnStatus: VPNStatus = .disconnected
private let keychain = Keychain(group: appGroup)
private var cfg: OpenVPN.ProviderConfiguration?
override func viewDidLoad() {
super.viewDidLoad()
textServer.stringValue = "nl-free-50"
textDomain.stringValue = "protonvpn.net"
textPort.stringValue = "80"
textUsername.stringValue = ""
textPassword.stringValue = ""
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNStatusDidChange(notification:)),
name: VPNNotification.didChangeStatus,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNDidFail(notification:)),
name: VPNNotification.didFail,
object: nil
)
Task {
await vpn.prepare()
}
// testFetchRef()
}
@IBAction func connectionClicked(_ sender: Any) {
switch vpnStatus {
case .disconnected:
connect()
case .connected, .connecting, .disconnecting:
disconnect()
}
}
func connect() {
let server = textServer.stringValue
let domain = textDomain.stringValue
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
let port = UInt16(textPort.stringValue)!
let credentials = OpenVPN.Credentials(textUsername.stringValue, textPassword.stringValue)
cfg = OpenVPN.DemoConfiguration.make(params: .init(
title: "TunnelKit.OpenVPN",
appGroup: appGroup,
hostname: hostname,
port: port,
socketType: .udp
))
cfg?.username = credentials.username
let passwordReference: Data
do {
passwordReference = try keychain.set(password: credentials.password, for: credentials.username, context: tunnelIdentifier)
} catch {
print("Keychain failure: \(error)")
return
}
Task {
var extra = NetworkExtensionExtra()
extra.passwordReference = passwordReference
try await vpn.reconnect(
tunnelIdentifier,
configuration: cfg!,
extra: extra,
after: .seconds(2)
)
}
}
func disconnect() {
Task {
await vpn.disconnect()
}
}
func updateButton() {
switch vpnStatus {
case .connected, .connecting:
buttonConnection.title = "Disconnect"
case .disconnected:
buttonConnection.title = "Connect"
case .disconnecting:
buttonConnection.title = "Disconnecting"
}
}
@objc private func VPNStatusDidChange(notification: Notification) {
vpnStatus = notification.vpnStatus
print("VPNStatusDidChange: \(vpnStatus)")
updateButton()
}
@objc private func VPNDidFail(notification: Notification) {
print("VPNStatusDidFail: \(notification.vpnError.localizedDescription)")
}
// private func testFetchRef() {
// let keychain = Keychain(group: appGroup)
// let username = "foo"
// let password = "bar"
//
// guard let ref = try? keychain.set(password: password, for: username, context: tunnelIdentifier) else {
// print("Couldn't set password")
// return
// }
// guard let fetchedPassword = try? Keychain.password(forReference: ref) else {
// print("Couldn't fetch password")
// return
// }
//
// print("\(username) -> \(password)")
// print("\(username) -> \(fetchedPassword)")
// }
}

View File

@ -1,148 +0,0 @@
//
// WireGuardViewController.swift
// Demo
//
// Created by Davide De Rosa on 11/22/21.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
import Cocoa
import TunnelKitManager
import TunnelKitWireGuard
private let appGroup = "DTDYD63ZX9.group.com.algoritmico.TunnelKit.Demo"
private let tunnelIdentifier = "com.algoritmico.macos.TunnelKit.Demo.WireGuard.Tunnel"
class WireGuardViewController: NSViewController {
@IBOutlet var textClientPrivateKey: NSTextField!
@IBOutlet var textAddress: NSTextField!
@IBOutlet var textServerPublicKey: NSTextField!
@IBOutlet var textServerAddress: NSTextField!
@IBOutlet var textServerPort: NSTextField!
@IBOutlet var buttonConnection: NSButton!
private let vpn = NetworkExtensionVPN()
private var vpnStatus: VPNStatus = .disconnected
override func viewDidLoad() {
super.viewDidLoad()
textClientPrivateKey.placeholderString = "client private key"
textAddress.placeholderString = "client address"
textServerPublicKey.placeholderString = "server public key"
textServerAddress.placeholderString = "server address"
textServerPort.placeholderString = "server port"
textAddress.stringValue = "192.168.30.2/32"
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNStatusDidChange(notification:)),
name: VPNNotification.didChangeStatus,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(VPNDidFail(notification:)),
name: VPNNotification.didFail,
object: nil
)
Task {
await vpn.prepare()
}
}
@IBAction func connectionClicked(_ sender: Any) {
switch vpnStatus {
case .disconnected:
connect()
case .connected, .connecting, .disconnecting:
disconnect()
}
}
func connect() {
let clientPrivateKey = textClientPrivateKey.stringValue
let clientAddress = textAddress.stringValue
let serverPublicKey = textServerPublicKey.stringValue
let serverAddress = textServerAddress.stringValue
let serverPort = textServerPort.stringValue
guard let cfg = WireGuard.DemoConfiguration.make(params: .init(
title: "TunnelKit.WireGuard",
appGroup: appGroup,
clientPrivateKey: clientPrivateKey,
clientAddress: clientAddress,
serverPublicKey: serverPublicKey,
serverAddress: serverAddress,
serverPort: serverPort
)) else {
print("Configuration incomplete")
return
}
Task {
try await vpn.reconnect(
tunnelIdentifier,
configuration: cfg,
extra: nil,
after: .seconds(2)
)
}
}
func disconnect() {
Task {
await vpn.disconnect()
}
}
func updateButton() {
switch vpnStatus {
case .connected, .connecting:
buttonConnection.title = "Disconnect"
case .disconnected:
buttonConnection.title = "Connect"
case .disconnecting:
buttonConnection.title = "Disconnecting"
}
}
@objc private func VPNStatusDidChange(notification: Notification) {
vpnStatus = notification.vpnStatus
print("VPNStatusDidChange: \(vpnStatus)")
updateButton()
}
@objc private func VPNDidFail(notification: Notification) {
print("VPNStatusDidFail: \(notification.vpnError.localizedDescription)")
}
}

View File

@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,11 @@
{
"images" : [
{
"idiom" : "tv"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,17 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"layers" : [
{
"filename" : "Front.imagestacklayer"
},
{
"filename" : "Middle.imagestacklayer"
},
{
"filename" : "Back.imagestacklayer"
}
]
}

View File

@ -0,0 +1,11 @@
{
"images" : [
{
"idiom" : "tv"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,11 @@
{
"images" : [
{
"idiom" : "tv"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,17 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"layers" : [
{
"filename" : "Front.imagestacklayer"
},
{
"filename" : "Middle.imagestacklayer"
},
{
"filename" : "Back.imagestacklayer"
}
]
}

View File

@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,32 @@
{
"assets" : [
{
"filename" : "App Icon - App Store.imagestack",
"idiom" : "tv",
"role" : "primary-app-icon",
"size" : "1280x768"
},
{
"filename" : "App Icon.imagestack",
"idiom" : "tv",
"role" : "primary-app-icon",
"size" : "400x240"
},
{
"filename" : "Top Shelf Image Wide.imageset",
"idiom" : "tv",
"role" : "top-shelf-image-wide",
"size" : "2320x720"
},
{
"filename" : "Top Shelf Image.imageset",
"idiom" : "tv",
"role" : "top-shelf-image",
"size" : "1920x720"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,16 @@
{
"images" : [
{
"idiom" : "tv",
"scale" : "1x"
},
{
"idiom" : "tv",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -2,13 +2,17 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.algoritmico.TunnelKit</string>
<string>group.com.algoritmico.TunnelKit.Demo</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)group.com.algoritmico.TunnelKit</string>
<string>$(AppIdentifierPrefix)group.com.algoritmico.TunnelKit.Demo</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.algoritmico.TunnelKit.Demo</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)group.com.algoritmico.TunnelKit.Demo</string>
</array>
</dict>
</plist>

View File

@ -1,71 +0,0 @@
//
// AppDelegate.swift
// TunnelKitHost
//
// Created by Davide De Rosa on 9/24/17.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
// This file incorporates work covered by the following copyright and
// permission notice:
//
// Copyright (c) 2018-Present Private Internet Access
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

View File

@ -1,93 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -1,40 +0,0 @@
//
// ViewController.swift
// TunnelKitHost
//
// Created by Davide De Rosa on 9/24/17.
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of TunnelKit.
//
// TunnelKit 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.
//
// TunnelKit 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 TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//
// This file incorporates work covered by the following copyright and
// permission notice:
//
// Copyright (c) 2018-Present Private Internet Access
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
class ViewController: UIViewController {
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1510"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1510"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E9FFE042B2D8746002C93D7"
BuildableName = "TunnelKitDemoOpenVPNTunnel-tvOS.appex"
BlueprintName = "TunnelKitDemoOpenVPNTunnel-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1510"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
LastUpgradeVersion = "1510"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E9FFE112B2D8750002C93D7"
BuildableName = "TunnelKitDemoWireGuardTunnel-tvOS.appex"
BlueprintName = "TunnelKitDemoWireGuardTunnel-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0ED1A5E92B2A6AE400A0EA90"
BuildableName = "TunnelKitDemo-tvOS.app"
BlueprintName = "TunnelKitDemo-tvOS"
ReferencedContainer = "container:TunnelKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"