Some SwiftUI
|
@ -71,7 +71,7 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
"Regex": "en.*",
|
||||
"Beacon": true,
|
||||
"Listen": true,
|
||||
]
|
||||
] as [String : Any]
|
||||
])
|
||||
}
|
||||
}
|
||||
|
@ -185,11 +185,7 @@ class ConfigurationProxy: PlatformItemSource {
|
|||
self.fix()
|
||||
if let data = self.data() {
|
||||
let providerProtocol = NETunnelProviderProtocol()
|
||||
#if os(iOS)
|
||||
providerProtocol.providerBundleIdentifier = "eu.neilalexander.yggdrasil.extension"
|
||||
#elseif os(OSX)
|
||||
providerProtocol.providerBundleIdentifier = "eu.neilalexander.yggdrasilmac.extension"
|
||||
#endif
|
||||
providerProtocol.providerConfiguration = [ "json": data ]
|
||||
providerProtocol.serverAddress = "yggdrasil"
|
||||
providerProtocol.username = self.get("PublicKey") as? String ?? self.get("SigningPublicKey") as? String ?? "(unknown public key)"
|
||||
|
|
|
@ -8,45 +8,86 @@
|
|||
import Foundation
|
||||
import NetworkExtension
|
||||
import Yggdrasil
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
class CrossPlatformAppDelegate: PlatformAppDelegate {
|
||||
#if os(iOS)
|
||||
class PlatformAppDelegate: UIResponder, UIApplicationDelegate {}
|
||||
typealias PlatformApplication = UIApplication
|
||||
typealias ApplicationDelegateAdaptor = UIApplicationDelegateAdaptor
|
||||
#elseif os(macOS)
|
||||
class PlatformAppDelegate: NSObject, NSApplicationDelegate {}
|
||||
typealias PlatformApplication = NSApplication
|
||||
typealias ApplicationDelegateAdaptor = NSApplicationDelegateAdaptor
|
||||
#endif
|
||||
|
||||
class CrossPlatformAppDelegate: PlatformAppDelegate, ObservableObject {
|
||||
var vpnManager: NETunnelProviderManager = NETunnelProviderManager()
|
||||
|
||||
#if os(iOS)
|
||||
let yggdrasilComponent = "eu.neilalexander.yggdrasil.extension"
|
||||
#elseif os(OSX)
|
||||
let yggdrasilComponent = "eu.neilalexander.yggdrasilmac.extension"
|
||||
#endif
|
||||
|
||||
var yggdrasilConfig: ConfigurationProxy? = nil
|
||||
|
||||
var yggdrasilAdminTimer: DispatchSourceTimer?
|
||||
|
||||
var yggdrasilSelfIP: String = "N/A"
|
||||
var yggdrasilSelfSubnet: String = "N/A"
|
||||
var yggdrasilSelfCoords: String = "[]"
|
||||
|
||||
var yggdrasilPeers: [[String: Any]] = [[:]]
|
||||
var yggdrasilDHT: [[String: Any]] = [[:]]
|
||||
var yggdrasilNodeInfo: [String: Any] = [:]
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
if self.yggdrasilAdminTimer == nil {
|
||||
self.yggdrasilAdminTimer = DispatchSource.makeTimerSource(flags: .strict, queue: DispatchQueue(label: "Admin Queue"))
|
||||
self.yggdrasilAdminTimer!.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(2), leeway: DispatchTimeInterval.seconds(1))
|
||||
self.yggdrasilAdminTimer!.setEventHandler {
|
||||
self.makeIPCRequests()
|
||||
}
|
||||
}
|
||||
if self.yggdrasilAdminTimer != nil {
|
||||
self.yggdrasilAdminTimer!.resume()
|
||||
}
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: nil, using: { notification in
|
||||
if let conn = notification.object as? NEVPNConnection {
|
||||
self.updateStatus(conn: conn)
|
||||
}
|
||||
})
|
||||
|
||||
self.vpnTunnelProviderManagerInit()
|
||||
self.makeIPCRequests()
|
||||
}
|
||||
|
||||
func toggleYggdrasil() {
|
||||
if !self.yggdrasilEnabled {
|
||||
print("Starting VPN tunnel")
|
||||
do {
|
||||
try self.vpnManager.connection.startVPNTunnel()
|
||||
} catch {
|
||||
print("Failed to start VPN tunnel: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
print("Started VPN tunnel")
|
||||
} else {
|
||||
print("Stopping VPN tunnel")
|
||||
self.vpnManager.connection.stopVPNTunnel()
|
||||
print("Stopped VPN tunnel")
|
||||
}
|
||||
self.yggdrasilEnabled = !self.yggdrasilEnabled
|
||||
}
|
||||
|
||||
var yggdrasilConfig: ConfigurationProxy? = nil
|
||||
|
||||
private var adminTimer: DispatchSourceTimer?
|
||||
|
||||
@Published var yggdrasilEnabled: Bool = false
|
||||
@Published var yggdrasilConnected: Bool = false
|
||||
|
||||
@Published var yggdrasilIP: String = "N/A"
|
||||
@Published var yggdrasilSubnet: String = "N/A"
|
||||
@Published var yggdrasilCoords: String = "[]"
|
||||
|
||||
@Published var yggdrasilPeers: [[String: Any]] = [[:]]
|
||||
@Published var yggdrasilDHT: [[String: Any]] = [[:]]
|
||||
@Published var yggdrasilNodeInfo: [String: Any] = [:]
|
||||
|
||||
func yggdrasilVersion() -> String {
|
||||
return Yggdrasil.MobileGetVersion()
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: PlatformApplication) {
|
||||
print("Application became active")
|
||||
|
||||
if self.adminTimer == nil {
|
||||
self.adminTimer = DispatchSource.makeTimerSource(flags: .strict, queue: DispatchQueue(label: "Admin Queue"))
|
||||
self.adminTimer!.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(2), leeway: DispatchTimeInterval.seconds(1))
|
||||
self.adminTimer!.setEventHandler {
|
||||
self.makeIPCRequests()
|
||||
}
|
||||
}
|
||||
if self.adminTimer != nil {
|
||||
self.adminTimer!.resume()
|
||||
}
|
||||
|
||||
self.updateStatus(conn: self.vpnManager.connection)
|
||||
}
|
||||
|
||||
|
@ -56,49 +97,70 @@ class CrossPlatformAppDelegate: PlatformAppDelegate {
|
|||
} else if conn.status == .disconnecting || conn.status == .disconnected {
|
||||
self.clearStatus()
|
||||
}
|
||||
self.yggdrasilConnected = self.yggdrasilEnabled && self.yggdrasilPeers.count > 0 && self.yggdrasilDHT.count > 0
|
||||
print("Connection status: \(yggdrasilEnabled), \(yggdrasilConnected)")
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
if self.yggdrasilAdminTimer != nil {
|
||||
self.yggdrasilAdminTimer!.suspend()
|
||||
func applicationWillResignActive(_ application: PlatformApplication) {
|
||||
if self.adminTimer != nil {
|
||||
self.adminTimer!.suspend()
|
||||
}
|
||||
}
|
||||
|
||||
func vpnTunnelProviderManagerInit() {
|
||||
print("Loading saved managers...")
|
||||
|
||||
NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
guard error == nil else {
|
||||
print("Failed to load VPN managers: \(error?.localizedDescription ?? "(no error)")")
|
||||
return
|
||||
}
|
||||
|
||||
if let savedManagers = savedManagers {
|
||||
for manager in savedManagers {
|
||||
if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.yggdrasilComponent {
|
||||
print("Found saved VPN Manager")
|
||||
self.vpnManager = manager
|
||||
}
|
||||
guard let savedManagers else {
|
||||
print("Expected to find saved managers but didn't")
|
||||
return
|
||||
}
|
||||
|
||||
print("Found \(savedManagers.count) saved VPN managers")
|
||||
for manager in savedManagers {
|
||||
guard let proto = manager.protocolConfiguration as? NETunnelProviderProtocol else {
|
||||
continue
|
||||
}
|
||||
guard let identifier = proto.providerBundleIdentifier else {
|
||||
continue
|
||||
}
|
||||
guard identifier == self.yggdrasilComponent else {
|
||||
continue
|
||||
}
|
||||
print("Found saved VPN Manager")
|
||||
self.vpnManager = manager
|
||||
break
|
||||
}
|
||||
|
||||
self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
if error == nil {
|
||||
if let vpnConfig = self.vpnManager.protocolConfiguration as? NETunnelProviderProtocol,
|
||||
let confJson = vpnConfig.providerConfiguration!["json"] as? Data {
|
||||
if let loaded = try? ConfigurationProxy(json: confJson) {
|
||||
print("Found existing protocol configuration")
|
||||
self.yggdrasilConfig = loaded
|
||||
} else {
|
||||
print("Existing protocol configuration is invalid, ignoring")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let vpnConfig = self.vpnManager.protocolConfiguration as? NETunnelProviderProtocol,
|
||||
let confJson = vpnConfig.providerConfiguration!["json"] as? Data {
|
||||
print("Found existing protocol configuration")
|
||||
self.yggdrasilConfig = try? ConfigurationProxy(json: confJson)
|
||||
} else {
|
||||
if self.yggdrasilConfig == nil {
|
||||
print("Generating new protocol configuration")
|
||||
self.yggdrasilConfig = ConfigurationProxy()
|
||||
|
||||
if let config = self.yggdrasilConfig {
|
||||
try? config.save(to: &self.vpnManager)
|
||||
}
|
||||
}
|
||||
|
||||
self.vpnManager.localizedDescription = "Yggdrasil"
|
||||
self.vpnManager.isEnabled = true
|
||||
|
||||
if let config = self.yggdrasilConfig {
|
||||
try? config.save(to: &self.vpnManager)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -110,19 +172,19 @@ class CrossPlatformAppDelegate: PlatformAppDelegate {
|
|||
if let session = self.vpnManager.connection as? NETunnelProviderSession {
|
||||
try? session.sendProviderMessage("address".data(using: .utf8)!) { (address) in
|
||||
if let address = address {
|
||||
self.yggdrasilSelfIP = String(data: address, encoding: .utf8)!
|
||||
self.yggdrasilIP = String(data: address, encoding: .utf8)!
|
||||
NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
|
||||
}
|
||||
}
|
||||
try? session.sendProviderMessage("subnet".data(using: .utf8)!) { (subnet) in
|
||||
if let subnet = subnet {
|
||||
self.yggdrasilSelfSubnet = String(data: subnet, encoding: .utf8)!
|
||||
self.yggdrasilSubnet = String(data: subnet, encoding: .utf8)!
|
||||
NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
|
||||
}
|
||||
}
|
||||
try? session.sendProviderMessage("coords".data(using: .utf8)!) { (coords) in
|
||||
if let coords = coords {
|
||||
self.yggdrasilSelfCoords = String(data: coords, encoding: .utf8)!
|
||||
self.yggdrasilCoords = String(data: coords, encoding: .utf8)!
|
||||
NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
|
||||
}
|
||||
}
|
||||
|
@ -146,9 +208,9 @@ class CrossPlatformAppDelegate: PlatformAppDelegate {
|
|||
}
|
||||
|
||||
func clearStatus() {
|
||||
self.yggdrasilSelfIP = "N/A"
|
||||
self.yggdrasilSelfSubnet = "N/A"
|
||||
self.yggdrasilSelfCoords = "[]"
|
||||
self.yggdrasilIP = "N/A"
|
||||
self.yggdrasilSubnet = "N/A"
|
||||
self.yggdrasilCoords = "[]"
|
||||
self.yggdrasilPeers = []
|
||||
self.yggdrasilDHT = []
|
||||
NotificationCenter.default.post(name: .YggdrasilSelfUpdated, object: nil)
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import UIKit
|
||||
|
||||
#if os(iOS)
|
||||
class PlatformAppDelegate: UIResponder, UIApplicationDelegate {}
|
||||
#elseif os(OSX)
|
||||
class PlatformAppDelegate: NSObject, NSApplicationDelegate {}
|
||||
#endif
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: CrossPlatformAppDelegate {
|
||||
var window: UIWindow?
|
||||
|
|
|
@ -94,9 +94,9 @@ class TableViewController: UITableViewController {
|
|||
}
|
||||
|
||||
@objc func onYggdrasilSelfUpdated(notification: NSNotification) {
|
||||
statsSelfIP.text = app.yggdrasilSelfIP
|
||||
statsSelfSubnet.text = app.yggdrasilSelfSubnet
|
||||
statsSelfCoords.text = app.yggdrasilSelfCoords
|
||||
statsSelfIP.text = app.yggdrasilIP
|
||||
statsSelfSubnet.text = app.yggdrasilSubnet
|
||||
statsSelfCoords.text = app.yggdrasilCoords
|
||||
|
||||
statsSelfIPCell.layoutSubviews()
|
||||
statsSelfSubnetCell.layoutSubviews()
|
||||
|
|
|
@ -20,8 +20,19 @@
|
|||
3996AF38270328080070947D /* Yggdrasil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3996AF37270328080070947D /* Yggdrasil.xcframework */; };
|
||||
3996AF39270328080070947D /* Yggdrasil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3996AF37270328080070947D /* Yggdrasil.xcframework */; };
|
||||
39AE88392319C93F0010FFF6 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39AE88382319C93F0010FFF6 /* NetworkExtension.framework */; };
|
||||
39B51A4A2997062E0059D29D /* PeersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B51A492997062E0059D29D /* PeersView.swift */; };
|
||||
39B51A4B29994F240059D29D /* ConfigurationProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3952ADB629945AF700B3835D /* ConfigurationProxy.swift */; };
|
||||
39B51A4C29994F350059D29D /* CrossPlatformAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3952ADB929945AFA00B3835D /* CrossPlatformAppDelegate.swift */; };
|
||||
39B51A4D299951D60059D29D /* NSNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CC924B221DEDCE004960DC /* NSNotification.swift */; };
|
||||
39BF9FC62A2F5FA7000E7269 /* PacketTunnelProvider+FileDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BF9FC52A2F5FA7000E7269 /* PacketTunnelProvider+FileDescriptor.swift */; };
|
||||
39BF9FC72A2F6FFD000E7269 /* Yggdrasil.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3996AF37270328080070947D /* Yggdrasil.xcframework */; };
|
||||
39CC924C221DEDCE004960DC /* NSNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CC924B221DEDCE004960DC /* NSNotification.swift */; };
|
||||
39CC924D221DEDD3004960DC /* NSNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CC924B221DEDCE004960DC /* NSNotification.swift */; };
|
||||
39F0205E2996CD760093F603 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F0205D2996CD760093F603 /* Application.swift */; };
|
||||
39F020602996CD760093F603 /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F0205F2996CD760093F603 /* StatusView.swift */; };
|
||||
39F020622996CD770093F603 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39F020612996CD770093F603 /* Assets.xcassets */; };
|
||||
39F020662996CD770093F603 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39F020652996CD770093F603 /* Preview Assets.xcassets */; };
|
||||
39F0206B2996CF260093F603 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F0206A2996CF260093F603 /* SettingsView.swift */; };
|
||||
E593CE6F1DF8FC3C00D7265D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E593CE6E1DF8FC3C00D7265D /* AppDelegate.swift */; };
|
||||
E593CE711DF8FC3C00D7265D /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E593CE701DF8FC3C00D7265D /* TableViewController.swift */; };
|
||||
E593CE741DF8FC3C00D7265D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E593CE721DF8FC3C00D7265D /* Main.storyboard */; };
|
||||
|
@ -71,7 +82,18 @@
|
|||
39682A382225AD15004FB670 /* CopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyableLabel.swift; sourceTree = "<group>"; };
|
||||
3996AF37270328080070947D /* Yggdrasil.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Yggdrasil.xcframework; sourceTree = "<group>"; };
|
||||
39AE88382319C93F0010FFF6 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
|
||||
39B51A492997062E0059D29D /* PeersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeersView.swift; sourceTree = "<group>"; };
|
||||
39BF9FC12A2E9E51000E7269 /* YggdrasilNetworkExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "YggdrasilNetworkExtension-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
39BF9FC22A2E9E52000E7269 /* PacketTunnelProvider+FileDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PacketTunnelProvider+FileDescriptor.h"; sourceTree = "<group>"; };
|
||||
39BF9FC52A2F5FA7000E7269 /* PacketTunnelProvider+FileDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PacketTunnelProvider+FileDescriptor.swift"; sourceTree = "<group>"; };
|
||||
39CC924B221DEDCE004960DC /* NSNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSNotification.swift; sourceTree = "<group>"; };
|
||||
39F0205B2996CD760093F603 /* YggdrasilSwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YggdrasilSwiftUI.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
39F0205D2996CD760093F603 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||
39F0205F2996CD760093F603 /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = "<group>"; };
|
||||
39F020612996CD770093F603 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
39F020632996CD770093F603 /* YggdrasilSwiftUI.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = YggdrasilSwiftUI.entitlements; sourceTree = "<group>"; };
|
||||
39F020652996CD770093F603 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
39F0206A2996CF260093F603 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
E593CE6B1DF8FC3C00D7265D /* YggdrasilNetwork.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YggdrasilNetwork.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E593CE6E1DF8FC3C00D7265D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
E593CE701DF8FC3C00D7265D /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -85,6 +107,14 @@
|
|||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
39F020582996CD760093F603 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
39BF9FC72A2F6FFD000E7269 /* Yggdrasil.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
E593CE681DF8FC3C00D7265D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -137,7 +167,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
E593CE6E1DF8FC3C00D7265D /* AppDelegate.swift */,
|
||||
39CC924B221DEDCE004960DC /* NSNotification.swift */,
|
||||
);
|
||||
path = Application;
|
||||
sourceTree = "<group>";
|
||||
|
@ -156,6 +185,7 @@
|
|||
children = (
|
||||
3952ADB929945AFA00B3835D /* CrossPlatformAppDelegate.swift */,
|
||||
3952ADB629945AF700B3835D /* ConfigurationProxy.swift */,
|
||||
39CC924B221DEDCE004960DC /* NSNotification.swift */,
|
||||
);
|
||||
name = "Yggdrasil Network Core";
|
||||
path = "Yggdrasil Network Cross-Platform";
|
||||
|
@ -170,6 +200,28 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
39F0205C2996CD760093F603 /* YggdrasilSwiftUI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
39F0205D2996CD760093F603 /* Application.swift */,
|
||||
39F0205F2996CD760093F603 /* StatusView.swift */,
|
||||
39F0206A2996CF260093F603 /* SettingsView.swift */,
|
||||
39B51A492997062E0059D29D /* PeersView.swift */,
|
||||
39F020612996CD770093F603 /* Assets.xcassets */,
|
||||
39F020632996CD770093F603 /* YggdrasilSwiftUI.entitlements */,
|
||||
39F020642996CD770093F603 /* Preview Content */,
|
||||
);
|
||||
path = YggdrasilSwiftUI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
39F020642996CD770093F603 /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
39F020652996CD770093F603 /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E593CE621DF8FC3C00D7265D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -178,6 +230,7 @@
|
|||
3913E99C21DB9B1C001E0EC7 /* YggdrasilNetworkExtension.entitlements */,
|
||||
E593CE981DF905AF00D7265D /* Yggdrasil Network Extension */,
|
||||
E593CE6D1DF8FC3C00D7265D /* Yggdrasil Network iOS */,
|
||||
39F0205C2996CD760093F603 /* YggdrasilSwiftUI */,
|
||||
E593CE6C1DF8FC3C00D7265D /* Products */,
|
||||
399D032221DA775D0016354F /* Frameworks */,
|
||||
);
|
||||
|
@ -188,6 +241,7 @@
|
|||
children = (
|
||||
E593CE6B1DF8FC3C00D7265D /* YggdrasilNetwork.app */,
|
||||
E593CE971DF905AF00D7265D /* YggdrasilNetworkExtension.appex */,
|
||||
39F0205B2996CD760093F603 /* YggdrasilSwiftUI.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -214,6 +268,7 @@
|
|||
391B72A62A2FD90100896278 /* PacketTunnelProvider+FileDescriptor.swift */,
|
||||
391B72A72A2FD90100896278 /* YggdrasilNetworkExtension-Bridging-Header.h */,
|
||||
E593CE9D1DF905AF00D7265D /* Info.plist */,
|
||||
39BF9FC12A2E9E51000E7269 /* YggdrasilNetworkExtension-Bridging-Header.h */,
|
||||
);
|
||||
path = "Yggdrasil Network Extension";
|
||||
sourceTree = "<group>";
|
||||
|
@ -221,6 +276,23 @@
|
|||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
39F0205A2996CD760093F603 /* YggdrasilSwiftUI */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 39F020672996CD770093F603 /* Build configuration list for PBXNativeTarget "YggdrasilSwiftUI" */;
|
||||
buildPhases = (
|
||||
39F020572996CD760093F603 /* Sources */,
|
||||
39F020582996CD760093F603 /* Frameworks */,
|
||||
39F020592996CD760093F603 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = YggdrasilSwiftUI;
|
||||
productName = YggdrasilSwiftUI;
|
||||
productReference = 39F0205B2996CD760093F603 /* YggdrasilSwiftUI.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
E593CE6A1DF8FC3C00D7265D /* YggdrasilNetwork */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = E593CE7D1DF8FC3C00D7265D /* Build configuration list for PBXNativeTarget "YggdrasilNetwork" */;
|
||||
|
@ -263,10 +335,13 @@
|
|||
E593CE631DF8FC3C00D7265D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1010;
|
||||
LastSwiftUpdateCheck = 1420;
|
||||
LastUpgradeCheck = 1420;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
39F0205A2996CD760093F603 = {
|
||||
CreatedOnToolsVersion = 14.2;
|
||||
};
|
||||
E593CE6A1DF8FC3C00D7265D = {
|
||||
CreatedOnToolsVersion = 8.1;
|
||||
LastSwiftMigration = 1030;
|
||||
|
@ -287,7 +362,7 @@
|
|||
};
|
||||
E593CE961DF905AF00D7265D = {
|
||||
CreatedOnToolsVersion = 8.1;
|
||||
LastSwiftMigration = 1030;
|
||||
LastSwiftMigration = 1430;
|
||||
SystemCapabilities = {
|
||||
com.apple.ApplicationGroups.iOS = {
|
||||
enabled = 1;
|
||||
|
@ -317,11 +392,21 @@
|
|||
targets = (
|
||||
E593CE6A1DF8FC3C00D7265D /* YggdrasilNetwork */,
|
||||
E593CE961DF905AF00D7265D /* YggdrasilNetworkExtension */,
|
||||
39F0205A2996CD760093F603 /* YggdrasilSwiftUI */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
39F020592996CD760093F603 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
39F020662996CD770093F603 /* Preview Assets.xcassets in Resources */,
|
||||
39F020622996CD770093F603 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
E593CE691DF8FC3C00D7265D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -342,6 +427,20 @@
|
|||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
39F020572996CD760093F603 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
39B51A4B29994F240059D29D /* ConfigurationProxy.swift in Sources */,
|
||||
39F0206B2996CF260093F603 /* SettingsView.swift in Sources */,
|
||||
39B51A4A2997062E0059D29D /* PeersView.swift in Sources */,
|
||||
39F020602996CD760093F603 /* StatusView.swift in Sources */,
|
||||
39B51A4D299951D60059D29D /* NSNotification.swift in Sources */,
|
||||
39B51A4C29994F350059D29D /* CrossPlatformAppDelegate.swift in Sources */,
|
||||
39F0205E2996CD760093F603 /* Application.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
E593CE671DF8FC3C00D7265D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -401,6 +500,95 @@
|
|||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
39F020682996CD770093F603 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = YggdrasilSwiftUI/YggdrasilSwiftUI.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"YggdrasilSwiftUI/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = R9AV23TXF2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
|
||||
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil.YggdrasilSwiftUI;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = auto;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
39F020692996CD770093F603 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = YggdrasilSwiftUI/YggdrasilSwiftUI.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"YggdrasilSwiftUI/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = R9AV23TXF2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
|
||||
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = eu.neilalexander.yggdrasil.YggdrasilSwiftUI;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = auto;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
E593CE7B1DF8FC3C00D7265D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
@ -452,8 +640,8 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -510,8 +698,8 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
|
||||
|
@ -539,7 +727,7 @@
|
|||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Yggdrasil Network iOS/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -573,7 +761,7 @@
|
|||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Yggdrasil Network iOS/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -592,6 +780,7 @@
|
|||
E593CEA11DF905AF00D7265D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = YggdrasilNetworkExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
|
@ -603,8 +792,7 @@
|
|||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Yggdrasil Network Extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -614,17 +802,18 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Yggdrasil Network Extension/YggdrasilNetworkExtension-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
E593CEA21DF905AF00D7265D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = YggdrasilNetworkExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
|
@ -636,8 +825,7 @@
|
|||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Yggdrasil Network Extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -647,17 +835,26 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "8ce353d5-fd5f-4d5e-b664-8ad294091125";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Yggdrasil Network Extension/YggdrasilNetworkExtension-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
39F020672996CD770093F603 /* Build configuration list for PBXNativeTarget "YggdrasilSwiftUI" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
39F020682996CD770093F603 /* Debug */,
|
||||
39F020692996CD770093F603 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
E593CE661DF8FC3C00D7265D /* Build configuration list for PBXProject "Yggdrasil Network" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
63
YggdrasilSwiftUI/Application.swift
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// YggdrasilSwiftUIApp.swift
|
||||
// YggdrasilSwiftUI
|
||||
//
|
||||
// Created by Neil on 10/02/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NetworkExtension
|
||||
|
||||
@main
|
||||
struct Application: App {
|
||||
#if os(iOS)
|
||||
@UIApplicationDelegateAdaptor(CrossPlatformAppDelegate.self) static var appDelegate: CrossPlatformAppDelegate
|
||||
#elseif os(macOS)
|
||||
@NSApplicationDelegateAdaptor(CrossPlatformAppDelegate.self) static var appDelegate: CrossPlatformAppDelegate
|
||||
#endif
|
||||
|
||||
@State private var selection: String? = "Status"
|
||||
@State private var config: ConfigurationProxy = ConfigurationProxy()
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
NavigationSplitView {
|
||||
List(selection: $selection) {
|
||||
NavigationLink(destination: StatusView(yggdrasilConfiguration: $config)) {
|
||||
HStack {
|
||||
Image(systemName: "info.circle")
|
||||
.foregroundColor(.accentColor)
|
||||
.frame(minWidth: 24)
|
||||
Text("Status")
|
||||
}
|
||||
}
|
||||
NavigationLink(destination: PeersView()) {
|
||||
HStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right")
|
||||
.foregroundColor(.accentColor)
|
||||
.frame(minWidth: 24)
|
||||
Text("Peers")
|
||||
}
|
||||
}
|
||||
NavigationLink(destination: SettingsView()) {
|
||||
HStack {
|
||||
Image(systemName: "gear")
|
||||
.foregroundColor(.accentColor)
|
||||
.frame(minWidth: 24)
|
||||
Text("Settings")
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
.navigationSplitViewColumnWidth(200)
|
||||
} detail: {
|
||||
StatusView(yggdrasilConfiguration: $config)
|
||||
}
|
||||
.navigationTitle("Yggdrasil")
|
||||
.navigationSplitViewStyle(.automatic)
|
||||
}
|
||||
#if os(macOS)
|
||||
.windowStyle(.hiddenTitleBar)
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "drawing copy-1.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "drawing copy.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "drawing copy-2.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"filename" : "drawing copy-3.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"filename" : "drawing copy-5.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"filename" : "drawing copy-4.png",
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4 KiB |
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "drawing copy-4 1.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "512x512"
|
||||
},
|
||||
{
|
||||
"filename" : "drawing copy-4.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "512x512"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 26 KiB |
6
YggdrasilSwiftUI/Assets.xcassets/Contents.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
77
YggdrasilSwiftUI/PeersView.swift
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// StatisticsView.swift
|
||||
// YggdrasilSwiftUI
|
||||
//
|
||||
// Created by Neil on 10/02/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct PeersView: View {
|
||||
@State private var peers = ["Paul", "Taylor", "Adele"]
|
||||
|
||||
@State private var multicastAdvertise = false
|
||||
@State private var multicastListen = false
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(content: {
|
||||
ForEach(peers, id: \.self) { peer in
|
||||
Text(peer)
|
||||
}
|
||||
.onDelete(perform: delete)
|
||||
Text("Yggdrasil will automatically attempt to connect to configured peers when started. If you configure more than one peer, your device may carry traffic on behalf of other network nodes. Avoid this by configuring only a single peer. Data charges may apply when using mobile data.")
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.gray)
|
||||
}, header: {
|
||||
Text("Configured peers")
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
Toggle(isOn: $multicastAdvertise) {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Discoverable over multicast")
|
||||
Text("Make your device discoverable to other Yggdrasil nodes on the same Wi-Fi network.")
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
Toggle(isOn: $multicastListen) {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Search for multicast peers")
|
||||
Text("Automatically connect to discoverable Yggdrasil nodes on the same Wi-Fi network.")
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}, header: {
|
||||
Text("Local connectivity")
|
||||
})
|
||||
}
|
||||
#if os(iOS)
|
||||
.toolbar {
|
||||
Button(role: nil, action: {
|
||||
|
||||
}, label: {
|
||||
Image(systemName: "plus")
|
||||
})
|
||||
EditButton()
|
||||
}
|
||||
#endif
|
||||
.formStyle(.grouped)
|
||||
.navigationTitle("Peers")
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
#endif
|
||||
}
|
||||
|
||||
func delete(at offsets: IndexSet) {
|
||||
peers.remove(atOffsets: offsets)
|
||||
}
|
||||
}
|
||||
|
||||
struct PeersView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PeersView()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
84
YggdrasilSwiftUI/SettingsView.swift
Normal file
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// SettingsView.swift
|
||||
// YggdrasilSwiftUI
|
||||
//
|
||||
// Created by Neil on 10/02/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
@State private var deviceName = ""
|
||||
|
||||
@State private var autoStartOnWiFi = false
|
||||
@State private var autoStartOnCellular = false
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(content: {
|
||||
TextField("Device Name", text: $deviceName)
|
||||
}, header: {
|
||||
Text("Public Identity")
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
Toggle("Wi-Fi", isOn: $autoStartOnWiFi)
|
||||
Toggle("Mobile Network", isOn: $autoStartOnCellular)
|
||||
}, header: {
|
||||
Text("Automatically start when connected to")
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
VStack(alignment: .leading) {
|
||||
Button("Import configuration") {
|
||||
|
||||
}
|
||||
#if os(macOS)
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
Text("Import configuration from another device, including the public key and Yggdrasil IP address.")
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Button("Export configuration") {
|
||||
|
||||
}
|
||||
#if os(macOS)
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
Text("Configuration will be exported as a file. Your configuration contains your private key which is extremely sensitive. Do not share it with anyone.")
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Button("Reset configuration") {
|
||||
|
||||
}
|
||||
#if os(macOS)
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
.foregroundColor(.red)
|
||||
Text("Resetting will overwrite with newly generated configuration. Your public key and Yggdrasil IP address will change.")
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}, header: {
|
||||
Text("Configuration")
|
||||
})
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
.navigationTitle("Settings")
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SettingsView()
|
||||
}
|
||||
}
|
125
YggdrasilSwiftUI/StatusView.swift
Normal file
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// ContentView.swift
|
||||
// YggdrasilSwiftUI
|
||||
//
|
||||
// Created by Neil on 10/02/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
#if os(iOS)
|
||||
typealias MyListStyle = DefaultListStyle
|
||||
#else
|
||||
typealias MyListStyle = SidebarListStyle
|
||||
#endif
|
||||
|
||||
struct StatusView: View {
|
||||
@Binding public var yggdrasilConfiguration: ConfigurationProxy
|
||||
|
||||
@ObservedObject private var appDelegate = Application.appDelegate
|
||||
|
||||
@State private var statusBadgeColor: SwiftUI.Color = .gray
|
||||
@State private var statusBadgeText: String = "Not enabled"
|
||||
|
||||
private func getStatusBadgeColor() -> SwiftUI.Color {
|
||||
if !appDelegate.yggdrasilEnabled {
|
||||
return .gray
|
||||
} else if !appDelegate.yggdrasilConnected {
|
||||
return .yellow
|
||||
} else {
|
||||
return .green
|
||||
}
|
||||
}
|
||||
|
||||
private func getStatusBadgeText() -> String {
|
||||
if !appDelegate.yggdrasilEnabled {
|
||||
return "Not enabled"
|
||||
} else if !appDelegate.yggdrasilConnected {
|
||||
return "Not connected"
|
||||
} else {
|
||||
return "Connected"
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(content: {
|
||||
VStack(alignment: .leading) {
|
||||
Toggle("Enable Yggdrasil", isOn: $appDelegate.yggdrasilEnabled)
|
||||
.onTapGesture {
|
||||
appDelegate.toggleYggdrasil()
|
||||
}
|
||||
HStack {
|
||||
Image(systemName: "circlebadge.fill")
|
||||
.foregroundColor(statusBadgeColor)
|
||||
.onAppear(perform: {
|
||||
statusBadgeColor = getStatusBadgeColor()
|
||||
})
|
||||
.onChange(of: appDelegate.yggdrasilEnabled) { newValue in
|
||||
statusBadgeColor = getStatusBadgeColor()
|
||||
}
|
||||
Text(statusBadgeText)
|
||||
.foregroundColor(.gray)
|
||||
.font(.system(size: 11))
|
||||
.onAppear(perform: {
|
||||
statusBadgeText = getStatusBadgeText()
|
||||
})
|
||||
.onChange(of: appDelegate.yggdrasilEnabled) { newValue in
|
||||
statusBadgeText = getStatusBadgeText()
|
||||
}
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Text("Version")
|
||||
Spacer()
|
||||
Text(appDelegate.yggdrasilVersion())
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
})
|
||||
|
||||
Section(content: {
|
||||
HStack {
|
||||
Text("IP")
|
||||
Spacer()
|
||||
Text(appDelegate.yggdrasilIP)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
HStack {
|
||||
Text("Subnet")
|
||||
Spacer()
|
||||
Text(appDelegate.yggdrasilSubnet)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
HStack {
|
||||
Text("Coordinates")
|
||||
Spacer()
|
||||
Text(appDelegate.yggdrasilCoords)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
/*
|
||||
HStack {
|
||||
Text("Public Key")
|
||||
Spacer()
|
||||
Text("N/A")
|
||||
.foregroundColor(Color.gray)
|
||||
.font(.system(size: 15, design: .monospaced))
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
*/
|
||||
})
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
.navigationTitle("Yggdrasil")
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct StatusView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
@State var config = ConfigurationProxy()
|
||||
|
||||
StatusView(yggdrasilConfiguration: $config)
|
||||
}
|
||||
}
|
22
YggdrasilSwiftUI/YggdrasilSwiftUI.entitlements
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?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.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
<key>com.apple.developer.networking.vpn.api</key>
|
||||
<array>
|
||||
<string>allow-vpn</string>
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.eu.neilalexander.yggdrasil</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|